]> gitweb.factorcode.org Git - factor.git/commitdiff
fixnum-shift intrinsics
authorSlava Pestov <slava@factorcode.org>
Tue, 10 May 2005 02:34:47 +0000 (02:34 +0000)
committerSlava Pestov <slava@factorcode.org>
Tue, 10 May 2005 02:34:47 +0000 (02:34 +0000)
16 files changed:
library/compiler/intrinsics.factor
library/compiler/simplifier.factor
library/compiler/vops.factor
library/compiler/x86/assembler.factor
library/compiler/x86/fixnum.factor
library/compiler/x86/generator.factor
library/math/math.factor
library/test/benchmark/fib.factor
library/test/compiler/intrinsics.factor
library/test/math/integer.factor
library/test/test.factor
native/compiler.h
native/factor.c
native/fixnum.c
native/image.c
native/image.h

index ad2d719eed01b347c8c64c9929f9b723481d93a6..bfd9f671a81623c938faa2948e1afee08f5d9358 100644 (file)
@@ -69,10 +69,12 @@ sequences words ;
     out-1
 ] "linearizer" set-word-prop
 
-: top-literal? ( seq -- ? ) peek literal? ;
+: node-peek ( node -- obj ) node-consume-d swap hash peek ;
+
 : peek-2 dup length 2 - swap nth ;
-: next-typed? ( seq -- ? )
-    peek-2 value-types length 1 = ;
+: node-peek-2 ( node -- obj ) node-consume-d swap hash peek-2 ;
+
+: typed? ( value -- ? ) value-types length 1 = ;
 
 : self ( word -- )
     f swap dup "infer-effect" word-prop (consume/produce) ;
@@ -82,14 +84,19 @@ sequences words ;
 
 \ slot intrinsic
 
-: slot@ ( seq -- n )
+: slot@ ( node -- n )
     #! Compute slot offset.
+    node-consume-d swap hash
     dup peek literal-value cell *
     swap peek-2 value-types car type-tag - ;
 
+: typed-literal? ( node -- ? )
+    #! Output if the node's first input is well-typed, and the
+    #! second is a literal.
+    dup node-peek literal? swap node-peek-2 typed? and ;
+
 \ slot [
-    node-consume-d swap hash
-    dup top-literal? over next-typed? and [
+    dup typed-literal? [
         1 %dec-d ,
         in-1
         0 swap slot@ %fast-slot ,
@@ -105,8 +112,7 @@ sequences words ;
 \ set-slot intrinsic
 
 \ set-slot [
-    node-consume-d swap hash
-    dup top-literal? over next-typed? and [
+    dup typed-literal? [
         1 %dec-d ,
         in-2
         2 %dec-d ,
@@ -149,11 +155,10 @@ sequences words ;
 
 : binary-op ( node op out -- )
     #! out is a vreg where the vop stores the result.
-    >r >r node-consume-d swap hash
-    dup top-literal? [
+    >r >r node-peek dup literal? [
         1 %dec-d ,
         in-1
-        peek literal-value 0 <vreg> r> execute ,
+        literal-value 0 <vreg> r> execute ,
         r> 0 %replace-d ,
     ] [
         drop
@@ -166,7 +171,6 @@ sequences words ;
     [[ fixnum-bitand %fixnum-bitand ]]
     [[ fixnum-bitor  %fixnum-bitor  ]]
     [[ fixnum-bitxor %fixnum-bitxor ]]
-    [[ fixnum-shift  %fixnum-shift  ]]
     [[ fixnum<=      %fixnum<=      ]]
     [[ fixnum<       %fixnum<       ]]
     [[ fixnum>=      %fixnum>=      ]]
@@ -181,7 +185,19 @@ sequences words ;
 \ fixnum* intrinsic
 
 \ fixnum* [
-    drop \ %fixnum* 0 binary-op-reg
+    ! Turn multiplication by a power of two into a left shift.
+    node-peek dup literal? [
+        literal-value dup power-of-2? [
+            1 %dec-d ,
+            in-1
+            log2 0 <vreg> %fixnum<< ,
+            0 0 %replace-d ,
+        ] [
+            drop binary-op-reg
+        ] ifte
+    ] [
+        drop binary-op-reg
+    ] ifte
 ] "linearizer" set-word-prop
 
 \ fixnum-mod intrinsic
@@ -218,3 +234,48 @@ sequences words ;
     0 %fixnum-bitnot ,
     out-1
 ] "linearizer" set-word-prop
+
+: slow-shift ( -- ) \ fixnum-shift %call , ;
+
+: negative-shift ( n -- )
+    1 %dec-d ,
+    in-1
+    dup cell -8 * <= [
+        drop 0 <vreg> 2 <vreg> %fixnum-sgn ,
+        2 0 %replace-d ,
+    ] [
+        neg 0 <vreg> %fixnum>> ,
+        out-1
+    ] ifte ;
+
+: positive-shift ( n -- )
+    dup cell 8 * tag-bits - <= [
+        1 %dec-d ,
+        in-1
+        0 <vreg> %fixnum<< ,
+        out-1
+    ] [
+        drop slow-shift
+    ] ifte ;
+
+: fast-shift ( n -- )
+    dup 0 = [
+        1 %dec-d ,
+        drop
+    ] [
+        dup 0 < [
+            negative-shift
+        ] [
+            positive-shift
+        ] ifte
+    ] ifte ;
+
+\ fixnum-shift intrinsic
+
+\ fixnum-shift [
+    node-peek dup literal? [
+        literal-value fast-shift
+    ] [
+        drop slow-shift
+    ] ifte
+] "linearizer" set-word-prop
index 8d66824c5ae92f678e1198f027390ff9ce932c58..17623e785c13b27bb0ff2ea49e329db5a003ac1c 100644 (file)
@@ -191,7 +191,7 @@ M: %call-label simplify-node ( linear vop -- ? )
 : dead-code ( linear -- linear ? )
     uncons (dead-code) >r cons r> ;
 
-M: %jump-label simplify-node ( linear vop -- ? )
+M: %jump-label simplify-node ( linear vop -- linear ? )
     drop
     \ %return dup double-jump [
         t
@@ -211,7 +211,6 @@ M: %jump-label simplify-node ( linear vop -- ? )
             ! ] ifte
         ] ifte
     ] ifte ;
-
 ! 
 ! #jump-label [
 !     [ #return #return double-jump ]
index 8312699052b0ed6832b69e2856a6c51924f70f27..ba2759e508c47a18c014486dfd53e810c9f56f38 100644 (file)
@@ -142,7 +142,6 @@ VOP: %fixnum-bitand : %fixnum-bitand src/dest-vop <%fixnum-bitand> ;
 VOP: %fixnum-bitor  : %fixnum-bitor src/dest-vop <%fixnum-bitor> ;
 VOP: %fixnum-bitxor : %fixnum-bitxor src/dest-vop <%fixnum-bitxor> ;
 VOP: %fixnum-bitnot : %fixnum-bitnot <vreg> dest-vop <%fixnum-bitnot> ;
-VOP: %fixnum-shift  : %fixnum-shift src/dest-vop <%fixnum-shift> ;
 
 VOP: %fixnum<=      : %fixnum<= src/dest-vop <%fixnum<=> ;
 VOP: %fixnum<       : %fixnum< src/dest-vop <%fixnum<> ;
@@ -150,6 +149,22 @@ VOP: %fixnum>=      : %fixnum>= src/dest-vop <%fixnum>=> ;
 VOP: %fixnum>       : %fixnum> src/dest-vop <%fixnum>> ;
 VOP: %eq?           : %eq? src/dest-vop <%eq?> ;
 
+! At the VOP level, the 'shift' operation is split into five
+! distinct operations:
+! - shifts with a large positive count: calls runtime to make
+!   a bignum
+! - shifts with a small positive count: %fixnum<<
+! - shifts with a small negative count: %fixnum>>
+! - shifts with a small negative count: %fixnum>>
+! - shifts with a large negative count: %fixnum-sgn
+VOP: %fixnum<<   : %fixnum<<   src/dest-vop <%fixnum<<> ;
+VOP: %fixnum>>   : %fixnum>>   src/dest-vop <%fixnum>>> ;
+! due to x86 limitations the destination of this VOP must be
+! vreg 2 (EDX), and the source must be vreg 0 (EAX).
+VOP: %fixnum-sgn : %fixnum-sgn src/dest-vop <%fixnum-sgn> ;
+
+! Integer comparison followed by a conditional branch is
+! optimized
 VOP: %jump-fixnum<= : %jump-fixnum<= f swap <%jump-fixnum<=> ;
 VOP: %jump-fixnum<  : %jump-fixnum< f swap <%jump-fixnum<> ;
 VOP: %jump-fixnum>= : %jump-fixnum>= f swap <%jump-fixnum>=> ;
index ac909daed2f31d0777d56e824c6d20a2d6b04dca..0d0c6e02a8ccf550b715d0bde84649f1926a8d5f 100644 (file)
@@ -202,7 +202,7 @@ M: word JUMPcc ( opcode addr -- )
 : JNO HEX: 81 swap JUMPcc ;
 : JB  HEX: 82 swap JUMPcc ;
 : JAE HEX: 83 swap JUMPcc ;
-: JE  HEX: 84 swap JUMPcc ;
+: JE  HEX: 84 swap JUMPcc ; ! aka JZ
 : JNE HEX: 85 swap JUMPcc ;
 : JBE HEX: 86 swap JUMPcc ;
 : JA  HEX: 87 swap JUMPcc ;
@@ -260,12 +260,14 @@ M: operand CMP OCT: 071 2-operand ;
 
 : CDQ HEX: 99 compile-byte ;
 
+: ROL ( dst n -- ) HEX: c1 BIN: 000 immediate-8 ;
+: ROR ( dst n -- ) HEX: c1 BIN: 001 immediate-8 ;
+: RCL ( dst n -- ) HEX: c1 BIN: 010 immediate-8 ;
+: RCR ( dst n -- ) HEX: c1 BIN: 011 immediate-8 ;
 : SHL ( dst n -- ) HEX: c1 BIN: 100 immediate-8 ;
 : SHR ( dst n -- ) HEX: c1 BIN: 101 immediate-8 ;
 : SAR ( dst n -- ) HEX: c1 BIN: 111 immediate-8 ;
 
-: RCR ( dst -- ) HEX: d1 compile-byte BIN: 011 1-operand ;
-
 : LEA ( dst src -- )
     HEX: 8d compile-byte swap register 1-operand ;
 
index f770c57c885fd86a06c48a0dd881718d100f1f03..4baffd5de6d581fdc0f46735dea637a1f4eb7cef 100644 (file)
@@ -12,7 +12,7 @@ memory namespaces words ;
     "end" get JNO
     ! There was an overflow. Untag the fixnum and add the carry.
     ! Thanks to Dazhbog for figuring out this trick.
-    dup RCR
+    dup RCR
     dup 2 SAR
     ! Create a bignum
     PUSH
@@ -36,7 +36,6 @@ M: %fixnum* generate-node ( vop -- )
     ECX IMUL
     <label> "end" set
     "end" get JNO
-    ! make a bignum
     EDX PUSH
     EAX PUSH
     "s48_long_long_to_bignum" f compile-c-call
@@ -70,7 +69,7 @@ M: %fixnum-mod generate-node ( vop -- )
     ECX EAX MOV
     ! Tag the value, since division cancelled tags from both
     ! inputs
-    EAX 3 SHL
+    EAX tag-bits SHL
     ! Did it overflow?
     "end" get JNO
     ! There was an overflow, so make ECX into a bignum. we must
@@ -80,7 +79,7 @@ M: %fixnum-mod generate-node ( vop -- )
     "s48_long_to_bignum" f compile-c-call
     ! An untagged pointer to the bignum is now in EAX; tag it
     EAX bignum-tag OR
-    ESP 4 ADD
+    ESP cell ADD
     ! the remainder is now in EDX
     EDX POP
     "end" get save-xt ;
@@ -101,6 +100,47 @@ M: %fixnum-bitnot generate-node ( vop -- )
     ! Mask off the low 3 bits to give a fixnum tag
     tag-mask XOR ;
 
+M: %fixnum<< generate-node
+    ! This has specific register requirements.
+    <label> "no-overflow" set
+    <label> "end" set
+    ! make a copy
+    ECX EAX MOV
+    vop-source
+    ! check for potential overflow
+    1 over cell 8 * swap 1 - - shift ECX over ADD
+    2 * 1 - ECX swap CMP
+    ! is there going to be an overflow?
+    "no-overflow" get JBE
+    ! there is going to be an overflow, make a bignum
+    EAX tag-bits SAR
+    dup ( n) PUSH
+    EAX PUSH
+    "s48_long_to_bignum" f compile-c-call
+    EDX POP
+    EAX PUSH
+    "s48_bignum_arithmetic_shift" f compile-c-call
+    ! tag the result
+    EAX bignum-tag OR
+    ESP cell 2 * ADD
+    "end" get JMP
+    ! there is not going to be an overflow
+    "no-overflow" get save-xt
+    EAX swap SHL
+    "end" get save-xt ;
+
+M: %fixnum>> generate-node
+    ! shift register
+    dup vop-dest v>operand dup rot vop-source SAR
+    ! give it a fixnum tag
+    tag-mask bitnot AND ;
+
+M: %fixnum-sgn generate-node
+    ! store 0 in EDX if EAX is >=0, otherwise store -1.
+    CDQ
+    ! give it a fixnum tag.
+    vop-dest v>operand tag-bits SHL ;
+
 : conditional ( dest cond -- )
     #! Compile this after a conditional jump to store f or t
     #! in dest depending on the jump being taken or not.
index 5b40c6c9962a2ab7e2e8d29f18d16b8c1b477166..9a26c2649314048c13d3a4161143a9527d326db3 100644 (file)
@@ -141,9 +141,9 @@ M: %arithmetic-type generate-node ( vop -- )
     ECX [ ESI ] MOV
     ! Compute their tags
     EAX BIN: 111 AND
-    EDX BIN: 111 AND
+    ECX BIN: 111 AND
     ! Are the tags equal?
-    EAX EDX CMP
+    EAX ECX CMP
     "end" get JE
     ! No, they are not equal. Call a runtime function to
     ! coerce the integers to a higher type.
index ac0a86227a5cbf35b4645d8c6a0b45958c9457f7..ada80744c88d34a35bf53a16a9f8be330df04ce8 100644 (file)
@@ -81,4 +81,13 @@ GENERIC: abs ( z -- |z| )
         rot [ [ rot dup slip -rot ] repeat ] keep -rot
     ] repeat 2drop ; inline
 
-: power-of-2? ( n -- ? ) dup dup neg bitand = ;
+: power-of-2? ( n -- ? )
+    dup 0 > [
+        dup dup neg bitand =
+    ] [
+        drop f
+    ] ifte ;
+
+: log2 ( n -- b )
+    #! Log base two for integers.
+    dup 1 = [ drop 0 ] [ 2 /i log2 1 + ] ifte ;
index 17c06038c7e198e4e269a09f93198d8bad41316c..d74881a0375261845d42bb8208f1cb8a7cb52bae 100644 (file)
@@ -35,4 +35,4 @@ TUPLE: box i ;
         swap box-i swap box-i + <box>
     ] ifte ; compiled
 
-[ << box f 9227465 ] [ << box f 34 >> tuple-fib ] unit-test
+[ << box f 9227465 >> ] [ << box f 34 >> tuple-fib ] unit-test
index 6016a700a40e3de44bdaa87877b2fa5012542582..72e20a2766ca2c426efc316eb17a5b862440d2e5 100644 (file)
@@ -48,6 +48,28 @@ math-internals test words ;
 [ 11 ] [ 12 [ 7 fixnum-bitxor ] compile-1 ] unit-test
 [ 11 ] [ [ 12 7 fixnum-bitxor ] compile-1 ] unit-test
 
+[ 4294967296 ] [ 1 32 [ fixnum-shift ] compile-1 ] unit-test
+[ 4294967296 ] [ 1 [ 32 fixnum-shift ] compile-1 ] unit-test
+[ 4294967296 ] [ 1 [ 16 fixnum-shift 16 fixnum-shift ] compile-1 ] unit-test
+[ -4294967296 ] [ -1 32 [ fixnum-shift ] compile-1 ] unit-test
+[ -4294967296 ] [ -1 [ 32 fixnum-shift ] compile-1 ] unit-test
+[ -4294967296 ] [ -1 [ 16 fixnum-shift 16 fixnum-shift ] compile-1 ] unit-test
+
+[ 8 ] [ 1 3 [ fixnum-shift ] compile-1 ] unit-test
+[ 8 ] [ 1 [ 3 fixnum-shift ] compile-1 ] unit-test
+[ 8 ] [ [ 1 3 fixnum-shift ] compile-1 ] unit-test
+[ -8 ] [ -1 3 [ fixnum-shift ] compile-1 ] unit-test
+[ -8 ] [ -1 [ 3 fixnum-shift ] compile-1 ] unit-test
+[ -8 ] [ [ -1 3 fixnum-shift ] compile-1 ] unit-test
+
+[ 2 ] [ 8 -2 [ fixnum-shift ] compile-1 ] unit-test
+[ 2 ] [ 8 [ -2 fixnum-shift ] compile-1 ] unit-test
+
+[ 0 ] [ [ 123 -64 fixnum-shift ] compile-1 ] unit-test
+[ 0 ] [ 123 -64 [ fixnum-shift ] compile-1 ] unit-test
+[ -1 ] [ [ -123 -64 fixnum-shift ] compile-1 ] unit-test
+[ -1 ] [ -123 -64 [ fixnum-shift ] compile-1 ] unit-test
+
 [ f ] [ 12 7 [ fixnum< ] compile-1 ] unit-test
 [ f ] [ 12 [ 7 fixnum< ] compile-1 ] unit-test
 [ f ] [ [ 12 7 fixnum< ] compile-1 ] unit-test
index 3b79bbe074491b8ba1941979fbaca726de32500a..b98beb0bc05e7768ab7e176dea8efff99dba2d99 100644 (file)
@@ -80,3 +80,8 @@ unit-test
 [ 1/8 ] [ 1/2 3 ^ ] unit-test
 [ 1/8 ] [ 2 -3 ^ ] unit-test
 [ t ] [ 1 100 shift 2 100 ^ = ] unit-test
+
+[ t ] [ 256 power-of-2? ] unit-test
+[ f ] [ 123 power-of-2? ] unit-test
+[ 8 ] [ 256 log2 ] unit-test
+[ 0 ] [ 1 log2 ] unit-test
index 4a39bc6b8589c3349918e29139074f878858f87a..77b7c474c193ed949b782840781540400440f4d0 100644 (file)
@@ -4,7 +4,7 @@ IN: test
 USING: errors kernel lists math memory namespaces parser
 prettyprint sequences stdio strings unparser vectors words ;
 
-TUPLE: assert expect got ;
+TUPLE: assert got expect ;
 M: assert error.
     "Assertion failed" print
     "Expected: " write dup assert-expect .
index 5eaa294dc605f5d41ffffeba7ddd63e530da38f1..2c822d3d06e7e055993f450b4b6b4880a749465c 100644 (file)
@@ -10,8 +10,6 @@ typedef struct
 
 ZONE compiling;
 
-#define LITERAL_TABLE 4096
-
 CELL literal_top;
 CELL literal_max;
 
index 2d431e3f18580a2d2bc3082e256de6f486438527..a36661361fc90c6b6e0ba15f0d05fb51628d9cec 100644 (file)
@@ -1,13 +1,13 @@
 #include "factor.h"
 
 void init_factor(char* image, CELL ds_size, CELL cs_size,
-       CELL data_size, CELL code_size)
+       CELL data_size, CELL code_size, CELL literal_size)
 {
        srand((unsigned)time(NULL)); /* initialize random number generator */
        init_ffi();
        init_arena(data_size);
        init_compiler(code_size);
-       load_image(image);
+       load_image(image,literal_size);
        init_stacks(ds_size,cs_size);
        init_c_io();
        init_signals();
@@ -34,6 +34,7 @@ int main(int argc, char** argv)
        CELL cs_size = 2048;
        CELL data_size = 16;
        CELL code_size = 2;
+       CELL literal_size = 64;
        CELL args;
        CELL i;
 
@@ -45,6 +46,7 @@ int main(int argc, char** argv)
                printf(" +Cn   Call stack size, kilobytes\n");
                printf(" +Mn   Data heap size, megabytes\n");
                printf(" +Xn   Code heap size, megabytes\n");
+               printf(" +Ln   Literal table size, kilobytes. Only for bootstrapping\n");
                printf("Other options are handled by the Factor library.\n");
                printf("See the documentation for details.\n");
                printf("Send bug reports to Slava Pestov <slava@jedit.org>.\n");
@@ -57,6 +59,7 @@ int main(int argc, char** argv)
                if(factor_arg(argv[i],"+C%d",&cs_size)) continue;
                if(factor_arg(argv[i],"+M%d",&data_size)) continue;
                if(factor_arg(argv[i],"+X%d",&code_size)) continue;
+               if(factor_arg(argv[i],"+L%d",&literal_size)) continue;
 
                if(strncmp(argv[i],"+",1) == 0)
                {
@@ -69,7 +72,8 @@ int main(int argc, char** argv)
                ds_size * 1024,
                cs_size * 1024,
                data_size * 1024 * 1024,
-               code_size * 1024 * 1024);
+               code_size * 1024 * 1024,
+               literal_size * 1024);
 
        args = F;
        while(--argc != 0)
index f05a641b6d2a4e3ba188d2d975af201b17182c6f..18091f48f651dabc089efed53e5b1721aa980425 100644 (file)
@@ -32,6 +32,9 @@ void primitive_to_fixnum(void)
        drepl(tag_fixnum(to_fixnum(dpeek())));
 }
 
+/* The fixnum arithmetic operations defined in C are relatively slow.
+The Factor compiler has optimized assembly intrinsics for all these
+operations. */
 void primitive_fixnum_add(void)
 {
        F_FIXNUM y = untag_fixnum_fast(dpop());
index 650d8e67d88374451de41b832b7753a4099d179c..5dcacd81a84609c91ecb6c53ffbea0065a5d4673 100644 (file)
@@ -1,6 +1,6 @@
 #include "factor.h"
 
-void load_image(char* filename)
+void load_image(char* filename, int literal_table)
 {
        FILE* file;
        HEADER h;
@@ -24,9 +24,9 @@ void load_image(char* filename)
                        fread(&ext_h,sizeof(HEADER_2)/sizeof(CELL),sizeof(CELL),file);
                else if(h.version == IMAGE_VERSION_0)
                {
-                       ext_h.size = LITERAL_TABLE;
+                       ext_h.size = literal_table;
                        ext_h.literal_top = 0;
-                       ext_h.literal_max = LITERAL_TABLE;
+                       ext_h.literal_max = literal_table;
                        ext_h.relocation_base = compiling.base;
                }
                else
index cfc58394b833ac12f6cb3fecced7d82d4b780b95..eb2acbffe14f606b31ad259f3a709169115aa01a 100644 (file)
@@ -28,6 +28,6 @@ typedef struct EXT_HEADER {
        CELL literal_max;
 } HEADER_2;
 
-void load_image(char* file);
+void load_image(char* file, int literal_size);
 bool save_image(char* file);
 void primitive_save_image(void);