1 ! Copyright (C) 2004, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs combinators hashtables kernel
4 math fry namespaces make sequences words byte-arrays
6 stack-checker.inlining cpu.architecture
9 compiler.tree.combinators
10 compiler.tree.propagation.info
13 compiler.cfg.utilities
14 compiler.cfg.registers
15 compiler.cfg.intrinsics
16 compiler.cfg.comparisons
17 compiler.cfg.stack-frame
18 compiler.cfg.instructions
19 compiler.cfg.predecessors
20 compiler.cfg.builder.blocks
22 compiler.cfg.stacks.local
24 IN: compiler.cfg.builder
26 ! Convert tree SSA IR to CFG IR. The result is not in SSA form; this is
27 ! constructed later by calling compiler.cfg.ssa.construction:construct-ssa.
32 : begin-cfg ( word label -- cfg )
35 [ basic-block get ] 2dip <cfg> dup cfg set ;
37 : begin-procedure ( word label -- )
38 begin-cfg procedures get push ;
40 : with-cfg-builder ( nodes word label quot -- )
48 : with-dummy-cfg-builder ( node quot -- )
50 [ V{ } clone procedures ] 2dip
51 '[ _ t t [ _ call( node -- ) ] with-cfg-builder ] with-variable
54 GENERIC: emit-node ( node -- )
56 : emit-nodes ( nodes -- )
57 [ basic-block get [ emit-node ] [ drop ] if ] each ;
64 : (build-cfg) ( nodes word label -- )
70 : build-cfg ( nodes word -- procedures )
77 : emit-loop-call ( basic-block -- )
79 basic-block get successors>> push
82 : emit-call ( word height -- )
84 [ drop loops get at emit-loop-call ]
85 [ [ [ ##call ] [ adjust-d ] bi* ] emit-trivial-block ]
89 : recursive-height ( #recursive -- n )
90 [ label>> return>> in-d>> length ] [ in-d>> length ] bi - ;
92 : emit-recursive ( #recursive -- )
93 [ [ label>> id>> ] [ recursive-height ] bi emit-call ]
94 [ [ child>> ] [ label>> word>> ] [ label>> id>> ] tri (build-cfg) ] bi ;
96 : remember-loop ( label -- )
97 basic-block get swap loops get set-at ;
99 : emit-loop ( node -- )
102 [ label>> id>> remember-loop ] [ child>> emit-nodes ] bi ;
104 M: #recursive emit-node
105 dup label>> loop?>> [ emit-loop ] [ emit-recursive ] if ;
108 : emit-branch ( obj -- final-bb )
109 [ emit-nodes ] with-branch ;
111 : emit-if ( node -- )
112 children>> [ emit-branch ] map emit-conditional ;
114 : trivial-branch? ( nodes -- value ? )
116 first dup #push? [ literal>> t ] [ drop f f ] if
119 : trivial-if? ( #if -- ? )
121 [ trivial-branch? [ t eq? ] when ]
122 [ trivial-branch? [ f eq? ] when ] bi*
125 : emit-trivial-if ( -- )
126 ds-pop \ f type-number cc/= ^^compare-imm ds-push ;
128 : trivial-not-if? ( #if -- ? )
130 [ trivial-branch? [ f eq? ] when ]
131 [ trivial-branch? [ t eq? ] when ] bi*
134 : emit-trivial-not-if ( -- )
135 ds-pop \ f type-number cc= ^^compare-imm ds-push ;
137 : emit-actual-if ( #if -- )
138 ! Inputs to the final instruction need to be copied because of
140 ds-pop any-rep ^^copy \ f type-number cc/= ##compare-imm-branch emit-if ;
144 { [ dup trivial-if? ] [ drop emit-trivial-if ] }
145 { [ dup trivial-not-if? ] [ drop emit-trivial-not-if ] }
150 M: #dispatch emit-node
151 ! Inputs to the final instruction need to be copied because of
152 ! loc>vreg sync. ^^offset>slot always returns a fresh vreg,
154 ds-pop ^^offset>slot next-vreg ##dispatch emit-if ;
158 dup word>> dup "intrinsic" word-prop
159 [ emit-intrinsic ] [ swap call-height emit-call ] if ;
162 M: #call-recursive emit-node [ label>> id>> ] [ call-height ] bi emit-call ;
166 literal>> ^^load-literal ds-push ;
170 ! Even though low level IR has its own dead code elimination pass,
171 ! we try not to introduce useless ##peeks here, since this reduces
172 ! the accuracy of global stack analysis.
174 : make-input-map ( #shuffle -- assoc )
175 ! Assoc maps high-level IR values to stack locations.
177 [ in-d>> <reversed> [ <ds-loc> swap set ] each-index ]
178 [ in-r>> <reversed> [ <rs-loc> swap set ] each-index ] bi
181 : make-output-seq ( values mapping input-map -- vregs )
182 '[ _ at _ at peek-loc ] map ;
184 : load-shuffle ( #shuffle mapping input-map -- ds-vregs rs-vregs )
185 [ [ out-d>> ] 2dip make-output-seq ]
186 [ [ out-r>> ] 2dip make-output-seq ] 3bi ;
188 : store-shuffle ( #shuffle ds-vregs rs-vregs -- )
189 [ [ in-d>> length neg inc-d ] dip ds-store ]
190 [ [ in-r>> length neg inc-r ] dip rs-store ]
193 M: #shuffle emit-node
194 dup dup [ mapping>> ] [ make-input-map ] bi load-shuffle store-shuffle ;
198 ##branch begin-basic-block ##epilogue ##return ;
200 M: #return emit-node drop emit-return ;
202 M: #return-recursive emit-node
203 label>> id>> loops get key? [ emit-return ] unless ;
206 M: #terminate emit-node drop ##no-tco end-basic-block ;
209 : return-size ( ctype -- n )
210 #! Amount of space we reserve for a return value.
212 { [ dup c-struct? not ] [ drop 0 ] }
213 { [ dup large-struct? not ] [ drop 2 cells ] }
217 : <alien-stack-frame> ( params -- stack-frame )
220 [ return>> return-size >>return ]
221 [ alien-parameters parameter-offsets drop >>params ] bi
224 : alien-node-height ( params -- )
225 [ out-d>> length ] [ in-d>> length ] bi - adjust-d ;
227 : emit-alien-node ( node quot -- )
229 [ params>> dup dup <alien-stack-frame> ] dip call
231 ] emit-trivial-block ; inline
233 M: #alien-invoke emit-node
234 [ ##alien-invoke ] emit-alien-node ;
236 M: #alien-indirect emit-node
237 [ ##alien-indirect ] emit-alien-node ;
239 M: #alien-callback emit-node
240 dup params>> xt>> dup
243 dup [ ##alien-callback ] emit-alien-node
245 params>> ##callback-return
249 M: #introduce emit-node drop ;
251 M: #copy emit-node drop ;
253 M: #enter-recursive emit-node drop ;
255 M: #phi emit-node drop ;
257 M: #declare emit-node drop ;