USING: accessors assocs heaps kernel namespaces sequences fry math
math.order combinators arrays sorting compiler.utilities
compiler.cfg.linear-scan.live-intervals
-compiler.cfg.linear-scan.allocation.coalescing
compiler.cfg.linear-scan.allocation.spilling
compiler.cfg.linear-scan.allocation.splitting
compiler.cfg.linear-scan.allocation.state ;
second 0 = ; inline
: assign-register ( new -- )
- dup coalesce? [ coalesce ] [
- dup register-status {
- { [ dup no-free-registers? ] [ drop assign-blocked-register ] }
- { [ 2dup register-available? ] [ register-available ] }
- [ drop assign-blocked-register ]
- } cond
- ] if ;
+ dup register-status {
+ { [ dup no-free-registers? ] [ drop assign-blocked-register ] }
+ { [ 2dup register-available? ] [ register-available ] }
+ [ drop assign-blocked-register ]
+ } cond ;
: handle-interval ( live-interval -- )
[
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel sequences namespaces assocs fry
-combinators.short-circuit
-compiler.cfg.linear-scan.live-intervals
-compiler.cfg.linear-scan.allocation.state ;
-IN: compiler.cfg.linear-scan.allocation.coalescing
-
-: active-interval ( vreg -- live-interval )
- dup [ dup active-intervals-for [ vreg>> = ] with find nip ] when ;
-
-: avoids-inactive-intervals? ( live-interval -- ? )
- dup vreg>> inactive-intervals-for
- [ intervals-intersect? not ] with all? ;
-
-: coalesce? ( live-interval -- ? )
- {
- [ copy-from>> active-interval ]
- [ [ start>> ] [ copy-from>> active-interval end>> ] bi = ]
- [ avoids-inactive-intervals? ]
- } 1&& ;
-
-: reuse-spill-slot ( old new -- )
- [ vreg>> spill-slots get at ] dip '[ _ vreg>> spill-slots get set-at ] when* ;
-
-: reuse-register ( old new -- )
- reg>> >>reg drop ;
-
-: (coalesce) ( old new -- )
- [ add-active ] [ [ delete-active ] [ add-handled ] bi ] bi* ;
-
-: coalesce ( live-interval -- )
- dup copy-from>> active-interval
- [ reuse-spill-slot ] [ reuse-register ] [ (coalesce) ] 2tri ;
-
\ No newline at end of file
f >>spill-to ; inline
: split-after ( after -- after' )
- f >>copy-from f >>reg f >>reload-from ; inline
+ f >>reg f >>reload-from ; inline
:: split-interval ( live-interval n -- before after )
live-interval n check-split
: interval-picture ( interval -- str )
[ uses>> picture ]
- [ copy-from>> unparse ]
[ vreg>> unparse ]
- tri 3array ;
+ bi 2array ;
: live-intervals. ( seq -- )
[ interval-picture ] map simple-table. ;
clone dup [ start>> ] [ end>> ] bi <live-range> 1vector >>ranges
] map ;
-! Coalescing interacted badly with splitting
[ ] [
{
T{ live-interval
{ start 14 }
{ end 17 }
{ uses V{ 14 15 16 17 } }
- { copy-from V int-regs 67 }
}
T{ live-interval
{ vreg V int-regs 67 }
{ start 10 }
{ end 18 }
{ uses V{ 10 11 12 18 } }
- { copy-from V int-regs 56 }
}
T{ live-interval
{ vreg V int-regs 60 }
{ start 44 }
{ end 56 }
{ uses V{ 44 45 45 46 56 } }
- { copy-from V int-regs 3686445 }
}
T{ live-interval
{ vreg V int-regs 3686198 }
{ start 46 }
{ end 49 }
{ uses V{ 46 47 47 49 } }
- { copy-from V int-regs 3686449 }
}
T{ live-interval
{ vreg V int-regs 3686196 }
{ start 49 }
{ end 52 }
{ uses V{ 49 50 50 52 } }
- { copy-from V int-regs 3686454 }
}
T{ live-interval
{ vreg V int-regs 3686461 }
{ start 54 }
{ end 76 }
{ uses V{ 54 55 55 76 } }
- { copy-from V int-regs 3686464 }
}
T{ live-interval
{ vreg V int-regs 3686470 }
{ start 58 }
{ end 60 }
{ uses V{ 58 59 59 60 } }
- { copy-from V int-regs 3686469 }
}
T{ live-interval
{ vreg V int-regs 3686469 }
{ start 56 }
{ end 58 }
{ uses V{ 56 57 57 58 } }
- { copy-from V int-regs 3686449 }
}
T{ live-interval
{ vreg V int-regs 3686473 }
{ start 60 }
{ end 62 }
{ uses V{ 60 61 61 62 } }
- { copy-from V int-regs 3686470 }
}
T{ live-interval
{ vreg V int-regs 3686479 }
{ start 62 }
{ end 64 }
{ uses V{ 62 63 63 64 } }
- { copy-from V int-regs 3686473 }
}
T{ live-interval
{ vreg V int-regs 3686735 }
{ start 78 }
{ end 96 }
{ uses V{ 78 79 79 96 } }
- { copy-from V int-regs 3686372 }
}
T{ live-interval
{ vreg V int-regs 3686482 }
{ start 66 }
{ end 75 }
{ uses V{ 66 67 67 75 } }
- { copy-from V int-regs 3686483 }
}
T{ live-interval
{ vreg V int-regs 3687509 }
{ start 69 }
{ end 74 }
{ uses V{ 69 70 70 74 } }
- { copy-from V int-regs 3686491 }
}
T{ live-interval
{ vreg V int-regs 3687778 }
{ start 72 }
{ end 74 }
{ uses V{ 72 73 73 74 } }
- { copy-from V int-regs 3686499 }
}
T{ live-interval
{ vreg V int-regs 3687780 }
{ start 27 }
{ end 30 }
{ uses V{ 27 28 28 30 } }
- { copy-from V int-regs 3686300 }
}
T{ live-interval
{ vreg V int-regs 3686306 }
{ start 243 }
{ end 245 }
{ uses V{ 243 244 244 245 } }
- { copy-from V int-regs 3687845 }
}
T{ live-interval
{ vreg V int-regs 3687850 }
{ start 141 }
{ end 143 }
{ uses V{ 141 142 142 143 } }
- { copy-from V int-regs 3687377 }
}
T{ live-interval
{ vreg V int-regs 3687381 }
{ start 293 }
{ end 295 }
{ uses V{ 293 294 294 295 } }
- { copy-from V int-regs 3687087 }
}
T{ live-interval
{ vreg V int-regs 3687403 }
{ start 78 }
{ end 96 }
{ uses V{ 78 79 96 } }
- { copy-from V int-regs 6372 }
}
T{ live-interval
{ vreg V int-regs 6483 }
TUPLE: live-interval
vreg
reg spill-to reload-from
-start end ranges uses
-copy-from ;
+start end ranges uses ;
GENERIC: covers? ( insn# obj -- ? )
[ [ temp-vregs ] 2dip '[ [ _ ] dip _ handle-temp ] each ]
3tri ;
-: record-copy ( insn -- )
- [ dst>> live-intervals get at ] [ src>> ] bi >>copy-from drop ;
-
-M: ##copy compute-live-intervals*
- [ call-next-method ] [ record-copy ] bi ;
-
-M: ##copy-float compute-live-intervals*
- [ call-next-method ] [ record-copy ] bi ;
-
: handle-live-out ( bb -- )
live-out keys
basic-block get [ block-from ] [ block-to ] bi
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: compiler.cfg.linearization compiler.cfg.two-operand
-compiler.cfg.gc-checks compiler.cfg.linear-scan
-compiler.cfg.build-stack-frame compiler.cfg.rpo ;
+USING: compiler.cfg.linearization compiler.cfg.gc-checks
+compiler.cfg.linear-scan compiler.cfg.build-stack-frame
+compiler.cfg.rpo ;
IN: compiler.cfg.mr
: build-mr ( cfg -- mr )
- convert-two-operand
insert-gc-checks
linear-scan
flatten-cfg
compiler.cfg.copy-prop
compiler.cfg.dce
compiler.cfg.write-barrier
+compiler.cfg.two-operand
compiler.cfg.ssa.destruction
compiler.cfg.empty-blocks
compiler.cfg.predecessors
copy-propagation
eliminate-dead-code
eliminate-write-barriers
+ convert-two-operand
destruct-ssa
delete-empty-blocks
?check
GENERIC: prepare-insn ( insn -- )
-M: ##copy prepare-insn
+: prepare-copy ( insn -- )
[ dst>> ] [ src>> ] bi 2array copies get push ;
+M: ##copy prepare-insn prepare-copy ;
+
+M: ##copy-float prepare-insn prepare-copy ;
+
M: ##phi prepare-insn
[ dst>> ] [ inputs>> values ] bi
[ eliminate-copy ] with each ;
[ 2drop ] [ eliminate-copy ] if
] assoc-each ;
+UNION: copy-insn ##copy ##copy-float ;
+
: useless-copy? ( ##copy -- ? )
- dup ##copy? [ [ dst>> ] [ src>> ] bi eq? ] [ drop f ] if ;
+ dup copy-insn? [ [ dst>> ] [ src>> ] bi eq? ] [ drop f ] if ;
: perform-renaming ( cfg -- )
leader-map get keys [ dup leader ] H{ } map>assoc renamings set
] each-basic-block ;
: destruct-ssa ( cfg -- cfg' )
- dup cfg-has-phis? [
- dup construct-cssa
- dup compute-defs
- dup compute-dominance
- compute-ssa-live-sets
- dup compute-live-ranges
- dup prepare-coalescing
- process-copies
- dup perform-renaming
- ] when ;
\ No newline at end of file
+ dup construct-cssa
+ dup compute-defs
+ dup compute-dominance
+ compute-ssa-live-sets
+ dup compute-live-ranges
+ dup prepare-coalescing
+ process-copies
+ dup perform-renaming ;
\ No newline at end of file
compiler.cfg.ssa.interference.live-ranges ;
IN: compiler.cfg.ssa.interference
+! Interference testing using SSA properties. Actually the only SSA property
+! used here is that definitions dominate uses; because of this, the input
+! is allowed to have multiple definitions of each vreg as long as they're
+! all in the same basic block. This is needed because two-operand conversion
+! runs before coalescing, which uses SSA interference testing.
<PRIVATE
:: kill-after-def? ( vreg1 vreg2 bb -- ? )
[ 2drop 2drop f ]
} cond ;
-! Debug this stuff later
<PRIVATE
+! Debug this stuff later
+
: quadratic-test? ( seq1 seq2 -- ? ) [ length ] bi@ + 10 < ;
: quadratic-test ( seq1 seq2 -- ? )
SYMBOLS: local-def-indices local-kill-indices ;
-: record-def ( n vregs -- )
- dup [ local-def-indices get set-at ] [ 2drop ] if ;
+: record-def ( n vreg -- )
+ ! We allow multiple defs of a vreg as long as they're
+ ! all in the same basic block
+ dup [
+ local-def-indices get 2dup key?
+ [ 3drop ] [ set-at ] if
+ ] [ 2drop ] if ;
: record-uses ( n vregs -- )
local-kill-indices get '[ _ set-at ] with each ;
T{ ##sub f V int-regs 1 V int-regs 2 V int-regs 3 }
} (convert-two-operand)
] unit-test
-
-[
- V{
- T{ ##sub f V int-regs 1 V int-regs 1 V int-regs 2 }
- }
-] [
- {
- T{ ##sub f V int-regs 1 V int-regs 1 V int-regs 2 }
- } (convert-two-operand)
-] unit-test
-
-[
- V{
- T{ ##copy f V int-regs 4 V int-regs 1 }
- T{ ##copy f V int-regs 1 V int-regs 2 }
- T{ ##sub f V int-regs 1 V int-regs 1 V int-regs 4 }
- }
-] [
- {
- T{ ##sub f V int-regs 1 V int-regs 2 V int-regs 1 }
- } (convert-two-operand)
-] unit-test
compiler.cfg.rpo cpu.architecture ;
IN: compiler.cfg.two-operand
-! This pass runs after SSA coalescing and normalizes instructions
-! to fit the x86 two-address scheme. Possibilities are:
-
-! 1) x = x op y
-! 2) x = y op x
-! 3) x = y op z
-
-! In case 1, there is nothing to do.
-
-! In case 2, we convert to
-! z = y
-! z = z op x
-! x = z
-
-! In case 3, we convert to
+! This pass runs before SSA coalescing and normalizes instructions
+! to fit the x86 two-address scheme. Since the input is in SSA,
+! it suffices to convert
+!
+! x = y op z
+!
+! to
+!
! x = y
! x = x op z
-
-! In case 2 and case 3, linear scan coalescing will eliminate a
-! copy if the value y is never used again.
-
+!
! We don't bother with ##add, ##add-imm, ##sub-imm or ##mul-imm
! since x86 has LEA and IMUL instructions which are effectively
! three-operand addition and multiplication, respectively.
{ double-float-regs [ ##copy-float ] }
} case ; inline
-: case-1? ( insn -- ? ) [ dst>> ] [ src1>> ] bi = ; inline
-
-: case-1 ( insn -- ) , ; inline
-
-: case-2? ( insn -- ? ) [ dst>> ] [ src2>> ] bi = ; inline
-
-: case-2 ( insn -- )
- dup dst>> reg-class>> next-vreg
- [ swap src2>> emit-copy ]
- [ drop [ src2>> ] [ src1>> ] bi emit-copy ]
- [ >>src2 dup dst>> >>src1 , ]
- 2tri ; inline
-
-: case-3 ( insn -- )
+M: two-operand-insn convert-two-operand*
[ [ dst>> ] [ src1>> ] bi emit-copy ]
[ dup dst>> >>src1 , ]
- bi ; inline
-
-M: two-operand-insn convert-two-operand*
- {
- { [ dup case-1? ] [ case-1 ] }
- { [ dup case-2? ] [ case-2 ] }
- [ case-3 ]
- } cond ; inline
+ bi ;
M: ##not convert-two-operand*
- dup [ dst>> ] [ src>> ] bi = [
- [ [ dst>> ] [ src>> ] bi ##copy ]
- [ dup dst>> >>src ]
- bi
- ] unless , ;
+ [ [ dst>> ] [ src>> ] bi emit-copy ]
+ [ dup dst>> >>src , ]
+ bi ;
M: insn convert-two-operand* , ;