factor/library/compiler/generator/templates.factor

285 lines
7.7 KiB
Factor
Raw Normal View History

! Copyright (C) 2006 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
IN: compiler
2006-04-22 15:26:32 -04:00
USING: arrays generic hashtables inference io kernel math
2006-04-17 17:17:34 -04:00
namespaces prettyprint sequences vectors words ;
! Register allocation
2006-05-04 18:19:39 -04:00
! Hash mapping reg-classes to mutable vectors
: free-vregs ( reg-class -- seq ) \ free-vregs get hash ;
: alloc-reg ( reg-class -- vreg ) free-vregs pop ;
: take-reg ( vreg -- ) dup delegate free-vregs delete ;
2006-05-05 21:41:57 -04:00
: reg-spec>class ( spec -- class )
float eq? T{ float-regs f 8 } T{ int-regs } ? ;
2006-05-09 13:17:03 -04:00
: spec>vreg ( spec -- vreg )
dup integer? [
<int-vreg> dup take-reg
] [
reg-spec>class alloc-reg
] if ;
2006-04-09 23:11:19 -04:00
! A data stack location.
TUPLE: ds-loc n ;
! A call stack location.
TUPLE: cs-loc n ;
UNION: loc ds-loc cs-loc ;
2006-04-09 23:11:19 -04:00
TUPLE: phantom-stack height ;
2006-04-09 22:23:00 -04:00
C: phantom-stack ( -- stack )
0 over set-phantom-stack-height
2006-04-09 23:11:19 -04:00
V{ } clone over set-delegate ;
2006-04-09 22:23:00 -04:00
GENERIC: finalize-height ( n stack -- )
GENERIC: <loc> ( n stack -- loc )
: (loc)
#! Utility for methods on <loc>
phantom-stack-height - ;
2006-04-09 22:23:00 -04:00
: (finalize-height) ( stack word -- )
#! We consolidate multiple stack height changes until the
#! last moment, and we emit the final height changing
#! instruction here.
2006-04-09 22:23:00 -04:00
swap [
phantom-stack-height
2006-04-28 18:38:48 -04:00
dup zero? [ 2drop ] [ swap execute ] if
2006-04-09 22:23:00 -04:00
0
] keep set-phantom-stack-height ; inline
TUPLE: phantom-datastack ;
C: phantom-datastack
[ >r <phantom-stack> r> set-delegate ] keep ;
M: phantom-datastack <loc> (loc) <ds-loc> ;
M: phantom-datastack finalize-height
\ %inc-d (finalize-height) ;
TUPLE: phantom-callstack ;
C: phantom-callstack
[ >r <phantom-stack> r> set-delegate ] keep ;
M: phantom-callstack <loc> (loc) <cs-loc> ;
M: phantom-callstack finalize-height
\ %inc-r (finalize-height) ;
: phantom-locs ( n phantom -- locs )
#! A sequence of n ds-locs or cs-locs indexing the stack.
2006-05-14 23:25:34 -04:00
swap <reversed> [ swap <loc> ] map-with ;
2006-04-09 22:23:00 -04:00
: phantom-locs* ( phantom -- locs )
2006-04-09 23:11:19 -04:00
dup length swap phantom-locs ;
2006-04-09 22:23:00 -04:00
: adjust-phantom ( n phantom -- )
[ phantom-stack-height + ] keep set-phantom-stack-height ;
2006-04-11 02:45:24 -04:00
GENERIC: cut-phantom ( n phantom -- seq )
M: phantom-stack cut-phantom ( n phantom -- seq )
[ delegate cut* swap ] keep set-delegate ;
2006-04-09 22:23:00 -04:00
SYMBOL: phantom-d
SYMBOL: phantom-r
: phantoms ( -- phantom phantom ) phantom-d get phantom-r get ;
2006-04-09 22:23:00 -04:00
: init-templates ( -- )
<phantom-datastack> phantom-d set
<phantom-callstack> phantom-r set ;
: finalize-heights ( -- )
phantoms [ finalize-height ] 2apply ;
2006-04-22 15:26:32 -04:00
: vreg>stack ( value loc -- )
over loc? over not or [ 2drop ] [ %replace ] if ;
2006-04-22 15:26:32 -04:00
: vregs>stack ( phantom -- )
[
dup phantom-locs* [ vreg>stack ] 2each 0
] keep set-length ;
: (live-locs) ( seq -- seq )
dup phantom-locs* [ 2array ] 2map
[ first2 over loc? >r = not r> and ] subset
[ first ] map ;
: stack>new-vreg ( loc spec -- vreg )
spec>vreg [ swap %peek ] keep ;
2006-04-22 15:26:32 -04:00
: live-locs ( phantom phantom -- hash )
[ (live-locs) ] 2apply append prune
2006-05-05 21:41:57 -04:00
[ dup f stack>new-vreg ] map>hash ;
2006-04-22 15:26:32 -04:00
: lazy-store ( value loc -- )
over loc? [
2dup =
[ 2drop ] [ >r \ live-locs get hash r> vreg>stack ] if
] [
2006-04-22 15:26:32 -04:00
2drop
] if ;
2006-04-11 02:45:24 -04:00
2006-04-22 15:26:32 -04:00
: flush-locs ( phantom phantom -- )
2dup live-locs \ live-locs set
[ dup phantom-locs* [ lazy-store ] 2each ] 2apply ;
: finalize-contents ( -- )
2006-04-23 01:40:49 -04:00
phantoms 2dup flush-locs [ vregs>stack ] 2apply ;
2006-04-08 03:13:01 -04:00
: end-basic-block ( -- ) finalize-contents finalize-heights ;
2006-04-11 02:45:24 -04:00
: used-vregs ( -- seq ) phantoms append [ vreg? ] subset ;
: (compute-free-vregs) ( used class -- vector )
dup vregs length reverse [ swap <vreg> ] map-with diff
>vector ;
2006-04-11 02:45:24 -04:00
: compute-free-vregs ( -- )
used-vregs
{ T{ int-regs } T{ float-regs f 8 } }
[ 2dup (compute-free-vregs) ] map>hash \ free-vregs set
drop ;
2006-04-11 02:45:24 -04:00
: additional-vregs ( seq seq -- n )
2006-04-23 01:40:49 -04:00
2array phantoms 2array [ [ length ] map ] 2apply v-
[ 0 max ] map sum ;
2006-04-23 01:40:49 -04:00
: free-vregs# ( -- int# float# )
T{ int-regs } free-vregs length
phantoms [ [ loc? ] subset length ] 2apply + -
T{ float-regs f 8 } free-vregs length ;
2006-04-23 01:40:49 -04:00
: ensure-vregs ( int# float# -- )
compute-free-vregs free-vregs# swapd <= >r <= r> and
2006-04-23 01:40:49 -04:00
[ finalize-contents compute-free-vregs ] unless ;
2006-05-09 13:17:03 -04:00
: (lazy-load) ( spec value -- value )
{
{ [ dup loc? ] [ >r spec>vreg dup r> %peek ] }
{ [ dup [ float-regs? ] is? ] [ nip ] }
{ [ over float eq? ] [ >r spec>vreg dup r> %move ] }
{ [ t ] [ nip ] }
} cond ;
2006-04-08 03:13:01 -04:00
2006-05-09 13:17:03 -04:00
: lazy-load ( values template -- )
dup length neg phantom-d get adjust-phantom
[ first2 >r swap (lazy-load) r> set ] 2each ;
2006-04-08 03:13:01 -04:00
: compatible-vreg? ( n vreg -- ? )
2006-05-09 11:31:10 -04:00
dup [ int-regs? ] is? [ vreg-n = ] [ 2drop f ] if ;
2006-04-08 03:13:01 -04:00
: compatible-values? ( value template -- ? )
{
{ [ over loc? ] [ 2drop t ] }
{ [ dup not ] [ drop [ float-regs? ] is? not ] }
{ [ dup float eq? ] [ 2drop t ] }
{ [ dup integer? ] [ swap compatible-vreg? ] }
2006-04-08 03:13:01 -04:00
} cond ;
2006-04-11 02:45:24 -04:00
: template-match? ( template phantom -- ? )
2006-05-14 23:25:34 -04:00
[ <reversed> ] 2apply
t [ swap first compatible-values? and ] 2reduce ;
2006-04-08 03:13:01 -04:00
: split-template ( template phantom -- slow fast )
2006-04-20 16:28:08 -04:00
over length over length <=
[ drop { } swap ] [ length swap cut* ] if ;
2006-04-11 02:45:24 -04:00
: match-template ( template -- slow fast )
phantom-d get 2dup template-match?
[ split-template ] [ drop { } ] if ;
: fast-input ( template -- )
2006-05-09 13:17:03 -04:00
phantom-d get over length swap cut-phantom swap lazy-load ;
2006-04-09 22:23:00 -04:00
2006-05-01 23:30:24 -04:00
: phantom-push ( obj stack -- )
1 over adjust-phantom push ;
: phantom-append ( seq stack -- )
over length over adjust-phantom swap nappend ;
: (template-outputs) ( seq stack -- )
phantoms swapd phantom-append phantom-append ;
SYMBOL: +input
SYMBOL: +output
SYMBOL: +scratch
SYMBOL: +clobber
: fix-spec ( spec -- spec )
H{
{ +input { } }
{ +output { } }
{ +scratch { } }
{ +clobber { } }
} swap hash-union ;
: output-vregs ( -- seq seq )
+output +clobber [ get [ get ] map ] 2apply ;
: outputs-clash? ( -- ? )
output-vregs append phantoms append
[ swap member? ] contains-with? ;
: slow-input ( template -- )
2006-05-09 13:17:03 -04:00
#! Are we loading stuff from the stack? Then flush out
#! remaining vregs, not slurped in by fast-input.
#! Do the outputs clash with vregs on the phantom stacks?
#! Then we must flush them first.
dup empty? not outputs-clash? or [ finalize-contents ] when
[ length phantom-d get phantom-locs ] keep lazy-load ;
: requested-vregs ( template -- int# float# )
dup length swap [ float eq? ] subset length [ - ] keep ;
2006-05-14 15:44:07 -04:00
: (requests-class?) ( class template -- )
[ second reg-spec>class eq? ] contains-with? ;
: requests-class? ( class -- ? )
dup +input get (requests-class?) swap
+scratch get (requests-class?) or ;
: ?fp-scratch ( -- n )
2006-05-14 16:44:47 -04:00
T{ float-regs f 8 } requests-class? 1 0 ? ;
2006-05-14 15:44:07 -04:00
: fp-scratch ( -- vreg )
"fp-scratch" get [
T{ int-regs } alloc-reg dup "fp-scratch" set
] unless* ;
: guess-vregs ( -- int# float# )
2006-05-14 15:44:07 -04:00
+input get { } additional-vregs ?fp-scratch +
2006-05-05 20:06:57 -04:00
+scratch get [ first ] map requested-vregs >r + r> ;
: alloc-scratch ( -- )
2006-05-09 13:17:03 -04:00
+scratch get [ first2 >r spec>vreg r> set ] each ;
: template-inputs ( -- )
! Ensure we have enough to hold any new stack elements we
! will read (if any), and scratch.
guess-vregs ensure-vregs
! Split the template into available (fast) parts and those
! that require allocating registers and reading the stack
+input get match-template fast-input slow-input
! Finally allocate scratch registers
alloc-scratch ;
2006-04-11 02:45:24 -04:00
: template-outputs ( -- )
+output get [ get ] map { } (template-outputs) ;
: with-template ( quot spec -- )
fix-spec [ template-inputs call template-outputs ] bind
compute-free-vregs ; inline
2006-04-28 18:38:48 -04:00
: operand ( var -- op ) get v>operand ; inline