Merge branch 'master' of git://factorcode.org/git/factor
commit
0406bd9a31
|
@ -6,7 +6,6 @@ sets classes layouts fry locals cpu.architecture
|
|||
compiler.cfg
|
||||
compiler.cfg.rpo
|
||||
compiler.cfg.def-use
|
||||
compiler.cfg.liveness
|
||||
compiler.cfg.registers
|
||||
compiler.cfg.utilities
|
||||
compiler.cfg.comparisons
|
||||
|
@ -79,19 +78,23 @@ SYMBOL: copies
|
|||
! Map vregs -> alias classes
|
||||
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 )
|
||||
#! Only vregs produced by ##allot, ##peek and ##slot can
|
||||
#! ever be used as valid inputs to ##slot and ##set-slot,
|
||||
#! so we assert this fact by not giving alias classes to
|
||||
#! other vregs.
|
||||
vregs>acs get ?at [ vreg-ac-not-set ] unless ;
|
||||
|
||||
! Map alias classes -> sequence of vregs
|
||||
SYMBOL: acs>vregs
|
||||
|
||||
: ac>vregs ( ac -- vregs ) acs>vregs get at ;
|
||||
vregs>acs get [ heap-ac get [ ac>vregs push ] keep ] cache ;
|
||||
|
||||
: aliases ( vreg -- vregs )
|
||||
#! All vregs which may contain the same value as vreg.
|
||||
|
@ -120,10 +123,11 @@ SYMBOL: dead-stores
|
|||
|
||||
: dead-store ( insn# -- ) dead-stores get adjoin ;
|
||||
|
||||
ERROR: vreg-not-new vreg ;
|
||||
|
||||
:: set-ac ( vreg ac -- )
|
||||
#! Set alias class of newly-seen vreg.
|
||||
H{ } clone vreg recent-stores get set-at
|
||||
H{ } clone vreg live-slots get set-at
|
||||
vreg vregs>acs get key? [ vreg vreg-not-new ] when
|
||||
ac vreg vregs>acs get set-at
|
||||
vreg ac acs>vregs get push-at ;
|
||||
|
||||
|
@ -132,10 +136,8 @@ SYMBOL: dead-stores
|
|||
#! value.
|
||||
over [ live-slots get at at ] [ 2drop f ] if ;
|
||||
|
||||
ERROR: vreg-has-no-slots 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 -- )
|
||||
over [ load-constant-slot ] [ 3drop ] if ;
|
||||
|
@ -160,20 +162,16 @@ SYMBOL: ac-counter
|
|||
: next-ac ( -- n )
|
||||
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 ;
|
||||
|
||||
: kill-constant-set-slot ( slot# vreg -- )
|
||||
[ 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 -- )
|
||||
vreg recent-stores get at :> recent-stores
|
||||
vreg recent-stores-of :> recent-stores
|
||||
slot# recent-stores at [ dead-store ] when*
|
||||
insn# slot# recent-stores set-at ;
|
||||
|
||||
|
@ -226,15 +224,12 @@ M: insn analyze-aliases ;
|
|||
! inserted yet.
|
||||
dup [
|
||||
{ int-rep tagged-rep } member?
|
||||
[ set-heap-ac ] [ set-new-ac ] if
|
||||
[ drop ] [ set-new-ac ] if
|
||||
] each-def-rep ;
|
||||
|
||||
M: vreg-insn analyze-aliases
|
||||
def-acs ;
|
||||
|
||||
M: ##phi analyze-aliases
|
||||
dup dst>> set-heap-ac ;
|
||||
|
||||
M: ##allocation analyze-aliases
|
||||
#! A freshly allocated object is distinct from any other
|
||||
#! object.
|
||||
|
@ -326,9 +321,8 @@ M: insn eliminate-dead-stores drop t ;
|
|||
|
||||
: alias-analysis-step ( insns -- insns' )
|
||||
reset-alias-analysis
|
||||
[ local-live-in [ set-heap-ac ] each ]
|
||||
[ 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 )
|
||||
init-alias-analysis
|
||||
|
|
|
@ -6,7 +6,6 @@ cpu.architecture layouts
|
|||
compiler.cfg
|
||||
compiler.cfg.def-use
|
||||
compiler.cfg.liveness
|
||||
compiler.cfg.liveness.ssa
|
||||
compiler.cfg.registers
|
||||
compiler.cfg.instructions
|
||||
compiler.cfg.linearization
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
USING: compiler.cfg.liveness compiler.cfg.liveness.ssa
|
||||
USING: compiler.cfg.liveness
|
||||
compiler.cfg.debugger compiler.cfg.instructions
|
||||
compiler.cfg.predecessors compiler.cfg.registers compiler.cfg
|
||||
cpu.architecture accessors namespaces sequences kernel
|
||||
tools.test vectors alien math compiler.cfg.comparisons
|
||||
cpu.x86.assembler.operands ;
|
||||
cpu.x86.assembler.operands assocs ;
|
||||
IN: compiler.cfg.liveness.tests
|
||||
|
||||
: test-liveness ( -- )
|
||||
cfg new 1 get >>entry
|
||||
compute-live-sets ;
|
||||
|
||||
: test-ssa-liveness ( -- )
|
||||
cfg new 1 get >>entry
|
||||
compute-ssa-live-sets ;
|
||||
|
||||
! Sanity check...
|
||||
|
||||
V{
|
||||
|
@ -148,9 +144,65 @@ V{
|
|||
7 8 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 } } ] [ 6 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
|
|
@ -1,17 +1,31 @@
|
|||
! Copyright (C) 2009, 2010 Slava Pestov.
|
||||
! See http://factorcode.org/license.txt for BSD license.
|
||||
USING: kernel accessors assocs namespaces sequences sets
|
||||
compiler.cfg.def-use compiler.cfg.dataflow-analysis
|
||||
USING: kernel accessors assocs fry deques dlists namespaces
|
||||
sequences sets compiler.cfg compiler.cfg.def-use
|
||||
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
|
||||
|
||||
! 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 )
|
||||
|
||||
|
@ -23,6 +37,11 @@ GENERIC: visit-insn ( live-set insn -- live-set )
|
|||
|
||||
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 )
|
||||
representations get [
|
||||
gc-map>> over keys
|
||||
|
@ -44,8 +63,49 @@ M: insn visit-insn drop ;
|
|||
: local-live-in ( instructions -- live-set )
|
||||
[ H{ } ] dip transfer-liveness keys ;
|
||||
|
||||
M: live-analysis transfer-set
|
||||
drop instructions>> transfer-liveness ;
|
||||
SYMBOL: work-list
|
||||
|
||||
M: live-analysis join-sets
|
||||
2drop assoc-combine ;
|
||||
: 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-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? ;
|
||||
|
|
|
@ -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
|
|
@ -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? ;
|
|
@ -3,8 +3,7 @@
|
|||
USING: accessors arrays assocs fry kernel locals make math
|
||||
namespaces sequences sets combinators.short-circuit
|
||||
compiler.cfg.def-use compiler.cfg.dependence
|
||||
compiler.cfg.instructions compiler.cfg.liveness compiler.cfg.rpo
|
||||
cpu.architecture ;
|
||||
compiler.cfg.instructions compiler.cfg.rpo cpu.architecture ;
|
||||
IN: compiler.cfg.scheduling
|
||||
|
||||
! Instruction scheduling to reduce register pressure, from:
|
||||
|
@ -130,18 +129,7 @@ ERROR: definition-after-usage vregs old-bb new-bb ;
|
|||
] change-instructions drop
|
||||
] 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' )
|
||||
dup [
|
||||
dup { [ kill-block?>> not ] [ might-spill? ] } 1&&
|
||||
[ schedule-block ] [ drop ] if
|
||||
dup kill-block?>> [ drop ] [ schedule-block ] if
|
||||
] each-basic-block ;
|
||||
|
|
|
@ -9,7 +9,7 @@ compiler.cfg.def-use
|
|||
compiler.cfg.registers
|
||||
compiler.cfg.dominance
|
||||
compiler.cfg.instructions
|
||||
compiler.cfg.liveness.ssa
|
||||
compiler.cfg.liveness
|
||||
compiler.cfg.ssa.cssa
|
||||
compiler.cfg.ssa.interference
|
||||
compiler.cfg.ssa.interference.live-ranges
|
||||
|
@ -28,9 +28,9 @@ IN: compiler.cfg.ssa.destruction
|
|||
! 2) Useless ##copy instructions, and all ##phi instructions,
|
||||
! are eliminated, so the register allocator does not have to
|
||||
! remove any redundant operations.
|
||||
! 3) A side effect of running this pass is that SSA liveness
|
||||
! information is computed, so the register allocator does not
|
||||
! need to compute it again.
|
||||
! 3) This pass computes live sets and fills out GC maps with
|
||||
! compiler.cfg.liveness, so the linear scan register allocator
|
||||
! does not need to compute liveness again.
|
||||
|
||||
SYMBOL: leader-map
|
||||
|
||||
|
@ -134,7 +134,7 @@ PRIVATE>
|
|||
dup construct-cssa
|
||||
dup compute-defs
|
||||
dup compute-insns
|
||||
dup compute-ssa-live-sets
|
||||
dup compute-live-sets
|
||||
dup compute-live-ranges
|
||||
dup prepare-coalescing
|
||||
process-copies
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
USING: accessors compiler.cfg compiler.cfg.debugger
|
||||
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.comparisons compiler.cfg.ssa.interference
|
||||
compiler.cfg.ssa.interference.private
|
||||
|
@ -11,7 +11,7 @@ IN: compiler.cfg.ssa.interference.tests
|
|||
|
||||
: test-interference ( -- )
|
||||
cfg new 0 get >>entry
|
||||
dup compute-ssa-live-sets
|
||||
dup compute-live-sets
|
||||
dup compute-defs
|
||||
dup compute-insns
|
||||
compute-live-ranges ;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
! See http://factorcode.org/license.txt for BSD license.
|
||||
USING: accessors assocs fry kernel namespaces sequences math
|
||||
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 ;
|
||||
IN: compiler.cfg.ssa.interference.live-ranges
|
||||
|
||||
|
|
Loading…
Reference in New Issue