! Copyright (C) 2005, 2007 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. IN: generator USING: alien arrays assembler-ppc kernel kernel-internals math math-internals namespaces sequences words ; : generate-slot ( size quot -- ) >r >r ! turn tagged fixnum slot # into an offset, multiple of 4 "n" operand dup tag-bits r> - SRAWI ! compute slot address "out" operand dup "n" operand ADD ! load slot value "out" operand dup r> call ; inline \ slot { ! Slot number is literal { [ "obj" operand "out" operand %untag "out" operand dup "n" get cells LWZ ] H{ { +input+ { { f "obj" } { [ cells ] "n" } } } { +scratch+ { { f "out" } } } { +output+ { "out" } } } } ! Slot number in a register { [ "obj" operand "out" operand %untag cell log2 [ 0 LWZ ] generate-slot ] H{ { +input+ { { f "obj" } { f "n" } } } { +scratch+ { { f "out" } } } { +output+ { "out" } } { +clobber+ { "n" } } } } } define-intrinsics \ char-slot [ "out" operand "obj" operand MR 1 [ string-offset LHZ ] generate-slot "out" operand dup %tag-fixnum ] H{ { +input+ { { f "n" } { f "obj" } } } { +scratch+ { { f "out" } } } { +output+ { "out" } } { +clobber+ { "n" } } } define-intrinsic : generate-set-slot ( size quot -- ) >r >r ! turn tagged fixnum slot # into an offset, multiple of 4 "slot" operand dup tag-bits r> - SRAWI ! compute slot address in 1st input "slot" operand dup "obj" operand ADD ! store new slot value "val" operand "slot" operand r> call ; inline : load-cards-offset ( dest -- ) "cards_offset" f pick compile-dlsym dup 0 LWZ ; : generate-write-barrier ( -- ) "obj" operand dup card-bits SRAWI "x" operand load-cards-offset "obj" operand dup "x" operand ADD "x" operand "obj" operand 0 LBZ "x" operand dup card-mark ORI "x" operand "obj" operand 0 STB ; \ set-slot { ! Slot number is literal { [ "obj" operand dup %untag "val" operand "obj" operand "n" get cells STW generate-write-barrier ] H{ { +input+ { { f "val" } { f "obj" } { [ cells ] "n" } } } { +scratch+ { { f "x" } } } { +clobber+ { "obj" } } } } ! Slot number is in a register { [ "obj" operand dup %untag cell log2 [ 0 STW ] generate-set-slot generate-write-barrier ] H{ { +input+ { { f "val" } { f "obj" } { f "slot" } } } { +scratch+ { { f "x" } } } { +clobber+ { "obj" "slot" } } } } } define-intrinsics \ set-char-slot [ ! untag the new value in 0th input "val" operand dup %untag-fixnum 1 [ string-offset STH ] generate-set-slot ] H{ { +input+ { { f "val" } { f "slot" } { f "obj" } } } { +scratch+ { { f "x" } } } { +clobber+ { "val" "slot" "obj" } } } define-intrinsic : fixnum-register-op ( op -- pair ) [ "out" operand "y" operand "x" operand ] swap add H{ { +input+ { { f "x" } { f "y" } } } { +scratch+ { { f "out" } } } { +output+ { "out" } } } 2array ; : fixnum-value-op ( op -- pair ) [ "out" operand "x" operand "y" operand ] swap add H{ { +input+ { { f "x" } { [ v>operand ] "y" } } } { +scratch+ { { f "out" } } } { +output+ { "out" } } } 2array ; : define-fixnum-op ( word imm-op reg-op -- ) >r fixnum-value-op r> fixnum-register-op 2array define-intrinsics ; { { fixnum+fast ADDI ADD } { fixnum-fast SUBI SUBF } { fixnum-bitand ANDI AND } { fixnum-bitor ORI OR } { fixnum-bitxor XORI XOR } } [ first3 define-fixnum-op ] each : generate-fixnum-mod #! PowerPC doesn't have a MOD instruction; so we compute #! x-(x/y)*y. Puts the result in "s" operand. "s" operand "r" operand "y" operand MULLW "s" operand "s" operand "x" operand SUBF ; \ fixnum-mod [ ! divide x by y, store result in x "r" operand "x" operand "y" operand DIVW generate-fixnum-mod ] H{ { +input+ { { f "x" } { f "y" } } } { +scratch+ { { f "r" } { f "s" } } } { +output+ { "s" } } } define-intrinsic \ fixnum-bitnot [ "x" operand dup NOT "x" operand dup %untag ] H{ { +input+ { { f "x" } } } { +output+ { "x" } } } define-intrinsic : fixnum-register-jump ( op -- pair ) [ "x" operand 0 "y" operand CMP ] swap add { { f "x" } { f "y" } } 2array ; : fixnum-value-jump ( op -- pair ) [ 0 "x" operand "y" operand CMPI ] swap add { { f "x" } { [ v>operand ] "y" } } 2array ; : define-fixnum-jump ( word op -- ) [ fixnum-value-jump ] keep fixnum-register-jump 2array define-if-intrinsics ; { { fixnum< BLT } { fixnum<= BLE } { fixnum> BGT } { fixnum>= BGE } { eq? BEQ } } [ first2 define-fixnum-jump ] each : simple-overflow ( insn1 insn2 -- ) [ >r 0 0 LI 0 MTXER "r" operand "y" operand "x" operand r> execute >r "end" define-label "end" get BNO { "x" "y" } [ dup %untag-fixnum ] unique-operands "r" operand "y" operand "x" operand r> execute "r" operand %allot-bignum-signed-1 "end" resolve-label ] with-scope ; inline \ fixnum+ [ \ ADD \ ADDO. simple-overflow ] H{ { +input+ { { f "x" } { f "y" } } } { +scratch+ { { f "r" } } } { +output+ { "r" } } { +clobber+ { "x" "y" } } } define-intrinsic \ fixnum- [ \ SUBF \ SUBFO. simple-overflow ] H{ { +input+ { { f "x" } { f "y" } } } { +scratch+ { { f "r" } } } { +output+ { "r" } } { +clobber+ { "x" "y" } } } define-intrinsic : generate-fixnum/i #! This VOP is funny. If there is an overflow, it falls #! through to the end, and the result is in "x" operand. #! Otherwise it jumps to the "no-overflow" label and the #! result is in "r" operand. "end" define-label "no-overflow" define-label "r" operand "x" operand "y" operand DIVW ! if the result is greater than the most positive fixnum, ! which can only ever happen if we do ! most-negative-fixnum -1 /i, then the result is a bignum. most-positive-fixnum "s" operand LOAD "r" operand 0 "s" operand CMP "no-overflow" get BLE most-negative-fixnum neg "x" operand LOAD "x" operand %allot-bignum-signed-1 ; \ fixnum/i [ generate-fixnum/i "end" get B "no-overflow" resolve-label "r" operand "x" operand %tag-fixnum "end" resolve-label ] H{ { +input+ { { f "x" } { f "y" } } } { +scratch+ { { f "r" } { f "s" } } } { +output+ { "x" } } { +clobber+ { "y" } } } define-intrinsic \ fixnum/mod [ generate-fixnum/i 0 "s" operand LI "end" get B "no-overflow" resolve-label generate-fixnum-mod "r" operand "x" operand %tag-fixnum "end" resolve-label ] H{ { +input+ { { f "x" } { f "y" } } } { +scratch+ { { f "r" } { f "s" } } } { +output+ { "x" "s" } } { +clobber+ { "y" } } } define-intrinsic \ fixnum>bignum [ "nonzero" define-label "end" define-label 0 "x" operand 0 CMPI ! is it zero? "nonzero" get BNE 0 >bignum "x" get load-literal "end" get B "nonzero" resolve-label "x" operand dup %untag-fixnum "x" operand %allot-bignum-signed-1 "end" resolve-label ] H{ { +input+ { { f "x" } } } { +output+ { "x" } } } define-intrinsic \ bignum>fixnum [ "nonzero" define-label "positive" define-label "end" define-label "x" operand dup %untag "y" operand "x" operand cell LWZ ! if the length is 1, its just the sign and nothing else, ! so output 0 0 "y" operand 1 tag-bits shift CMPI "nonzero" get BNE 0 "y" operand LI "end" get B "nonzero" resolve-label ! load the value "y" operand "x" operand 3 cells LWZ ! load the sign "x" operand "x" operand 2 cells LWZ ! is the sign negative? 0 "x" operand 0 CMPI "positive" get BEQ "y" operand dup -1 MULI "positive" resolve-label "y" operand dup %tag-fixnum "end" resolve-label ] H{ { +input+ { { f "x" } } } { +scratch+ { { f "y" } } } { +clobber+ { "x" } } { +output+ { "y" } } } define-intrinsic : define-float-op ( word op -- ) [ "x" operand "x" operand "y" operand ] swap add H{ { +input+ { { float "x" } { float "y" } } } { +output+ { "x" } } } define-intrinsic ; { { float+ FADD } { float- FSUB } { float* FMUL } { float/f FDIV } } [ first2 define-float-op ] each : define-float-jump ( word op -- ) [ "x" operand 0 "y" operand FCMPU ] swap add { { float "x" } { float "y" } } define-if-intrinsic ; { { float< BLT } { float<= BLE } { float> BGT } { float>= BGE } { float= BEQ } } [ first2 define-float-jump ] each \ float>fixnum [ "scratch" operand "in" operand FCTIWZ "scratch" operand 1 0 param@ STFD "out" operand 1 cell param@ LWZ "out" operand dup %tag-fixnum ] H{ { +input+ { { float "in" } } } { +scratch+ { { float "scratch" } { f "out" } } } { +output+ { "out" } } } define-intrinsic \ tag [ "out" operand "in" operand tag-mask ANDI "out" operand dup %tag-fixnum ] H{ { +input+ { { f "in" } } } { +scratch+ { { f "out" } } } { +output+ { "out" } } } define-intrinsic \ type [ "f" define-label "end" define-label ! Get the tag "y" operand "obj" operand tag-mask ANDI ! Tag the tag "y" operand "x" operand %tag-fixnum ! Compare with object tag number (3). 0 "y" operand object-tag CMPI ! Jump if the object doesn't store type info in its header "end" get BNE ! It does store type info in its header ! Is the pointer itself equal to 3? Then its F_TYPE (9). 0 "obj" operand object-tag CMPI "f" get BEQ ! The pointer is not equal to 3. Load the object header. "x" operand "obj" operand object-tag neg LWZ "x" operand dup %untag "end" get B "f" resolve-label ! The pointer is equal to 3. Load F_TYPE (9). f type tag-bits shift "x" operand LI "end" resolve-label ] H{ { +input+ { { f "obj" } } } { +scratch+ { { f "x" } { f "y" } } } { +output+ { "x" } } } define-intrinsic : userenv ( reg -- ) #! Load the userenv pointer in a register. "userenv" f rot compile-dlsym ; \ getenv [ "n" operand dup 1 SRAWI "x" operand userenv "x" operand "n" operand "x" operand ADD "x" operand dup 0 LWZ ] H{ { +input+ { { f "n" } } } { +scratch+ { { f "x" } } } { +output+ { "x" } } { +clobber+ { "n" } } } define-intrinsic \ setenv [ "n" operand dup 1 SRAWI "x" operand userenv "x" operand "n" operand "x" operand ADD "val" operand "x" operand 0 STW ] H{ { +input+ { { f "val" } { f "n" } } } { +scratch+ { { f "x" } } } { +clobber+ { "n" } } } define-intrinsic