1 ! Copyright (C) 2008, 2010 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: kernel math namespaces assocs hashtables sequences arrays
4 accessors words vectors combinators combinators.short-circuit
5 sets classes layouts fry locals cpu.architecture
10 compiler.cfg.utilities
11 compiler.cfg.comparisons
12 compiler.cfg.instructions
13 compiler.cfg.representations.preferred ;
14 FROM: namespaces => set ;
15 IN: compiler.cfg.alias-analysis
17 ! We try to eliminate redundant slot operations using some
20 ! All heap-allocated objects which are loaded from the stack, or
21 ! other object slots are pessimistically assumed to belong to
22 ! the same alias class.
24 ! Freshly-allocated objects get their own alias class.
26 ! Simple pseudo-C example showing load elimination:
28 ! int *x, *y, z: inputs
29 ! int a, b, c, d, e: locals
31 ! Before alias analysis:
41 ! After alias analysis:
44 ! b = a /* ELIMINATED */
47 ! d = x[2] /* if x=y, d=z, if x!=y, d=b; NOT ELIMINATED */
48 ! e = z /* ELIMINATED */
49 ! f = c /* ELIMINATED */
51 ! Simple pseudo-C example showing store elimination:
53 ! Before alias analysis:
62 ! After alias analysis:
64 ! x[0] = a /* dead if n = 0, live otherwise; NOT ELIMINATED */
67 ! /* x[1] = d */ /* ELIMINATED */
71 ! Local copy propagation
74 : resolve ( vreg -- vreg ) copies get ?at drop ;
76 : record-copy ( ##copy -- )
77 [ src>> resolve ] [ dst>> ] bi copies get set-at ; inline
79 ! Map vregs -> alias classes
82 ! Map alias classes -> sequence of vregs
85 ! Alias class for objects which are loaded from the data stack
86 ! or other object slots. We pessimistically assume that they
87 ! can all alias each other.
90 : ac>vregs ( ac -- vregs )
91 acs>vregs get [ drop V{ } clone ] cache ;
93 : vreg>ac ( vreg -- ac )
94 #! Only vregs produced by ##allot, ##peek and ##slot can
95 #! ever be used as valid inputs to ##slot and ##set-slot,
96 #! so we assert this fact by not giving alias classes to
98 vregs>acs get [ heap-ac get [ ac>vregs push ] keep ] cache ;
100 : aliases ( vreg -- vregs )
101 #! All vregs which may contain the same value as vreg.
104 : each-alias ( vreg quot -- )
105 [ aliases ] dip each ; inline
107 : merge-acs ( vreg into -- )
111 [ vregs>acs get '[ [ _ ] dip _ set-at ] each ]
112 [ ac>vregs push-all ]
116 ! Map vregs -> slot# -> vreg
119 ! Maps vreg -> slot# -> insn# of last store or f
120 SYMBOL: recent-stores
122 ! A set of insn#s of dead stores
125 : dead-store ( insn# -- ) dead-stores get adjoin ;
127 ERROR: vreg-not-new vreg ;
129 :: set-ac ( vreg ac -- )
130 #! Set alias class of newly-seen vreg.
131 vreg vregs>acs get key? [ vreg vreg-not-new ] when
132 ac vreg vregs>acs get set-at
133 vreg ac ac>vregs push ;
135 : live-slot ( slot#/f vreg -- vreg' )
136 #! If the slot number is unknown, we never reuse a previous
138 over [ live-slots get at at ] [ 2drop f ] if ;
140 : load-constant-slot ( value slot# vreg -- )
141 live-slots get [ drop H{ } clone ] cache set-at ;
143 : load-slot ( value slot#/f vreg -- )
144 over [ load-constant-slot ] [ 3drop ] if ;
146 : record-constant-slot ( slot# vreg -- )
147 #! A load can potentially read every store of this slot#
148 #! in that alias class.
149 [ recent-stores get at delete-at ] with each-alias ;
151 : record-computed-slot ( vreg -- )
152 #! Computed load is like a load of every slot touched so far
153 [ recent-stores get at clear-assoc ] each-alias ;
155 :: remember-slot ( value slot# vreg -- )
157 slot# vreg record-constant-slot
158 value slot# vreg load-constant-slot
159 ] [ vreg record-computed-slot ] if ;
164 ac-counter [ dup 1 + ] change ;
166 : set-new-ac ( vreg -- ) next-ac set-ac ;
168 : kill-constant-set-slot ( slot# vreg -- )
169 [ live-slots get at delete-at ] with each-alias ;
171 : recent-stores-of ( vreg -- assoc )
172 recent-stores get [ drop H{ } clone ] cache ;
174 :: record-constant-set-slot ( insn# slot# vreg -- )
175 vreg recent-stores-of :> recent-stores
176 slot# recent-stores at [ dead-store ] when*
177 insn# slot# recent-stores set-at ;
179 : kill-computed-set-slot ( vreg -- )
180 [ live-slots get at clear-assoc ] each-alias ;
182 :: remember-set-slot ( insn# slot# vreg -- )
184 insn# slot# vreg record-constant-set-slot
185 slot# vreg kill-constant-set-slot
186 ] [ vreg kill-computed-set-slot ] if ;
188 : init-alias-analysis ( -- )
189 H{ } clone vregs>acs set
190 H{ } clone acs>vregs set
191 H{ } clone live-slots set
192 H{ } clone copies set
193 H{ } clone recent-stores set
194 HS{ } clone dead-stores set
197 GENERIC: insn-slot# ( insn -- slot#/f )
198 GENERIC: insn-object ( insn -- vreg )
200 M: ##slot insn-slot# drop f ;
201 M: ##slot-imm insn-slot# slot>> ;
202 M: ##set-slot insn-slot# drop f ;
203 M: ##set-slot-imm insn-slot# slot>> ;
204 M: ##alien-global insn-slot# [ library>> ] [ symbol>> ] bi 2array ;
205 M: ##vm-field insn-slot# offset>> ;
206 M: ##set-vm-field insn-slot# offset>> ;
208 M: ##slot insn-object obj>> resolve ;
209 M: ##slot-imm insn-object obj>> resolve ;
210 M: ##set-slot insn-object obj>> resolve ;
211 M: ##set-slot-imm insn-object obj>> resolve ;
212 M: ##alien-global insn-object drop ##alien-global ;
213 M: ##vm-field insn-object drop ##vm-field ;
214 M: ##set-vm-field insn-object drop ##vm-field ;
216 GENERIC: analyze-aliases ( insn -- insn' )
218 M: insn analyze-aliases ;
220 : def-acs ( insn -- insn' )
221 ! If an instruction defines a value with a non-integer
222 ! representation it means that the value will be boxed
223 ! anywhere its used as a tagged pointer. Boxing allocates
224 ! a new value, except boxing instructions haven't been
227 { int-rep tagged-rep } member?
228 [ drop ] [ set-new-ac ] if
231 M: vreg-insn analyze-aliases
234 M: ##allocation analyze-aliases
235 #! A freshly allocated object is distinct from any other
237 dup dst>> set-new-ac ;
239 M: ##box-displaced-alien analyze-aliases
241 [ base>> heap-ac get merge-acs ] bi ;
243 M: ##read analyze-aliases
245 dup [ dst>> ] [ insn-slot# ] [ insn-object ] tri
247 [ 2nip <copy> analyze-aliases nip ]
248 [ drop remember-slot ]
251 : idempotent? ( value slot#/f vreg -- ? )
252 #! Are we storing a value back to the same slot it was read
256 M:: ##write analyze-aliases ( insn -- insn )
257 insn src>> resolve :> src
258 insn insn-slot# :> slot#
259 insn insn-object :> vreg
260 insn insn#>> :> insn#
262 src slot# vreg idempotent? [ insn# dead-store ] [
263 src heap-ac get merge-acs
264 insn insn#>> slot# vreg remember-set-slot
265 src slot# vreg load-slot
270 M: ##copy analyze-aliases
271 #! The output vreg gets the same alias class as the input
272 #! vreg, since they both contain the same value.
275 : useless-compare? ( insn -- ? )
278 [ [ src1>> ] [ src2>> ] bi [ resolve vreg>ac ] bi@ = not ]
281 M: ##compare analyze-aliases
283 dup useless-compare? [
284 dst>> f ##load-reference new-insn
288 : clear-live-slots ( -- )
289 heap-ac get ac>vregs [ live-slots get at clear-assoc ] each ;
291 : clear-recent-stores ( -- )
292 recent-stores get values [ clear-assoc ] each ;
294 M: gc-map-insn analyze-aliases
295 ! Can't use call-next-method here because of a limitation, gah
297 clear-recent-stores ;
299 M: factor-call-insn analyze-aliases
304 GENERIC: eliminate-dead-stores ( insn -- ? )
306 M: ##set-slot-imm eliminate-dead-stores
307 insn#>> dead-stores get in? not ;
309 M: insn eliminate-dead-stores drop t ;
311 : reset-alias-analysis ( -- )
312 recent-stores get clear-assoc
313 vregs>acs get clear-assoc
314 acs>vregs get clear-assoc
315 live-slots get clear-assoc
316 copies get clear-assoc
317 dead-stores get table>> clear-assoc
320 ##vm-field set-new-ac
321 ##alien-global set-new-ac ;
323 : alias-analysis-step ( insns -- insns' )
325 [ 0 [ [ insn#<< ] [ drop 1 + ] 2bi ] reduce drop ]
326 [ [ analyze-aliases ] map! [ eliminate-dead-stores ] filter! ] bi ;
328 : alias-analysis ( cfg -- cfg )
330 dup [ alias-analysis-step ] simple-optimization ;