191 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Factor
		
	
	
			
		
		
	
	
			191 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Factor
		
	
	
! Copyright (C) 2004, 2010 Slava Pestov.
 | 
						|
! See http://factorcode.org/license.txt for BSD license.
 | 
						|
USING: accessors arrays assocs combinators compiler.cfg
 | 
						|
compiler.cfg.builder.blocks compiler.cfg.comparisons
 | 
						|
compiler.cfg.hats compiler.cfg.instructions
 | 
						|
compiler.cfg.intrinsics compiler.cfg.registers
 | 
						|
compiler.cfg.stacks compiler.cfg.stacks.local compiler.tree
 | 
						|
compiler.cfg.utilities cpu.architecture fry kernel locals make math
 | 
						|
namespaces sequences words ;
 | 
						|
IN: compiler.cfg.builder
 | 
						|
 | 
						|
SYMBOL: procedures
 | 
						|
SYMBOL: loops
 | 
						|
 | 
						|
: begin-cfg ( word label -- cfg )
 | 
						|
    H{ } clone loops set
 | 
						|
    <basic-block> dup set-basic-block <cfg> dup cfg set ;
 | 
						|
 | 
						|
: with-cfg-builder ( nodes word label quot: ( ..a block -- ..b ) -- )
 | 
						|
    '[
 | 
						|
        begin-stack-analysis
 | 
						|
        begin-cfg
 | 
						|
        [ procedures get push ]
 | 
						|
        [ entry>> @ ]
 | 
						|
        [ end-stack-analysis ] tri
 | 
						|
    ] with-scope ; inline
 | 
						|
 | 
						|
: with-dummy-cfg-builder ( node quot -- )
 | 
						|
    [
 | 
						|
        [ V{ } clone procedures ] 2dip
 | 
						|
        '[ _ t t [ drop _ call( node -- ) ] with-cfg-builder ] with-variable
 | 
						|
    ] { } make drop ;
 | 
						|
 | 
						|
GENERIC: emit-node ( block node -- block' )
 | 
						|
 | 
						|
: emit-nodes ( block nodes -- block' )
 | 
						|
    [ over [ emit-node ] [ drop ] if ] each ;
 | 
						|
 | 
						|
: begin-word ( block -- block' )
 | 
						|
    t >>kill-block?
 | 
						|
    ##safepoint, ##prologue, ##branch,
 | 
						|
    begin-basic-block ;
 | 
						|
 | 
						|
: (build-cfg) ( nodes word label -- )
 | 
						|
    [ begin-word swap emit-nodes drop ] with-cfg-builder ;
 | 
						|
 | 
						|
: build-cfg ( nodes word -- procedures )
 | 
						|
    V{ } clone [
 | 
						|
        procedures [
 | 
						|
            dup (build-cfg)
 | 
						|
        ] with-variable
 | 
						|
    ] keep ;
 | 
						|
 | 
						|
: emit-loop-call ( successor-block current-block -- )
 | 
						|
    ##safepoint, ##branch,
 | 
						|
    [ swap connect-bbs ] [ end-basic-block ] bi ;
 | 
						|
 | 
						|
: emit-call ( block word height -- block' )
 | 
						|
    over loops get at [
 | 
						|
        2nip swap emit-loop-call f
 | 
						|
    ] [ emit-trivial-call ] if* ;
 | 
						|
 | 
						|
! #recursive
 | 
						|
: recursive-height ( #recursive -- n )
 | 
						|
    [ label>> return>> in-d>> length ] [ in-d>> length ] bi - ;
 | 
						|
 | 
						|
: emit-recursive ( block #recursive -- block' )
 | 
						|
    [ [ label>> id>> ] [ recursive-height ] bi emit-call ] keep
 | 
						|
    [ child>> ] [ label>> word>> ] [ label>> id>> ] tri (build-cfg) ;
 | 
						|
 | 
						|
: emit-loop ( block #recursive -- block' )
 | 
						|
    ##branch, [ begin-basic-block ] dip
 | 
						|
    [ label>> id>> loops get set-at ] [ child>> emit-nodes ] 2bi ;
 | 
						|
 | 
						|
M: #recursive emit-node ( block node -- block' )
 | 
						|
    dup label>> loop?>> [ emit-loop ] [ emit-recursive ] if ;
 | 
						|
 | 
						|
! #if
 | 
						|
: emit-branch ( nodes block -- pair/f )
 | 
						|
    [ swap emit-nodes ] with-branch ;
 | 
						|
 | 
						|
: emit-if ( block node -- block' )
 | 
						|
    children>> over '[ _ emit-branch ] map emit-conditional ;
 | 
						|
 | 
						|
: trivial-branch? ( nodes -- value ? )
 | 
						|
    dup length 1 = [
 | 
						|
        first dup #push? [ literal>> t ] [ drop f f ] if
 | 
						|
    ] [ drop f f ] if ;
 | 
						|
 | 
						|
: trivial-if? ( #if -- ? )
 | 
						|
    children>> first2
 | 
						|
    [ trivial-branch? [ t eq? ] when ]
 | 
						|
    [ trivial-branch? [ f eq? ] when ] bi*
 | 
						|
    and ;
 | 
						|
 | 
						|
: emit-trivial-if ( -- )
 | 
						|
    [ f cc/= ^^compare-imm ] unary-op ;
 | 
						|
 | 
						|
: trivial-not-if? ( #if -- ? )
 | 
						|
    children>> first2
 | 
						|
    [ trivial-branch? [ f eq? ] when ]
 | 
						|
    [ trivial-branch? [ t eq? ] when ] bi*
 | 
						|
    and ;
 | 
						|
 | 
						|
: emit-trivial-not-if ( -- )
 | 
						|
    [ f cc= ^^compare-imm ] unary-op ;
 | 
						|
 | 
						|
: emit-actual-if ( block #if -- block' )
 | 
						|
    ! Inputs to the final instruction need to be copied because of
 | 
						|
    ! loc>vreg sync
 | 
						|
    ds-pop any-rep ^^copy f cc/= ##compare-imm-branch, emit-if ;
 | 
						|
 | 
						|
M: #if emit-node ( block node -- block' )
 | 
						|
    {
 | 
						|
        { [ dup trivial-if? ] [ drop emit-trivial-if ] }
 | 
						|
        { [ dup trivial-not-if? ] [ drop emit-trivial-not-if ] }
 | 
						|
        [ emit-actual-if ]
 | 
						|
    } cond ;
 | 
						|
 | 
						|
M: #dispatch emit-node ( block node -- block' )
 | 
						|
    ! Inputs to the final instruction need to be copied because of
 | 
						|
    ! loc>vreg sync. ^^offset>slot always returns a fresh vreg,
 | 
						|
    ! though.
 | 
						|
    ds-pop ^^offset>slot next-vreg ##dispatch, emit-if ;
 | 
						|
 | 
						|
M: #call emit-node ( block node -- block' )
 | 
						|
    dup word>> dup "intrinsic" word-prop [
 | 
						|
        nip call( block #call -- block' )
 | 
						|
    ] [ swap call-height emit-call ] if* ;
 | 
						|
 | 
						|
M: #call-recursive emit-node ( block node -- block' )
 | 
						|
    [ label>> id>> ] [ call-height ] bi emit-call ;
 | 
						|
 | 
						|
M: #push emit-node ( block node -- block' )
 | 
						|
    literal>> ^^load-literal ds-push ;
 | 
						|
 | 
						|
! #shuffle
 | 
						|
 | 
						|
! Even though low level IR has its own dead code elimination pass,
 | 
						|
! we try not to introduce useless ##peeks here, since this reduces
 | 
						|
! the accuracy of global stack analysis.
 | 
						|
 | 
						|
: make-input-map ( #shuffle -- assoc )
 | 
						|
    [ in-d>> ds-loc ] [ in-r>> rs-loc ] bi
 | 
						|
    [ over length stack-locs zip ] 2bi@ append ;
 | 
						|
 | 
						|
: height-changes ( #shuffle -- height-changes )
 | 
						|
    { [ out-d>> ] [ in-d>> ] [ out-r>> ] [ in-r>> ] } cleave
 | 
						|
    4array [ length ] map first4 [ - ] 2bi@ 2array ;
 | 
						|
 | 
						|
: store-height-changes ( #shuffle -- )
 | 
						|
    height-changes { ds-loc rs-loc } [ new swap >>n inc-stack ] 2each ;
 | 
						|
 | 
						|
: extract-outputs ( #shuffle -- seq )
 | 
						|
    [ out-d>> ds-loc 2array ] [ out-r>> rs-loc 2array ] bi 2array ;
 | 
						|
 | 
						|
: out-vregs/stack ( #shuffle -- seq )
 | 
						|
    [ make-input-map ] [ mapping>> ] [ extract-outputs ] tri
 | 
						|
    [ first2 [ [ of of peek-loc ] 2with map ] dip 2array ] 2with map ;
 | 
						|
 | 
						|
M: #shuffle emit-node ( block node -- block' )
 | 
						|
    [ out-vregs/stack ] keep store-height-changes
 | 
						|
    [ first2 store-vregs ] each ;
 | 
						|
 | 
						|
! #return
 | 
						|
: end-word ( block -- block' )
 | 
						|
    ##branch, begin-basic-block
 | 
						|
    t >>kill-block?
 | 
						|
    ##safepoint, ##epilogue, ##return, ;
 | 
						|
 | 
						|
M: #return emit-node ( block node -- block' )
 | 
						|
    drop end-word ;
 | 
						|
 | 
						|
M: #return-recursive emit-node ( block node -- block' )
 | 
						|
    label>> id>> loops get key? [ ] [ end-word ] if ;
 | 
						|
 | 
						|
! #terminate
 | 
						|
M: #terminate emit-node ( block node -- block' )
 | 
						|
    drop ##no-tco, end-basic-block f ;
 | 
						|
 | 
						|
! No-op nodes
 | 
						|
M: #introduce emit-node drop ;
 | 
						|
 | 
						|
M: #copy emit-node drop ;
 | 
						|
 | 
						|
M: #enter-recursive emit-node drop ;
 | 
						|
 | 
						|
M: #phi emit-node drop ;
 | 
						|
 | 
						|
M: #declare emit-node drop ;
 |