Merge branch 'master' of git://factorcode.org/git/factor

db4
Anton Gorenko 2010-09-27 15:25:02 +06:00
commit 0406bd9a31
10 changed files with 162 additions and 193 deletions

View File

@ -6,7 +6,6 @@ sets classes layouts fry locals cpu.architecture
compiler.cfg compiler.cfg
compiler.cfg.rpo compiler.cfg.rpo
compiler.cfg.def-use compiler.cfg.def-use
compiler.cfg.liveness
compiler.cfg.registers compiler.cfg.registers
compiler.cfg.utilities compiler.cfg.utilities
compiler.cfg.comparisons compiler.cfg.comparisons
@ -79,19 +78,23 @@ SYMBOL: copies
! Map vregs -> alias classes ! Map vregs -> alias classes
SYMBOL: vregs>acs SYMBOL: vregs>acs
ERROR: vreg-ac-not-set vreg ; ! Map alias classes -> sequence of vregs
SYMBOL: acs>vregs
! Alias class for objects which are loaded from the data stack
! or other object slots. We pessimistically assume that they
! can all alias each other.
SYMBOL: heap-ac
: ac>vregs ( ac -- vregs )
acs>vregs get [ drop V{ } clone ] cache ;
: vreg>ac ( vreg -- ac ) : vreg>ac ( vreg -- ac )
#! Only vregs produced by ##allot, ##peek and ##slot can #! Only vregs produced by ##allot, ##peek and ##slot can
#! ever be used as valid inputs to ##slot and ##set-slot, #! ever be used as valid inputs to ##slot and ##set-slot,
#! so we assert this fact by not giving alias classes to #! so we assert this fact by not giving alias classes to
#! other vregs. #! other vregs.
vregs>acs get ?at [ vreg-ac-not-set ] unless ; vregs>acs get [ heap-ac get [ ac>vregs push ] keep ] cache ;
! Map alias classes -> sequence of vregs
SYMBOL: acs>vregs
: ac>vregs ( ac -- vregs ) acs>vregs get at ;
: aliases ( vreg -- vregs ) : aliases ( vreg -- vregs )
#! All vregs which may contain the same value as vreg. #! All vregs which may contain the same value as vreg.
@ -120,10 +123,11 @@ SYMBOL: dead-stores
: dead-store ( insn# -- ) dead-stores get adjoin ; : dead-store ( insn# -- ) dead-stores get adjoin ;
ERROR: vreg-not-new vreg ;
:: set-ac ( vreg ac -- ) :: set-ac ( vreg ac -- )
#! Set alias class of newly-seen vreg. #! Set alias class of newly-seen vreg.
H{ } clone vreg recent-stores get set-at vreg vregs>acs get key? [ vreg vreg-not-new ] when
H{ } clone vreg live-slots get set-at
ac vreg vregs>acs get set-at ac vreg vregs>acs get set-at
vreg ac acs>vregs get push-at ; vreg ac acs>vregs get push-at ;
@ -132,10 +136,8 @@ SYMBOL: dead-stores
#! value. #! value.
over [ live-slots get at at ] [ 2drop f ] if ; over [ live-slots get at at ] [ 2drop f ] if ;
ERROR: vreg-has-no-slots vreg ;
: load-constant-slot ( value slot# vreg -- ) : load-constant-slot ( value slot# vreg -- )
live-slots get ?at [ vreg-has-no-slots ] unless set-at ; live-slots get [ drop H{ } clone ] cache set-at ;
: load-slot ( value slot#/f vreg -- ) : load-slot ( value slot#/f vreg -- )
over [ load-constant-slot ] [ 3drop ] if ; over [ load-constant-slot ] [ 3drop ] if ;
@ -160,20 +162,16 @@ SYMBOL: ac-counter
: next-ac ( -- n ) : next-ac ( -- n )
ac-counter [ dup 1 + ] change ; ac-counter [ dup 1 + ] change ;
! Alias class for objects which are loaded from the data stack
! or other object slots. We pessimistically assume that they
! can all alias each other.
SYMBOL: heap-ac
: set-heap-ac ( vreg -- ) heap-ac get set-ac ;
: set-new-ac ( vreg -- ) next-ac set-ac ; : set-new-ac ( vreg -- ) next-ac set-ac ;
: kill-constant-set-slot ( slot# vreg -- ) : kill-constant-set-slot ( slot# vreg -- )
[ live-slots get at delete-at ] with each-alias ; [ live-slots get at delete-at ] with each-alias ;
: recent-stores-of ( vreg -- assoc )
recent-stores get [ drop H{ } clone ] cache ;
:: record-constant-set-slot ( insn# slot# vreg -- ) :: record-constant-set-slot ( insn# slot# vreg -- )
vreg recent-stores get at :> recent-stores vreg recent-stores-of :> recent-stores
slot# recent-stores at [ dead-store ] when* slot# recent-stores at [ dead-store ] when*
insn# slot# recent-stores set-at ; insn# slot# recent-stores set-at ;
@ -226,15 +224,12 @@ M: insn analyze-aliases ;
! inserted yet. ! inserted yet.
dup [ dup [
{ int-rep tagged-rep } member? { int-rep tagged-rep } member?
[ set-heap-ac ] [ set-new-ac ] if [ drop ] [ set-new-ac ] if
] each-def-rep ; ] each-def-rep ;
M: vreg-insn analyze-aliases M: vreg-insn analyze-aliases
def-acs ; def-acs ;
M: ##phi analyze-aliases
dup dst>> set-heap-ac ;
M: ##allocation analyze-aliases M: ##allocation analyze-aliases
#! A freshly allocated object is distinct from any other #! A freshly allocated object is distinct from any other
#! object. #! object.
@ -326,9 +321,8 @@ M: insn eliminate-dead-stores drop t ;
: alias-analysis-step ( insns -- insns' ) : alias-analysis-step ( insns -- insns' )
reset-alias-analysis reset-alias-analysis
[ local-live-in [ set-heap-ac ] each ]
[ 0 [ [ insn#<< ] [ drop 1 + ] 2bi ] reduce drop ] [ 0 [ [ insn#<< ] [ drop 1 + ] 2bi ] reduce drop ]
[ [ analyze-aliases ] map! [ eliminate-dead-stores ] filter! ] tri ; [ [ analyze-aliases ] map! [ eliminate-dead-stores ] filter! ] bi ;
: alias-analysis ( cfg -- cfg ) : alias-analysis ( cfg -- cfg )
init-alias-analysis init-alias-analysis

View File

@ -6,7 +6,6 @@ cpu.architecture layouts
compiler.cfg compiler.cfg
compiler.cfg.def-use compiler.cfg.def-use
compiler.cfg.liveness compiler.cfg.liveness
compiler.cfg.liveness.ssa
compiler.cfg.registers compiler.cfg.registers
compiler.cfg.instructions compiler.cfg.instructions
compiler.cfg.linearization compiler.cfg.linearization

View File

@ -1,19 +1,15 @@
USING: compiler.cfg.liveness compiler.cfg.liveness.ssa USING: compiler.cfg.liveness
compiler.cfg.debugger compiler.cfg.instructions compiler.cfg.debugger compiler.cfg.instructions
compiler.cfg.predecessors compiler.cfg.registers compiler.cfg compiler.cfg.predecessors compiler.cfg.registers compiler.cfg
cpu.architecture accessors namespaces sequences kernel cpu.architecture accessors namespaces sequences kernel
tools.test vectors alien math compiler.cfg.comparisons tools.test vectors alien math compiler.cfg.comparisons
cpu.x86.assembler.operands ; cpu.x86.assembler.operands assocs ;
IN: compiler.cfg.liveness.tests IN: compiler.cfg.liveness.tests
: test-liveness ( -- ) : test-liveness ( -- )
cfg new 1 get >>entry cfg new 1 get >>entry
compute-live-sets ; compute-live-sets ;
: test-ssa-liveness ( -- )
cfg new 1 get >>entry
compute-ssa-live-sets ;
! Sanity check... ! Sanity check...
V{ V{
@ -148,9 +144,65 @@ V{
7 8 edge 7 8 edge
8 9 edge 8 9 edge
[ ] [ test-ssa-liveness ] unit-test [ ] [ test-liveness ] unit-test
[ H{ { 28 28 } { 29 29 } { 30 30 } { 31 31 } } ] [ 5 get live-out ] unit-test [ H{ { 28 28 } { 29 29 } { 30 30 } { 31 31 } } ] [ 5 get live-out ] unit-test
[ H{ { 28 28 } { 29 29 } { 30 30 } } ] [ 6 get live-in ] unit-test [ H{ { 28 28 } { 29 29 } { 30 30 } } ] [ 6 get live-in ] unit-test
[ H{ { 28 28 } { 29 29 } { 31 31 } } ] [ 7 get live-in ] unit-test [ H{ { 28 28 } { 29 29 } { 31 31 } } ] [ 7 get live-in ] unit-test
[ H{ { 30 30 } } ] [ 6 get 8 get edge-live-in ] unit-test [ H{ { 30 30 } } ] [ 6 get 8 get edge-live-in ] unit-test
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##branch }
} 1 test-bb
V{
T{ ##load-integer f 0 0 }
T{ ##branch }
} 2 test-bb
V{
T{ ##load-integer f 1 1 }
T{ ##branch }
} 3 test-bb
V{
T{ ##phi f 2 H{ { 2 0 } { 3 1 } } }
T{ ##branch }
} 4 test-bb
V{
T{ ##branch }
} 5 test-bb
V{
T{ ##replace f 2 D 0 }
T{ ##branch }
} 6 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 7 test-bb
0 1 edge
1 { 2 3 } edges
2 4 edge
3 4 edge
4 { 5 6 } edges
5 6 edge
6 7 edge
[ ] [ cfg new 0 get >>entry dup cfg set compute-live-sets ] unit-test
[ t ] [ 0 get live-in assoc-empty? ] unit-test
[ H{ { 2 2 } } ] [ 4 get live-out ] unit-test
[ H{ { 0 0 } } ] [ 2 get 4 get edge-live-in ] unit-test
[ H{ { 1 1 } } ] [ 3 get 4 get edge-live-in ] unit-test

View File

@ -1,17 +1,31 @@
! Copyright (C) 2009, 2010 Slava Pestov. ! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors assocs namespaces sequences sets USING: kernel accessors assocs fry deques dlists namespaces
compiler.cfg.def-use compiler.cfg.dataflow-analysis sequences sets compiler.cfg compiler.cfg.def-use
compiler.cfg.instructions compiler.cfg.registers compiler.cfg.instructions compiler.cfg.registers
cpu.architecture ; compiler.cfg.utilities compiler.cfg.predecessors
compiler.cfg.rpo cpu.architecture ;
FROM: namespaces => set ;
IN: compiler.cfg.liveness IN: compiler.cfg.liveness
! See http://en.wikipedia.org/wiki/Liveness_analysis ! See http://en.wikipedia.org/wiki/Liveness_analysis
! Do not run after SSA construction; compiler.cfg.liveness.ssa
! should be used instead. The transfer-liveness word is used
! by SSA liveness too, so it handles ##phi instructions.
BACKWARD-ANALYSIS: live SYMBOL: live-ins
: live-in ( bb -- set )
live-ins get at ;
SYMBOL: live-outs
: live-out ( bb -- set )
live-outs get at ;
! Assoc mapping basic blocks to sequences of sets of vregs; each
! sequence is in correspondence with a predecessor
SYMBOL: edge-live-ins
: edge-live-in ( predecessor basic-block -- set )
edge-live-ins get at at ;
GENERIC: visit-insn ( live-set insn -- live-set ) GENERIC: visit-insn ( live-set insn -- live-set )
@ -23,6 +37,11 @@ GENERIC: visit-insn ( live-set insn -- live-set )
M: vreg-insn visit-insn [ kill-defs ] [ gen-uses ] bi ; M: vreg-insn visit-insn [ kill-defs ] [ gen-uses ] bi ;
! Our liveness analysis annotates call sites with GC maps
! indicating the spill slots in the stack frame that contain
! tagged pointers, and thus have to be visited if a GC occurs
! inside the call.
: fill-gc-map ( live-set insn -- live-set ) : fill-gc-map ( live-set insn -- live-set )
representations get [ representations get [
gc-map>> over keys gc-map>> over keys
@ -44,8 +63,49 @@ M: insn visit-insn drop ;
: local-live-in ( instructions -- live-set ) : local-live-in ( instructions -- live-set )
[ H{ } ] dip transfer-liveness keys ; [ H{ } ] dip transfer-liveness keys ;
M: live-analysis transfer-set SYMBOL: work-list
drop instructions>> transfer-liveness ;
M: live-analysis join-sets : add-to-work-list ( basic-blocks -- )
2drop assoc-combine ; work-list get '[ _ push-front ] each ;
: compute-live-in ( basic-block -- live-in )
[ live-out ] keep instructions>> transfer-liveness ;
: compute-edge-live-in ( basic-block -- edge-live-in )
H{ } clone [
'[ inputs>> [ swap _ conjoin-at ] assoc-each ] each-phi
] keep ;
: update-live-in ( basic-block -- changed? )
[ [ compute-live-in ] keep live-ins get maybe-set-at ]
[ [ compute-edge-live-in ] keep edge-live-ins get maybe-set-at ]
bi or ;
: compute-live-out ( basic-block -- live-out )
[ successors>> [ live-in ] map ]
[ dup successors>> [ edge-live-in ] with map ] bi
append assoc-combine ;
: update-live-out ( basic-block -- changed? )
[ compute-live-out ] keep
live-outs get maybe-set-at ;
: liveness-step ( basic-block -- )
dup update-live-out [
dup update-live-in
[ predecessors>> add-to-work-list ] [ drop ] if
] [ drop ] if ;
: compute-live-sets ( cfg -- )
needs-predecessors
<hashed-dlist> work-list set
H{ } clone live-ins set
H{ } clone edge-live-ins set
H{ } clone live-outs set
post-order add-to-work-list
work-list get [ liveness-step ] slurp-deque ;
: live-in? ( vreg bb -- ? ) live-in key? ;
: live-out? ( vreg bb -- ? ) live-out key? ;

View File

@ -1,61 +0,0 @@
USING: accessors compiler.cfg compiler.cfg.debugger
compiler.cfg.instructions compiler.cfg.liveness.ssa
compiler.cfg.liveness arrays sequences assocs
compiler.cfg.registers kernel namespaces tools.test ;
IN: compiler.cfg.liveness.ssa.tests
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##branch }
} 1 test-bb
V{
T{ ##load-integer f 0 0 }
T{ ##branch }
} 2 test-bb
V{
T{ ##load-integer f 1 1 }
T{ ##branch }
} 3 test-bb
V{
T{ ##phi f 2 H{ { 2 0 } { 3 1 } } }
T{ ##branch }
} 4 test-bb
V{
T{ ##branch }
} 5 test-bb
V{
T{ ##replace f 2 D 0 }
T{ ##branch }
} 6 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 7 test-bb
0 1 edge
1 { 2 3 } edges
2 4 edge
3 4 edge
4 { 5 6 } edges
5 6 edge
6 7 edge
[ ] [ cfg new 0 get >>entry dup cfg set compute-ssa-live-sets ] unit-test
[ t ] [ 0 get live-in assoc-empty? ] unit-test
[ H{ { 2 2 } } ] [ 4 get live-out ] unit-test
[ H{ { 0 0 } } ] [ 2 get 4 get edge-live-in ] unit-test
[ H{ { 1 1 } } ] [ 3 get 4 get edge-live-in ] unit-test

View File

@ -1,63 +0,0 @@
! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel namespaces deques accessors sets sequences assocs fry
hashtables dlists compiler.cfg.def-use compiler.cfg.instructions
compiler.cfg.rpo compiler.cfg.liveness compiler.cfg.utilities
compiler.cfg.predecessors ;
FROM: namespaces => set ;
IN: compiler.cfg.liveness.ssa
! TODO: merge with compiler.cfg.liveness
! Assoc mapping basic blocks to sequences of sets of vregs; each sequence
! is in correspondence with a predecessor
SYMBOL: edge-live-ins
: edge-live-in ( predecessor basic-block -- set ) edge-live-ins get at at ;
SYMBOL: work-list
: add-to-work-list ( basic-blocks -- )
work-list get '[ _ push-front ] each ;
: compute-live-in ( basic-block -- live-in )
[ live-out ] keep instructions>> transfer-liveness ;
: compute-edge-live-in ( basic-block -- edge-live-in )
H{ } clone [
'[ inputs>> [ swap _ conjoin-at ] assoc-each ] each-phi
] keep ;
: update-live-in ( basic-block -- changed? )
[ [ compute-live-in ] keep live-ins get maybe-set-at ]
[ [ compute-edge-live-in ] keep edge-live-ins get maybe-set-at ]
bi or ;
: compute-live-out ( basic-block -- live-out )
[ successors>> [ live-in ] map ]
[ dup successors>> [ edge-live-in ] with map ] bi
append assoc-combine ;
: update-live-out ( basic-block -- changed? )
[ compute-live-out ] keep
live-outs get maybe-set-at ;
: liveness-step ( basic-block -- )
dup update-live-out [
dup update-live-in
[ predecessors>> add-to-work-list ] [ drop ] if
] [ drop ] if ;
: compute-ssa-live-sets ( cfg -- )
needs-predecessors
<hashed-dlist> work-list set
H{ } clone live-ins set
H{ } clone edge-live-ins set
H{ } clone live-outs set
post-order add-to-work-list
work-list get [ liveness-step ] slurp-deque ;
: live-in? ( vreg bb -- ? ) live-in key? ;
: live-out? ( vreg bb -- ? ) live-out key? ;

View File

@ -3,8 +3,7 @@
USING: accessors arrays assocs fry kernel locals make math USING: accessors arrays assocs fry kernel locals make math
namespaces sequences sets combinators.short-circuit namespaces sequences sets combinators.short-circuit
compiler.cfg.def-use compiler.cfg.dependence compiler.cfg.def-use compiler.cfg.dependence
compiler.cfg.instructions compiler.cfg.liveness compiler.cfg.rpo compiler.cfg.instructions compiler.cfg.rpo cpu.architecture ;
cpu.architecture ;
IN: compiler.cfg.scheduling IN: compiler.cfg.scheduling
! Instruction scheduling to reduce register pressure, from: ! Instruction scheduling to reduce register pressure, from:
@ -130,18 +129,7 @@ ERROR: definition-after-usage vregs old-bb new-bb ;
] change-instructions drop ] change-instructions drop
] with-scheduling-check ; ] with-scheduling-check ;
! Really, instruction scheduling should be aware that there are
! multiple types of registers, but this number is just used
! to decide whether to schedule instructions
: num-registers ( -- x ) int-regs machine-registers at length ;
: might-spill? ( bb -- ? )
[ live-in assoc-size ]
[ instructions>> [ defs-vregs length ] map-sum ] bi
+ num-registers >= ;
: schedule-instructions ( cfg -- cfg' ) : schedule-instructions ( cfg -- cfg' )
dup [ dup [
dup { [ kill-block?>> not ] [ might-spill? ] } 1&& dup kill-block?>> [ drop ] [ schedule-block ] if
[ schedule-block ] [ drop ] if
] each-basic-block ; ] each-basic-block ;

View File

@ -9,7 +9,7 @@ compiler.cfg.def-use
compiler.cfg.registers compiler.cfg.registers
compiler.cfg.dominance compiler.cfg.dominance
compiler.cfg.instructions compiler.cfg.instructions
compiler.cfg.liveness.ssa compiler.cfg.liveness
compiler.cfg.ssa.cssa compiler.cfg.ssa.cssa
compiler.cfg.ssa.interference compiler.cfg.ssa.interference
compiler.cfg.ssa.interference.live-ranges compiler.cfg.ssa.interference.live-ranges
@ -28,9 +28,9 @@ IN: compiler.cfg.ssa.destruction
! 2) Useless ##copy instructions, and all ##phi instructions, ! 2) Useless ##copy instructions, and all ##phi instructions,
! are eliminated, so the register allocator does not have to ! are eliminated, so the register allocator does not have to
! remove any redundant operations. ! remove any redundant operations.
! 3) A side effect of running this pass is that SSA liveness ! 3) This pass computes live sets and fills out GC maps with
! information is computed, so the register allocator does not ! compiler.cfg.liveness, so the linear scan register allocator
! need to compute it again. ! does not need to compute liveness again.
SYMBOL: leader-map SYMBOL: leader-map
@ -134,7 +134,7 @@ PRIVATE>
dup construct-cssa dup construct-cssa
dup compute-defs dup compute-defs
dup compute-insns dup compute-insns
dup compute-ssa-live-sets dup compute-live-sets
dup compute-live-ranges dup compute-live-ranges
dup prepare-coalescing dup prepare-coalescing
process-copies process-copies

View File

@ -1,6 +1,6 @@
USING: accessors compiler.cfg compiler.cfg.debugger USING: accessors compiler.cfg compiler.cfg.debugger
compiler.cfg.def-use compiler.cfg.dominance compiler.cfg.def-use compiler.cfg.dominance
compiler.cfg.instructions compiler.cfg.liveness.ssa compiler.cfg.instructions compiler.cfg.liveness
compiler.cfg.registers compiler.cfg.predecessors compiler.cfg.registers compiler.cfg.predecessors
compiler.cfg.comparisons compiler.cfg.ssa.interference compiler.cfg.comparisons compiler.cfg.ssa.interference
compiler.cfg.ssa.interference.private compiler.cfg.ssa.interference.private
@ -11,7 +11,7 @@ IN: compiler.cfg.ssa.interference.tests
: test-interference ( -- ) : test-interference ( -- )
cfg new 0 get >>entry cfg new 0 get >>entry
dup compute-ssa-live-sets dup compute-live-sets
dup compute-defs dup compute-defs
dup compute-insns dup compute-insns
compute-live-ranges ; compute-live-ranges ;

View File

@ -2,7 +2,7 @@
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs fry kernel namespaces sequences math USING: accessors assocs fry kernel namespaces sequences math
arrays compiler.cfg.def-use compiler.cfg.instructions arrays compiler.cfg.def-use compiler.cfg.instructions
compiler.cfg.liveness.ssa compiler.cfg.rpo compiler.cfg.liveness compiler.cfg.rpo
compiler.cfg.dominance compiler.cfg ; compiler.cfg.dominance compiler.cfg ;
IN: compiler.cfg.ssa.interference.live-ranges IN: compiler.cfg.ssa.interference.live-ranges