Debugging register allocator and inline allocation
parent
0e4e05d5cd
commit
cf46a832e7
|
@ -250,9 +250,9 @@ M: #dispatch emit-node
|
|||
|
||||
: emit-intrinsic ( word -- next )
|
||||
{
|
||||
{ \ (tuple) [ allot-size 2 cells + tuple tuple emit-allot ] }
|
||||
{ \ (array) [ allot-size 2 cells + array object emit-allot ] }
|
||||
{ \ (byte-array) [ allot-size cells 2 + byte-array object emit-allot ] }
|
||||
{ \ (tuple) [ allot-size 2 + cells tuple tuple emit-allot ] }
|
||||
{ \ (array) [ allot-size 2 + cells array object emit-allot ] }
|
||||
{ \ (byte-array) [ allot-size 2 cells + byte-array object emit-allot ] }
|
||||
{ \ (complex) [ 3 cells complex complex emit-allot ] }
|
||||
{ \ (ratio) [ 3 cells ratio ratio emit-allot ] }
|
||||
{ \ (wrapper) [ 2 cells wrapper object emit-allot ] }
|
||||
|
|
|
@ -24,15 +24,21 @@ SYMBOL: active-intervals
|
|||
: delete-active ( live-interval -- )
|
||||
active-intervals get delete ;
|
||||
|
||||
: expired-interval? ( n interval -- ? )
|
||||
[ end>> ] [ start>> ] bi or > ;
|
||||
|
||||
: expire-old-intervals ( n -- )
|
||||
active-intervals get
|
||||
swap '[ end>> _ < ] partition
|
||||
active-intervals set
|
||||
[ deallocate-register ] each ;
|
||||
[ expired-interval? ] with partition
|
||||
[ [ deallocate-register ] each ] [ active-intervals set ] bi* ;
|
||||
|
||||
: expire-old-uses ( n -- )
|
||||
active-intervals get
|
||||
swap '[ uses>> dup peek _ < [ pop* ] [ drop ] if ] each ;
|
||||
swap '[
|
||||
uses>> [
|
||||
dup peek _ < [ pop* ] [ drop ] if
|
||||
] unless-empty
|
||||
] each ;
|
||||
|
||||
: update-state ( live-interval -- )
|
||||
start>> [ expire-old-intervals ] [ expire-old-uses ] bi ;
|
||||
|
@ -59,13 +65,7 @@ SYMBOL: progress
|
|||
unhandled-intervals get heap-push-all ;
|
||||
|
||||
: assign-free-register ( live-interval registers -- )
|
||||
#! If the live interval does not have any uses, it means it
|
||||
#! will be spilled immediately, so it still needs a register
|
||||
#! to compute the new value, but we don't add the interval
|
||||
#! to the active set and we don't remove the register from
|
||||
#! the free list.
|
||||
over uses>> empty?
|
||||
[ peek >>reg drop ] [ pop >>reg add-active ] if ;
|
||||
pop >>reg add-active ;
|
||||
|
||||
! Spilling
|
||||
SYMBOL: spill-counts
|
||||
|
@ -75,7 +75,9 @@ SYMBOL: spill-counts
|
|||
|
||||
: interval-to-spill ( -- live-interval )
|
||||
#! We spill the interval with the most distant use location.
|
||||
active-intervals get unclip-slice [
|
||||
active-intervals get
|
||||
[ uses>> empty? not ] filter
|
||||
unclip-slice [
|
||||
[ [ uses>> peek ] bi@ > ] most
|
||||
] reduce ;
|
||||
|
||||
|
@ -95,15 +97,16 @@ SYMBOL: spill-counts
|
|||
|
||||
: assign-spill ( before after -- before after )
|
||||
#! If it has been spilled already, reuse spill location.
|
||||
over reload-from>> [ next-spill-location ] unless*
|
||||
USE: cpu.architecture ! XXX
|
||||
over reload-from>>
|
||||
[ int-regs next-spill-location ] unless*
|
||||
tuck [ >>spill-to ] [ >>reload-from ] 2bi* ;
|
||||
|
||||
: split-and-spill ( live-interval -- before after )
|
||||
dup split-interval [ record-split ] [ assign-spill ] 2bi ;
|
||||
|
||||
: reuse-register ( new existing -- )
|
||||
reg>> >>reg
|
||||
dup uses>> empty? [ deallocate-register ] [ add-active ] if ;
|
||||
reg>> >>reg add-active ;
|
||||
|
||||
: spill-existing ( new existing -- )
|
||||
#! Our new interval will be used before the active interval
|
||||
|
|
|
@ -2,6 +2,8 @@ IN: compiler.cfg.linear-scan.tests
|
|||
USING: tools.test random sorting sequences sets hashtables assocs
|
||||
kernel fry arrays splitting namespaces math accessors vectors
|
||||
math.order
|
||||
cpu.architecture
|
||||
compiler.cfg.instructions
|
||||
compiler.cfg.registers
|
||||
compiler.cfg.linear-scan
|
||||
compiler.cfg.linear-scan.live-intervals
|
||||
|
@ -103,3 +105,17 @@ SYMBOL: max-uses
|
|||
USING: math.private compiler.cfg.debugger ;
|
||||
|
||||
[ ] [ [ float+ float>fixnum 3 fixnum*fast ] test-mr first linear-scan drop ] unit-test
|
||||
|
||||
[ f ] [
|
||||
T{ ##allot
|
||||
f
|
||||
T{ vreg f int-regs 1 }
|
||||
40
|
||||
array
|
||||
object
|
||||
T{ vreg f int-regs 2 }
|
||||
T{ vreg f int-regs 3 }
|
||||
f
|
||||
} clone
|
||||
1array (linear-scan) first regs>> values all-equal?
|
||||
] unit-test
|
||||
|
|
|
@ -22,12 +22,12 @@ IN: compiler.cfg.linear-scan
|
|||
! by Omri Traub, Glenn Holloway, Michael D. Smith
|
||||
! http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.34.8435
|
||||
|
||||
: (linear-scan) ( insns -- insns' )
|
||||
dup compute-live-intervals
|
||||
machine-registers allocate-registers assign-registers ;
|
||||
|
||||
: linear-scan ( mr -- mr' )
|
||||
[
|
||||
[
|
||||
dup compute-live-intervals
|
||||
machine-registers allocate-registers
|
||||
assign-registers
|
||||
] change-instructions
|
||||
[ (linear-scan) ] change-instructions
|
||||
! spill-counts get >>spill-counts
|
||||
] with-scope ;
|
||||
|
|
|
@ -24,7 +24,7 @@ GENERIC: lazy-store ( dst src -- )
|
|||
GENERIC: minimal-ds-loc* ( min obj -- min )
|
||||
|
||||
! This will be a multimethod soon
|
||||
DEFER: %move
|
||||
DEFER: ##move
|
||||
|
||||
PRIVATE>
|
||||
|
||||
|
@ -62,7 +62,7 @@ M: cached (lazy-load) >r vreg>> r> (lazy-load) ;
|
|||
M: cached (eager-load) >r vreg>> r> (eager-load) ;
|
||||
M: cached lazy-store
|
||||
2dup loc>> live-loc?
|
||||
[ "live-locs" get at %move ] [ 2drop ] if ;
|
||||
[ "live-locs" get at ##move ] [ 2drop ] if ;
|
||||
M: cached minimal-ds-loc* loc>> minimal-ds-loc* ;
|
||||
|
||||
M: tagged move-spec drop f ;
|
||||
|
@ -78,9 +78,9 @@ M: unboxed-c-ptr move-spec class ;
|
|||
M: constant move-spec class ;
|
||||
|
||||
! Moving values between locations and registers
|
||||
: %move-bug ( -- * ) "Bug in generator.registers" throw ;
|
||||
: ##move-bug ( -- * ) "Bug in generator.registers" throw ;
|
||||
|
||||
: %unbox-c-ptr ( dst src -- )
|
||||
: ##unbox-c-ptr ( dst src -- )
|
||||
dup value-class {
|
||||
{ [ dup \ f class<= ] [ drop ##unbox-f ] }
|
||||
{ [ dup simple-alien class<= ] [ drop ##unbox-alien ] }
|
||||
|
@ -88,15 +88,15 @@ M: constant move-spec class ;
|
|||
[ drop ##unbox-any-c-ptr ]
|
||||
} cond ; inline
|
||||
|
||||
: %move-via-temp ( dst src -- )
|
||||
: ##move-via-temp ( dst src -- )
|
||||
#! For many transfers, such as loc to unboxed-alien, we
|
||||
#! don't have an intrinsic, so we transfer the source to
|
||||
#! temp then temp to the destination.
|
||||
int-regs next-vreg [ over %move value-class ] keep
|
||||
int-regs next-vreg [ over ##move value-class ] keep
|
||||
tagged new
|
||||
swap >>vreg
|
||||
swap >>class
|
||||
%move ;
|
||||
##move ;
|
||||
|
||||
! Operands holding pointers to freshly-allocated objects which
|
||||
! are guaranteed to be in the nursery
|
||||
|
@ -106,7 +106,7 @@ SYMBOL: fresh-objects
|
|||
|
||||
: fresh-object? ( vreg -- ? ) fresh-objects get memq? ;
|
||||
|
||||
: %move ( dst src -- )
|
||||
: ##move ( dst src -- )
|
||||
2dup [ move-spec ] bi@ 2array {
|
||||
{ { f f } [ ##copy ] }
|
||||
{ { unboxed-alien unboxed-alien } [ ##copy ] }
|
||||
|
@ -115,8 +115,8 @@ SYMBOL: fresh-objects
|
|||
{ { unboxed-c-ptr unboxed-c-ptr } [ ##copy ] }
|
||||
{ { float float } [ ##copy-float ] }
|
||||
|
||||
{ { f unboxed-c-ptr } [ %move-bug ] }
|
||||
{ { f unboxed-byte-array } [ %move-bug ] }
|
||||
{ { f unboxed-c-ptr } [ ##move-bug ] }
|
||||
{ { f unboxed-byte-array } [ ##move-bug ] }
|
||||
|
||||
{ { f constant } [ value>> ##load-literal ] }
|
||||
|
||||
|
@ -128,10 +128,10 @@ SYMBOL: fresh-objects
|
|||
{ { unboxed-alien f } [ ##unbox-alien ] }
|
||||
{ { unboxed-byte-array f } [ ##unbox-byte-array ] }
|
||||
{ { unboxed-f f } [ ##unbox-f ] }
|
||||
{ { unboxed-c-ptr f } [ %unbox-c-ptr ] }
|
||||
{ { unboxed-c-ptr f } [ ##unbox-c-ptr ] }
|
||||
{ { loc f } [ swap ##replace ] }
|
||||
|
||||
[ drop %move-via-temp ]
|
||||
[ drop ##move-via-temp ]
|
||||
} case ;
|
||||
|
||||
! A compile-time stack
|
||||
|
@ -264,10 +264,10 @@ M: value (lazy-load)
|
|||
|
||||
M: value (eager-load) ( value spec -- vreg )
|
||||
[ alloc-vreg-for ] [ drop ] 2bi
|
||||
[ %move ] [ drop ] 2bi ;
|
||||
[ ##move ] [ drop ] 2bi ;
|
||||
|
||||
M: loc lazy-store
|
||||
2dup live-loc? [ "live-locs" get at %move ] [ 2drop ] if ;
|
||||
2dup live-loc? [ "live-locs" get at ##move ] [ 2drop ] if ;
|
||||
|
||||
: finalize-locs ( -- )
|
||||
#! Perform any deferred stack shuffling.
|
||||
|
@ -279,7 +279,7 @@ M: loc lazy-store
|
|||
: finalize-vregs ( -- )
|
||||
#! Store any vregs to their final stack locations.
|
||||
[
|
||||
dup loc? over cached? or [ 2drop ] [ %move ] if
|
||||
dup loc? over cached? or [ 2drop ] [ ##move ] if
|
||||
] each-loc ;
|
||||
|
||||
: clear-phantoms ( -- )
|
||||
|
|
|
@ -88,7 +88,7 @@ HOOK: %copy-float cpu ( dst src -- )
|
|||
|
||||
! Box and unbox floats
|
||||
HOOK: %unbox-float cpu ( dst src -- )
|
||||
HOOK: %box-float cpu ( dst src -- )
|
||||
HOOK: %box-float cpu ( dst src temp -- )
|
||||
|
||||
! FFI stuff
|
||||
|
||||
|
@ -184,7 +184,7 @@ HOOK: %unbox-f cpu ( dst src -- )
|
|||
|
||||
HOOK: %unbox-any-c-ptr cpu ( dst src -- )
|
||||
|
||||
HOOK: %box-alien cpu ( dst src -- )
|
||||
HOOK: %box-alien cpu ( dst src temp1 temp2 -- )
|
||||
|
||||
! Allocation
|
||||
HOOK: %allot cpu ( dst size type tag temp -- )
|
||||
|
|
|
@ -12,34 +12,34 @@ M:: x86 %write-barrier ( src temp -- )
|
|||
! Mark the card
|
||||
src card-bits SHR
|
||||
"cards_offset" f temp %alien-global
|
||||
temp temp [+] card-mark <byte> MOV
|
||||
temp src [+] card-mark <byte> MOV
|
||||
|
||||
! Mark the card deck
|
||||
temp deck-bits card-bits - SHR
|
||||
src deck-bits card-bits - SHR
|
||||
"decks_offset" f temp %alien-global
|
||||
temp temp [+] card-mark <byte> MOV ;
|
||||
temp src [+] card-mark <byte> MOV ;
|
||||
|
||||
: load-zone-ptr ( reg -- )
|
||||
#! Load pointer to start of zone array
|
||||
0 MOV "nursery" f rc-absolute-cell rel-dlsym ;
|
||||
|
||||
: load-allot-ptr ( temp -- )
|
||||
[ load-zone-ptr ] [ PUSH ] [ dup cell [+] MOV ] tri ;
|
||||
: load-allot-ptr ( nursery-ptr allot-ptr -- )
|
||||
[ drop load-zone-ptr ] [ swap cell [+] MOV ] 2bi ;
|
||||
|
||||
: inc-allot-ptr ( n temp -- )
|
||||
[ POP ] [ cell [+] swap 8 align ADD ] bi ;
|
||||
: inc-allot-ptr ( nursery-ptr n -- )
|
||||
[ cell [+] ] dip 8 align ADD ;
|
||||
|
||||
: store-header ( temp type -- )
|
||||
[ 0 [+] ] [ type-number tag-fixnum ] bi* MOV ;
|
||||
[ [] ] [ type-number tag-fixnum ] bi* MOV ;
|
||||
|
||||
: store-tagged ( dst temp tag -- )
|
||||
dupd tag-number OR MOV ;
|
||||
: store-tagged ( dst tag -- )
|
||||
tag-number OR ;
|
||||
|
||||
M:: x86 %allot ( dst size type tag temp -- )
|
||||
temp load-allot-ptr
|
||||
temp type store-header
|
||||
temp size inc-allot-ptr
|
||||
dst temp store-tagged ;
|
||||
M:: x86 %allot ( dst size type tag nursery-ptr -- )
|
||||
nursery-ptr dst load-allot-ptr
|
||||
dst type store-header
|
||||
dst tag store-tagged
|
||||
nursery-ptr size inc-allot-ptr ;
|
||||
|
||||
M: x86 %gc ( -- )
|
||||
"end" define-label
|
||||
|
@ -130,10 +130,11 @@ M:: x86 %box-alien ( dst src temp -- )
|
|||
|
||||
\ fixnum>bignum [
|
||||
"x" operand %untag-fixnum
|
||||
"x" operand dup "scratch" operand %allot-bignum-signed-1
|
||||
"y" operand "x" operand "scratch" operand %allot-bignum-signed-1
|
||||
] T{ template
|
||||
{ input { { f "x" } } }
|
||||
{ scratch { { f "scratch" } } }
|
||||
{ output { "x" } }
|
||||
{ scratch { { f "y" } { f "scratch" } } }
|
||||
{ output { "y" } }
|
||||
{ clobber { "x" } }
|
||||
{ gc t }
|
||||
} define-intrinsic
|
||||
|
|
Loading…
Reference in New Issue