From 7418990bdc1094f66781dda1edca63260616af0a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 16 May 2005 21:01:39 +0000 Subject: [PATCH] linear IR and simplifier refactoring --- CHANGES.txt | 3 + library/bootstrap/boot-stage2.factor | 2 - library/compiler/simplifier.factor | 78 +++++++--- library/compiler/vops.factor | 190 ++++++++++++++++-------- library/compiler/x86/alien.factor | 10 +- library/compiler/x86/fixnum.factor | 12 +- library/compiler/x86/generator.factor | 20 +-- library/compiler/x86/slots.factor | 42 +++--- library/compiler/x86/stack.factor | 18 +-- library/generic/builtin.factor | 4 +- library/generic/tuple.factor | 2 +- library/inference/branches.factor | 75 +--------- library/inference/partial-eval.factor | 23 +-- library/inference/ties.factor | 48 ------ library/inference/types.factor | 30 ---- library/inference/values.factor | 2 +- library/test/compiler/intrinsics.factor | 8 + library/test/inference.factor | 55 ++++--- library/test/lists/lists.factor | 1 - 19 files changed, 284 insertions(+), 339 deletions(-) delete mode 100644 library/inference/ties.factor delete mode 100644 library/inference/types.factor diff --git a/CHANGES.txt b/CHANGES.txt index 90ffbe8950..45de49b938 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -7,6 +7,9 @@ for controlling it: +Yn Size of 2 youngest generations, megabytes +An Size of tenured and semi-spaces, megabytes +The compiler now does constant folding for certain words with literal +operands. The compiler's peephole optimizer has been improved. + The alien interface now supports "float" and "double" types. Defining a predicate subclass of tuple is supported now. Note that diff --git a/library/bootstrap/boot-stage2.factor b/library/bootstrap/boot-stage2.factor index 8b7a1945ef..e5a89419e7 100644 --- a/library/bootstrap/boot-stage2.factor +++ b/library/bootstrap/boot-stage2.factor @@ -30,11 +30,9 @@ t [ "/library/inference/dataflow.factor" "/library/inference/values.factor" "/library/inference/inference.factor" - "/library/inference/ties.factor" "/library/inference/branches.factor" "/library/inference/words.factor" "/library/inference/stack.factor" - "/library/inference/types.factor" "/library/inference/partial-eval.factor" "/library/compiler/assembler.factor" diff --git a/library/compiler/simplifier.factor b/library/compiler/simplifier.factor index 4897b97878..fd12a4b60f 100644 --- a/library/compiler/simplifier.factor +++ b/library/compiler/simplifier.factor @@ -2,7 +2,7 @@ ! See http://factor.sf.net/license.txt for BSD license. IN: compiler-backend USING: generic inference kernel lists math namespaces -prettyprint strings words ; +prettyprint sequences strings words ; ! A peephole optimizer operating on the linear IR. @@ -51,51 +51,91 @@ M: %label simplify-node ( linear vop -- linear ? ) M: %inc-d simplify-node ( linear vop -- linear ? ) #! %inc-d cancels a following %inc-d. - dup vop-literal 0 = [ + dup vop-in-1 0 = [ drop cdr t ] [ >r dup \ %inc-d next-physical? [ - vop-literal r> vop-literal + + vop-in-1 r> vop-in-1 + %inc-d >r cdr cdr r> swons t ] [ r> 2drop f ] ifte ] ifte ; -: dead-load? ( linear vop -- ? ) +: basic-block ( linear quot -- | quot: vop -- ? ) + #! Keep applying the quotation to each VOP until either a + #! VOP answering f to basic-block?, or the quotation answers + #! f. + over car basic-block? [ + >r uncons r> tuck >r >r call [ + r> r> basic-block + ] [ + r> r> 2drop + ] ifte + ] [ + 2drop + ] ifte ; inline + +: reads-vreg? ( vreg linear -- ? ) + #! Tests if the vreg is read before being written in the + #! current basic block. Outputs a true value if the vreg + #! is not read or written before the end of the basic block. + [ + 2dup vop-inputs contains? [ + ! we are reading the vreg + 2drop t f + ] [ + 2dup vop-outputs contains? [ + ! we are writing the vreg + 2drop f f + ] [ + ! keep checking + drop t + ] ifte + ] ifte + ] basic-block ; + +: dead-load ( vreg linear -- linear ? ) + #! If the vreg is not read before being written, drop + #! the current VOP. + tuck cdr reads-vreg? [ f ] [ cdr t ] ifte ; + +M: %peek-d simplify-node ( linear vop -- linear ? ) + vop-out-1 swap dead-load ; + +M: %immediate simplify-node ( linear vop -- linear ? ) + vop-out-1 swap dead-load ; + +M: %indirect simplify-node ( linear vop -- linear ? ) + vop-out-1 swap dead-load ; + +: dead-peek? ( linear vop -- ? ) #! Is the %replace-d followed by a %peek-d of the same #! stack slot and vreg? swap cdr car dup %peek-d? [ - over vop-source over vop-dest = >r - swap vop-literal swap vop-literal = r> and + over vop-in-2 over vop-out-1 = >r + swap vop-in-1 swap vop-in-1 = r> and ] [ 2drop f ] ifte ; -: dead-store? ( linear n -- ? ) +: dead-replace? ( linear n -- ? ) #! Is the %replace-d followed by a %dec-d, so the stored #! value is lost? swap \ %inc-d next-physical? [ - vop-literal + 0 < + vop-in-1 + 0 < ] [ 2drop f ] ifte ; M: %replace-d simplify-node ( linear vop -- linear ? ) - 2dup dead-load? [ + 2dup dead-peek? [ drop uncons cdr cons t ] [ - 2dup vop-literal dead-store? [ - drop cdr t - ] [ - drop f - ] ifte + dupd vop-in-1 dead-replace? [ cdr t ] [ f ] ifte ] ifte ; -! M: %immediate-d simplify-node ( linear vop -- linear ? ) -! over 0 dead-store? [ drop cdr t ] [ drop f ] ifte ; - -: pop? ( vop -- ? ) dup %inc-d? swap vop-literal -1 = and ; +: pop? ( vop -- ? ) dup %inc-d? swap vop-in-1 -1 = and ; : can-fast-branch? ( linear -- ? ) unswons class fast-branch [ @@ -105,7 +145,7 @@ M: %replace-d simplify-node ( linear vop -- linear ? ) ] ifte ; : fast-branch-params ( linear -- src dest label linear ) - uncons >r dup vop-source swap vop-dest r> cdr + uncons >r dup vop-in-1 swap vop-out-1 r> cdr uncons >r vop-label r> ; : make-fast-branch ( linear op -- linear ? ) diff --git a/library/compiler/vops.factor b/library/compiler/vops.factor index 145cc0584f..b00b19c1db 100644 --- a/library/compiler/vops.factor +++ b/library/compiler/vops.factor @@ -1,8 +1,8 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: compiler-backend -USING: errors generic hashtables kernel math namespaces parser -words ; +USING: errors generic hashtables kernel lists math namespaces +parser sequences words ; ! The linear IR is the second of the two intermediate ! representations used by Factor. It is basically a high-level @@ -22,13 +22,21 @@ words ; TUPLE: vreg n ; ! A virtual operation -TUPLE: vop source dest literal label ; +TUPLE: vop inputs outputs label ; +: vop-in-1 ( vop -- input ) vop-inputs car ; +: vop-in-2 ( vop -- input ) vop-inputs cdr car ; +: vop-in-3 ( vop -- input ) vop-inputs cdr cdr car ; +: vop-out-1 ( vop -- output ) vop-outputs car ; + +GENERIC: basic-block? ( vop -- ? ) +M: vop basic-block? drop f ; +! simplifies some code +M: f basic-block? drop f ; GENERIC: calls-label? ( label vop -- ? ) - M: vop calls-label? vop-label = ; -: make-vop ( source dest literal label vop -- vop ) +: make-vop ( inputs outputs label vop -- vop ) [ >r r> set-delegate ] keep ; : VOP: @@ -36,19 +44,21 @@ M: vop calls-label? vop-label = ; scan dup [ ] define-tuple create-in [ make-vop ] define-constructor ; parsing -: empty-vop f f f f ; -: label-vop ( label) >r f f f r> ; -: label/src-vop ( label src) swap >r f f r> ; -: src-vop ( src) f f f ; -: dest-vop ( dest) f swap f f ; -: src/dest-vop ( src dest) f f ; -: literal-vop ( literal) >r f f r> f ; -: src/literal-vop ( src literal) f swap f ; -: dest/literal-vop ( dest literal) >r f swap r> f ; +: empty-vop f f f ; +: label-vop ( label) >r f f r> ; +: label/src-vop ( label src) unit swap f swap ; +: src-vop ( src) unit f f ; +: dest-vop ( dest) unit dup f ; +: src/dest-vop ( src dest) >r unit r> unit f ; +: binary-vop ( src dest) [ 2list ] keep unit f ; +: 2-in-vop ( in1 in2) 2list f f ; +: 2-in/label-vop ( in1 in2 label) >r 2list f r> ; +: ternary-vop ( in1 in2 dest) >r 2list r> unit f ; ! miscellanea VOP: %prologue : %prologue empty-vop <%prologue> ; + VOP: %label : %label label-vop <%label> ; M: %label calls-label? 2drop f ; @@ -61,49 +71,69 @@ VOP: %return VOP: %return-to : %return-to label-vop <%return-to> ; + VOP: %jump : %jump label-vop <%jump> ; + VOP: %jump-label : %jump-label label-vop <%jump-label> ; + VOP: %call : %call label-vop <%call> ; + VOP: %call-label : %call-label label-vop <%call-label> ; + VOP: %jump-t : %jump-t label/src-vop <%jump-t> ; + VOP: %jump-f : %jump-f label/src-vop <%jump-f> ; ! dispatch tables VOP: %dispatch : %dispatch src-vop <%dispatch> ; + VOP: %target-label : %target-label label-vop <%target-label> ; + VOP: %target : %target label-vop <%target> ; + VOP: %end-dispatch : %end-dispatch empty-vop <%end-dispatch> ; ! stack operations VOP: %peek-d -: %peek-d ( vreg n -- ) >r >r f r> r> f <%peek-d> ; +: %peek-d ( vreg n -- ) swap src/dest-vop <%peek-d> ; +M: %peek-d basic-block? drop t ; + VOP: %replace-d -: %replace-d ( vreg n -- ) >r f r> f <%replace-d> ; +: %replace-d ( vreg n -- ) swap 2-in-vop <%replace-d> ; +M: %replace-d basic-block? drop t ; + VOP: %inc-d -: %inc-d ( n -- ) literal-vop <%inc-d> ; +: %inc-d ( n -- ) src-vop <%inc-d> ; : %dec-d ( n -- ) neg %inc-d ; +M: %inc-d basic-block? drop t ; + VOP: %immediate : %immediate ( vreg obj -- ) - >r r> dest/literal-vop <%immediate> ; + swap src/dest-vop <%immediate> ; +M: %immediate basic-block? drop t ; + VOP: %peek-r -: %peek-r ( vreg n -- ) >r >r f r> r> f <%peek-r> ; +: %peek-r ( vreg n -- ) swap src/dest-vop <%peek-r> ; + VOP: %replace-r -: %replace-r ( vreg n -- ) >r f r> f <%replace-r> ; +: %replace-r ( vreg n -- ) swap 2-in-vop <%replace-r> ; + VOP: %inc-r -: %inc-r ( n -- ) literal-vop <%inc-r> ; +: %inc-r ( n -- ) src-vop <%inc-r> ; + ! this exists, unlike %dec-d which does not, due to x86 quirks VOP: %dec-r -: %dec-r ( n -- ) literal-vop <%dec-r> ; +: %dec-r ( n -- ) src-vop <%dec-r> ; : in-1 0 0 %peek-d , ; : in-2 0 1 %peek-d , 1 0 %peek-d , ; @@ -112,44 +142,58 @@ VOP: %dec-r ! indirect load of a literal through a table VOP: %indirect -: %indirect ( vreg obj -- ) >r r> f -rot f <%indirect> ; +: %indirect ( vreg obj -- ) + swap src/dest-vop <%indirect> ; +M: %indirect basic-block? drop t ; ! object slot accessors ! mask off a tag (see also %untag-fixnum) VOP: %untag : %untag dest-vop <%untag> ; +M: %untag basic-block? drop t ; + VOP: %slot -: %slot ( n vreg ) >r r> f f <%slot> ; +: %slot ( n vreg ) >r r> binary-vop <%slot> ; +M: %slot basic-block? drop t ; VOP: %set-slot -: %set-slot ( vreg:value vreg:obj n ) - >r >r r> r> f <%set-slot> ; +: %set-slot ( value obj n ) + #! %set-slot writes to vreg n. + >r >r r> r> [ 3list ] keep unit f + <%set-slot> ; +M: %set-slot basic-block? drop t ; ! in the 'fast' versions, the object's type and slot number is ! known at compile time, so these become a single instruction VOP: %fast-slot -: %fast-slot ( vreg n ) >r >r f r> r> f <%fast-slot> ; +: %fast-slot ( vreg n ) + swap binary-vop <%fast-slot> ; +M: %fast-slot basic-block? drop t ; + VOP: %fast-set-slot -: %fast-set-slot ( vreg:value vreg:obj n ) - >r >r r> r> f <%fast-set-slot> ; +: %fast-set-slot ( value obj n ) + #! %fast-set-slot writes to vreg obj. + >r >r r> r> over >r 3list r> unit f + <%fast-set-slot> ; +M: %fast-set-slot basic-block? drop t ; ! fixnum intrinsics -VOP: %fixnum+ : %fixnum+ src/dest-vop <%fixnum+> ; -VOP: %fixnum- : %fixnum- src/dest-vop <%fixnum-> ; -VOP: %fixnum* : %fixnum* src/dest-vop <%fixnum*> ; -VOP: %fixnum-mod : %fixnum-mod src/dest-vop <%fixnum-mod> ; -VOP: %fixnum/i : %fixnum/i src/dest-vop <%fixnum/i> ; -VOP: %fixnum/mod : %fixnum/mod src/dest-vop <%fixnum/mod> ; -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+ : %fixnum+ binary-vop <%fixnum+> ; +VOP: %fixnum- : %fixnum- binary-vop <%fixnum-> ; +VOP: %fixnum* : %fixnum* binary-vop <%fixnum*> ; +VOP: %fixnum-mod : %fixnum-mod binary-vop <%fixnum-mod> ; +VOP: %fixnum/i : %fixnum/i binary-vop <%fixnum/i> ; +VOP: %fixnum/mod : %fixnum/mod binary-vop <%fixnum/mod> ; +VOP: %fixnum-bitand : %fixnum-bitand binary-vop <%fixnum-bitand> ; +VOP: %fixnum-bitor : %fixnum-bitor binary-vop <%fixnum-bitor> ; +VOP: %fixnum-bitxor : %fixnum-bitxor binary-vop <%fixnum-bitxor> ; VOP: %fixnum-bitnot : %fixnum-bitnot dest-vop <%fixnum-bitnot> ; -VOP: %fixnum<= : %fixnum<= src/dest-vop <%fixnum<=> ; -VOP: %fixnum< : %fixnum< src/dest-vop <%fixnum<> ; -VOP: %fixnum>= : %fixnum>= src/dest-vop <%fixnum>=> ; -VOP: %fixnum> : %fixnum> src/dest-vop <%fixnum>> ; -VOP: %eq? : %eq? src/dest-vop <%eq?> ; +VOP: %fixnum<= : %fixnum<= binary-vop <%fixnum<=> ; +VOP: %fixnum< : %fixnum< binary-vop <%fixnum<> ; +VOP: %fixnum>= : %fixnum>= binary-vop <%fixnum>=> ; +VOP: %fixnum> : %fixnum> binary-vop <%fixnum>> ; +VOP: %eq? : %eq? binary-vop <%eq?> ; ! At the VOP level, the 'shift' operation is split into five ! distinct operations: @@ -159,19 +203,28 @@ VOP: %eq? : %eq? src/dest-vop <%eq?> ; ! - 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>>> ; +VOP: %fixnum<< : %fixnum<< binary-vop <%fixnum<<> ; +VOP: %fixnum>> : %fixnum>> binary-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> ; +VOP: %fixnum-sgn : %fixnum-sgn binary-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>=> ; -VOP: %jump-fixnum> : %jump-fixnum> f swap <%jump-fixnum>> ; -VOP: %jump-eq? : %jump-eq? f swap <%jump-eq?> ; +VOP: %jump-fixnum<= +: %jump-fixnum<= 2-in/label-vop <%jump-fixnum<=> ; + +VOP: %jump-fixnum< +: %jump-fixnum< 2-in/label-vop <%jump-fixnum<> ; + +VOP: %jump-fixnum>= +: %jump-fixnum>= 2-in/label-vop <%jump-fixnum>=> ; + +VOP: %jump-fixnum> +: %jump-fixnum> 2-in/label-vop <%jump-fixnum>> ; + +VOP: %jump-eq? +: %jump-eq? 2-in/label-vop <%jump-eq?> ; : fast-branch ( class -- class ) {{ @@ -190,55 +243,62 @@ PREDICATE: tuple fast-branch ! some slightly optimized inline assembly VOP: %type : %type ( vreg ) dest-vop <%type> ; +M: %type basic-block? drop t ; VOP: %arithmetic-type : %arithmetic-type dest-vop <%arithmetic-type> ; VOP: %tag-fixnum : %tag-fixnum dest-vop <%tag-fixnum> ; +M: %tag-fixnum basic-block? drop t ; VOP: %untag-fixnum : %untag-fixnum dest-vop <%untag-fixnum> ; +M: %untag-fixnum basic-block? drop t ; : check-dest ( vop reg -- ) - swap vop-dest = [ "invalid VOP destination" throw ] unless ; + swap vop-out-1 = [ + "invalid VOP destination" throw + ] unless ; VOP: %getenv -: %getenv dest/literal-vop <%getenv> ; +: %getenv swap src/dest-vop <%getenv> ; +M: %getenv basic-block? drop t ; VOP: %setenv -: %setenv src/literal-vop <%setenv> ; +: %setenv 2-in-vop <%setenv> ; +M: %setenv basic-block? drop t ; ! alien operations VOP: %parameters -: %parameters ( n -- vop ) literal-vop <%parameters> ; +: %parameters ( n -- vop ) src-vop <%parameters> ; VOP: %parameter -: %parameter ( n -- vop ) literal-vop <%parameter> ; +: %parameter ( n -- vop ) src-vop <%parameter> ; VOP: %cleanup -: %cleanup ( n -- vop ) literal-vop <%cleanup> ; +: %cleanup ( n -- vop ) src-vop <%cleanup> ; VOP: %unbox -: %unbox ( [[ n func ]] -- vop ) literal-vop <%unbox> ; +: %unbox ( [[ n func ]] -- vop ) src-vop <%unbox> ; VOP: %unbox-float -: %unbox-float ( [[ n func ]] -- vop ) literal-vop <%unbox-float> ; +: %unbox-float ( [[ n func ]] -- vop ) src-vop <%unbox-float> ; VOP: %unbox-double -: %unbox-double ( [[ n func ]] -- vop ) literal-vop <%unbox-double> ; +: %unbox-double ( [[ n func ]] -- vop ) src-vop <%unbox-double> ; VOP: %box -: %box ( func -- vop ) literal-vop <%box> ; +: %box ( func -- vop ) src-vop <%box> ; VOP: %box-float -: %box-float ( func -- vop ) literal-vop <%box-float> ; +: %box-float ( func -- vop ) src-vop <%box-float> ; VOP: %box-double -: %box-double ( [[ n func ]] -- vop ) literal-vop <%box-double> ; +: %box-double ( [[ n func ]] -- vop ) src-vop <%box-double> ; VOP: %alien-invoke -: %alien-invoke ( func -- vop ) literal-vop <%alien-invoke> ; +: %alien-invoke ( func -- vop ) src-vop <%alien-invoke> ; VOP: %alien-global -: %alien-global ( global -- vop ) literal-vop <%alien-global> ; +: %alien-global ( global -- vop ) src-vop <%alien-global> ; diff --git a/library/compiler/x86/alien.factor b/library/compiler/x86/alien.factor index 6b44e27baf..b26661c1ff 100644 --- a/library/compiler/x86/alien.factor +++ b/library/compiler/x86/alien.factor @@ -6,10 +6,10 @@ kernel-internals lists math memory namespaces words ; M: %alien-invoke generate-node #! call a C function. - vop-literal uncons load-library compile-c-call ; + vop-in-1 uncons load-library compile-c-call ; M: %alien-global generate-node - vop-literal uncons load-library + vop-in-1 uncons load-library 2dup dlsym EAX swap unit MOV 0 0 rel-dlsym ; M: %parameters generate-node @@ -23,7 +23,7 @@ M: %parameter generate-node : UNBOX ( vop -- ) #! An unboxer function takes a value from the data stack and #! converts it into a C value. - vop-literal cdr f compile-c-call ; + vop-in-1 cdr f compile-c-call ; M: %unbox generate-node #! C functions return integers in EAX. @@ -49,7 +49,7 @@ M: %unbox-double generate-node #! A boxer function takes a C value as a parameter and #! converts into a Factor value, and pushes it on the data #! stack. - vop-literal f compile-c-call ; + vop-in-1 f compile-c-call ; M: %box generate-node #! C functions return integers in EAX. @@ -78,4 +78,4 @@ M: %cleanup generate-node #! In the cdecl ABI, the caller must pop input parameters #! off the C stack. In stdcall, the callee does it, so #! this node is not used in that case. - vop-literal dup 0 = [ drop ] [ ESP swap ADD ] ifte ; + vop-in-1 dup 0 = [ drop ] [ ESP swap ADD ] ifte ; diff --git a/library/compiler/x86/fixnum.factor b/library/compiler/x86/fixnum.factor index 214bb4ff7e..4029ca916b 100644 --- a/library/compiler/x86/fixnum.factor +++ b/library/compiler/x86/fixnum.factor @@ -112,7 +112,7 @@ M: %fixnum-bitxor generate-node ( vop -- ) dest/src XOR ; M: %fixnum-bitnot generate-node ( vop -- ) ! Negate the bits of the operand - vop-dest v>operand dup NOT + vop-out-1 v>operand dup NOT ! Mask off the low 3 bits to give a fixnum tag tag-mask XOR ; @@ -122,7 +122,7 @@ M: %fixnum<< generate-node