1 ! Copyright (C) 2004, 2008 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 stack-checker.inlining
7 compiler.tree.combinators
8 compiler.tree.propagation.info
11 compiler.cfg.templates
16 IN: compiler.cfg.builder
18 ! Convert tree SSA IR to CFG (not quite SSA yet) IR.
20 : set-basic-block ( basic-block -- )
21 [ basic-block set ] [ instructions>> building set ] bi ;
23 : begin-basic-block ( -- )
24 <basic-block> basic-block get [
25 dupd successors>> push
29 : end-basic-block ( -- )
34 FROM: compiler.generator.registers => +input+ ;
35 FROM: compiler.generator.registers => +output+ ;
36 FROM: compiler.generator.registers => +scratch+ ;
37 FROM: compiler.generator.registers => +clobber+ ;
47 ! Basic block after prologue, makes recursion faster
48 SYMBOL: current-label-start
50 : add-procedure ( -- )
51 basic-block get current-word get current-label get
52 <procedure> procedures get push ;
54 : begin-procedure ( word label -- )
62 : with-cfg-builder ( nodes word label quot -- )
63 '[ begin-procedure @ ] with-scope ; inline
65 GENERIC: emit-node ( node -- next )
67 : check-basic-block ( node -- node' )
68 basic-block get [ drop f ] unless ; inline
70 : emit-nodes ( nodes -- )
71 [ current-node emit-node check-basic-block ] iterate-nodes
74 : remember-loop ( label -- )
75 basic-block get swap loops get set-at ;
78 #! We store the basic block after the prologue as a loop
79 #! labelled by the current word, so that self-recursive
80 #! calls can skip an epilogue/prologue.
85 current-label get remember-loop ;
87 : (build-cfg) ( nodes word label -- )
90 [ emit-nodes ] with-node-iterator
93 : build-cfg ( nodes word label -- procedures )
100 : if-intrinsics ( #call -- quot )
101 word>> "if-intrinsics" word-prop ;
103 : local-recursive-call ( basic-block -- )
105 basic-block get successors>> push
108 : emit-call ( word -- next )
111 { [ tail-call? not ] [ 0 %frame-required %call iterate-next ] }
112 { [ dup loops get key? ] [ loops get at local-recursive-call f ] }
113 [ %epilogue %jump f ]
117 : compile-recursive ( node -- next )
118 [ label>> id>> emit-call ]
119 [ [ child>> ] [ label>> word>> ] [ label>> id>> ] tri (build-cfg) ] bi ;
121 : compile-loop ( node -- next )
124 [ label>> id>> remember-loop ] [ child>> emit-nodes ] bi
127 M: #recursive emit-node
128 dup label>> loop?>> [ compile-loop ] [ compile-recursive ] if ;
131 : emit-branch ( nodes -- final-bb )
133 begin-basic-block copy-phantoms
135 basic-block get dup [ %branch ] when
138 : emit-if ( node -- next )
139 children>> [ emit-branch ] map
142 basic-block get '[ [ _ swap successors>> push ] when* ] each
147 { { f "flag" } } lazy-load first %branch-t
151 : dispatch-branch ( nodes word -- label )
156 [ emit-nodes ] with-node-iterator
162 : dispatch-branches ( node -- )
164 current-word get dispatch-branch
168 : emit-dispatch ( node -- )
169 %dispatch dispatch-branches init-phantoms ;
171 M: #dispatch emit-node
172 #! The order here is important, dispatch-branches must
173 #! run after %dispatch, so that each branch gets the
174 #! correct register state
176 emit-dispatch iterate-next
178 current-word get gensym [
187 : define-intrinsics ( word intrinsics -- )
188 "intrinsics" set-word-prop ;
190 : define-intrinsic ( word quot assoc -- )
191 2array 1array define-intrinsics ;
193 : define-if-intrinsics ( word intrinsics -- )
194 [ +input+ associate ] assoc-map
195 "if-intrinsics" set-word-prop ;
197 : define-if-intrinsic ( word quot inputs -- )
198 2array 1array define-if-intrinsics ;
200 : find-intrinsic ( #call -- pair/f )
201 word>> "intrinsics" word-prop find-template ;
203 : find-boolean-intrinsic ( #call -- pair/f )
204 word>> "if-intrinsics" word-prop find-template ;
206 : find-if-intrinsic ( #call -- pair/f )
208 { [ dup length 2 < ] [ 2drop f ] }
209 { [ dup second #if? ] [ drop find-boolean-intrinsic ] }
213 : do-if-intrinsic ( pair -- next )
214 [ %if-intrinsic ] apply-template skip-next emit-if ;
216 : do-boolean-intrinsic ( pair -- next )
218 f alloc-vreg [ %boolean-intrinsic ] keep phantom-push
219 ] apply-template iterate-next ;
221 : do-intrinsic ( pair -- next )
222 [ %intrinsic ] apply-template iterate-next ;
224 : setup-operand-classes ( #call -- )
225 node-input-infos [ class>> ] map set-operand-classes ;
228 dup setup-operand-classes
229 dup find-if-intrinsic [ do-if-intrinsic ] [
230 dup find-boolean-intrinsic [ do-boolean-intrinsic ] [
231 dup find-intrinsic [ do-intrinsic ] [
238 M: #call-recursive emit-node label>> id>> emit-call ;
242 literal>> <constant> phantom-push iterate-next ;
245 M: #shuffle emit-node
246 shuffle-effect phantom-shuffle iterate-next ;
249 [ in-d>> length ] [ out-r>> empty? ] bi
250 [ phantom-drop ] [ phantom->r ] if
254 [ in-r>> length ] [ out-d>> empty? ] bi
255 [ phantom-rdrop ] [ phantom-r> ] if
260 drop finalize-phantoms %epilogue %return f ;
262 M: #return-recursive emit-node
264 label>> id>> loops get key?
265 [ %epilogue %return ] unless f ;
268 M: #terminate emit-node drop end-basic-block f ;
271 M: #alien-invoke emit-node
273 [ alien-invoke-frame %frame-required ]
274 [ %alien-invoke iterate-next ]
277 M: #alien-indirect emit-node
279 [ alien-invoke-frame %frame-required ]
280 [ %alien-indirect iterate-next ]
283 M: #alien-callback emit-node
284 params>> dup xt>> dup
285 [ init-phantoms %alien-callback ] with-cfg-builder
289 M: #introduce emit-node drop iterate-next ;
291 M: #copy emit-node drop iterate-next ;
293 M: #enter-recursive emit-node drop iterate-next ;
295 M: #phi emit-node drop iterate-next ;