1 ! Copyright (C) 2010 Slava Pestov, 2011 Alex Vondrak.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors combinators kernel math math.order namespaces
4 sequences vectors combinators.short-circuit
7 compiler.cfg.comparisons
8 compiler.cfg.instructions
11 compiler.cfg.gvn.graph
12 compiler.cfg.gvn.avail
13 compiler.cfg.gvn.rewrite ;
14 IN: compiler.cfg.gvn.comparisons
16 ! Optimizations performed here:
18 ! 1) Eliminating intermediate boolean values when the result of
19 ! a comparison is used by a compare-branch
20 ! 2) Folding comparisons where both inputs are literal
21 ! 3) Folding comparisons where both inputs are congruent
22 ! 4) Converting compare instructions into compare-imm instructions
24 : fold-compare-imm? ( insn -- ? )
25 src1>> vreg>insn literal-insn? ;
27 : evaluate-compare-imm ( insn -- ? )
28 [ src1>> vreg>literal ] [ src2>> ] [ cc>> ] tri
34 : fold-compare-integer-imm? ( insn -- ? )
35 src1>> vreg>insn ##load-integer? ;
37 : evaluate-compare-integer-imm ( insn -- ? )
38 [ src1>> vreg>integer ] [ src2>> ] [ cc>> ] tri
39 [ <=> ] dip evaluate-cc ;
41 : fold-test-imm? ( insn -- ? )
42 src1>> vreg>insn ##load-integer? ;
44 : evaluate-test-imm ( insn -- ? )
45 [ src1>> vreg>integer ] [ src2>> ] [ cc>> ] tri
51 : rewrite-into-test? ( insn -- ? )
53 [ drop test-instruction? ]
54 [ cc>> { cc= cc/= } member-eq? ]
58 : >compare< ( insn -- in1 in2 cc )
59 [ src1>> ] [ src2>> ] [ cc>> ] tri ; inline
61 : >test-vector< ( insn -- src1 temp rep vcc )
69 UNION: scalar-compare-insn
76 ##compare-float-unordered
77 ##compare-float-ordered ;
79 UNION: general-compare-insn scalar-compare-insn ##test-vector ;
81 : rewrite-boolean-comparison? ( insn -- ? )
83 [ src1>> vreg>insn [ general-compare-insn? ] with-available-uses? ]
88 : rewrite-boolean-comparison ( insn -- insn )
90 { [ dup ##compare? ] [ >compare< ##compare-branch new-insn ] }
91 { [ dup ##compare-imm? ] [ >compare< ##compare-imm-branch new-insn ] }
92 { [ dup ##compare-integer? ] [ >compare< ##compare-integer-branch new-insn ] }
93 { [ dup ##compare-integer-imm? ] [ >compare< ##compare-integer-imm-branch new-insn ] }
94 { [ dup ##test? ] [ >compare< ##test-branch new-insn ] }
95 { [ dup ##test-imm? ] [ >compare< ##test-imm-branch new-insn ] }
96 { [ dup ##compare-float-unordered? ] [ >compare< ##compare-float-unordered-branch new-insn ] }
97 { [ dup ##compare-float-ordered? ] [ >compare< ##compare-float-ordered-branch new-insn ] }
98 { [ dup ##test-vector? ] [ >test-vector< ##test-vector-branch new-insn ] }
101 : fold-branch ( ? -- insn )
102 final-iteration? get [
104 basic-block get [ nth 1vector ] change-successors drop
108 : fold-compare-imm-branch ( insn -- insn/f )
109 evaluate-compare-imm fold-branch ;
111 : >test-branch ( insn -- insn )
112 [ src1>> ] [ src1>> ] [ cc>> ] tri ##test-branch new-insn ;
114 M: ##compare-imm-branch rewrite
116 { [ dup rewrite-boolean-comparison? ] [ rewrite-boolean-comparison ] }
117 { [ dup fold-compare-imm? ] [ fold-compare-imm-branch ] }
121 : fold-compare-integer-imm-branch ( insn -- insn/f )
122 evaluate-compare-integer-imm fold-branch ;
124 M: ##compare-integer-imm-branch rewrite
126 { [ dup fold-compare-integer-imm? ] [ fold-compare-integer-imm-branch ] }
127 { [ dup rewrite-into-test? ] [ >test-branch ] }
131 : fold-test-imm-branch ( insn -- insn/f )
132 evaluate-test-imm fold-branch ;
134 M: ##test-imm-branch rewrite
136 { [ dup fold-test-imm? ] [ fold-test-imm-branch ] }
140 : swap-compare ( src1 src2 cc swap? -- src1 src2 cc )
141 [ swapd swap-cc ] when ; inline
143 : (>compare-imm-branch) ( insn swap? -- src1 src2 cc )
144 [ [ src1>> ] [ src2>> ] [ cc>> ] tri ] dip swap-compare ; inline
146 : >compare-imm-branch ( insn swap? -- insn' )
147 (>compare-imm-branch)
149 ##compare-imm-branch new-insn ; inline
151 : >compare-integer-imm-branch ( insn swap? -- insn' )
152 (>compare-imm-branch)
154 ##compare-integer-imm-branch new-insn ; inline
156 : evaluate-self-compare ( insn -- ? )
157 cc>> { cc= cc<= cc>= } member-eq? ;
159 : rewrite-self-compare-branch ( insn -- insn' )
160 evaluate-self-compare fold-branch ;
162 M: ##compare-branch rewrite
164 { [ dup src1>> vreg-immediate-comparand? ] [ t >compare-imm-branch ] }
165 { [ dup src2>> vreg-immediate-comparand? ] [ f >compare-imm-branch ] }
166 { [ dup diagonal? ] [ rewrite-self-compare-branch ] }
170 M: ##compare-integer-branch rewrite
172 { [ dup src1>> vreg-immediate-arithmetic? ] [ t >compare-integer-imm-branch ] }
173 { [ dup src2>> vreg-immediate-arithmetic? ] [ f >compare-integer-imm-branch ] }
174 { [ dup diagonal? ] [ rewrite-self-compare-branch ] }
178 : (>compare-imm) ( insn swap? -- dst src1 src2 cc )
179 [ { [ dst>> ] [ src1>> ] [ src2>> ] [ cc>> ] } cleave ] dip
180 swap-compare ; inline
182 : >compare-imm ( insn swap? -- insn' )
185 next-vreg ##compare-imm new-insn ; inline
187 : >compare-integer-imm ( insn swap? -- insn' )
190 next-vreg ##compare-integer-imm new-insn ; inline
192 : >boolean-insn ( insn ? -- insn' )
193 [ dst>> ] dip ##load-reference new-insn ;
195 : rewrite-self-compare ( insn -- insn' )
196 dup evaluate-self-compare >boolean-insn ;
200 { [ dup src1>> vreg-immediate-comparand? ] [ t >compare-imm ] }
201 { [ dup src2>> vreg-immediate-comparand? ] [ f >compare-imm ] }
202 { [ dup diagonal? ] [ rewrite-self-compare ] }
206 M: ##compare-integer rewrite
208 { [ dup src1>> vreg-immediate-arithmetic? ] [ t >compare-integer-imm ] }
209 { [ dup src2>> vreg-immediate-arithmetic? ] [ f >compare-integer-imm ] }
210 { [ dup diagonal? ] [ rewrite-self-compare ] }
214 : rewrite-redundant-comparison? ( insn -- ? )
216 [ src1>> vreg>insn [ scalar-compare-insn? ] with-available-uses? ]
218 [ cc>> { cc= cc/= } member? ]
221 : rewrite-redundant-comparison ( insn -- insn' )
222 [ cc>> ] [ dst>> ] [ src1>> vreg>insn ] tri {
223 { [ dup ##compare? ] [ >compare< next-vreg ##compare new-insn ] }
224 { [ dup ##compare-imm? ] [ >compare< next-vreg ##compare-imm new-insn ] }
225 { [ dup ##compare-integer? ] [ >compare< next-vreg ##compare-integer new-insn ] }
226 { [ dup ##compare-integer-imm? ] [ >compare< next-vreg ##compare-integer-imm new-insn ] }
227 { [ dup ##test? ] [ >compare< next-vreg ##test new-insn ] }
228 { [ dup ##test-imm? ] [ >compare< next-vreg ##test-imm new-insn ] }
229 { [ dup ##compare-float-unordered? ] [ >compare< next-vreg ##compare-float-unordered new-insn ] }
230 { [ dup ##compare-float-ordered? ] [ >compare< next-vreg ##compare-float-ordered new-insn ] }
232 swap cc= eq? [ [ negate-cc ] change-cc ] when ;
234 : fold-compare-imm ( insn -- insn' )
235 dup evaluate-compare-imm >boolean-insn ;
237 M: ##compare-imm rewrite
239 { [ dup rewrite-redundant-comparison? ] [ rewrite-redundant-comparison ] }
240 { [ dup fold-compare-imm? ] [ fold-compare-imm ] }
244 : fold-compare-integer-imm ( insn -- insn' )
245 dup evaluate-compare-integer-imm >boolean-insn ;
247 : >test ( insn -- insn' )
248 { [ dst>> ] [ src1>> ] [ src1>> ] [ cc>> ] [ temp>> ] } cleave
251 M: ##compare-integer-imm rewrite
253 { [ dup fold-compare-integer-imm? ] [ fold-compare-integer-imm ] }
254 { [ dup rewrite-into-test? ] [ >test ] }
258 : simplify-test? ( insn -- ? )
259 src1>> vreg>insn [ ##and? ] with-available-uses? ;
261 : (simplify-test) ( insn -- src1 src2 cc )
262 [ src1>> vreg>insn [ src1>> ] [ src2>> ] bi ] [ cc>> ] bi ; inline
264 : simplify-test ( insn -- insn )
265 [ dst>> ] [ (simplify-test) ] [ temp>> ] tri ##test new-insn ; inline
267 : simplify-test-branch ( insn -- insn )
268 (simplify-test) ##test-branch new-insn ; inline
270 : simplify-test-imm? ( insn -- ? )
271 src1>> vreg>insn [ ##and-imm? ] with-available-uses? ;
273 : (simplify-test-imm) ( insn -- src1 src2 cc )
274 [ src1>> vreg>insn [ src1>> ] [ src2>> ] bi ] [ cc>> ] bi ; inline
276 : simplify-test-imm ( insn -- insn )
277 [ dst>> ] [ (simplify-test-imm) ] [ temp>> ] tri ##test-imm new-insn ; inline
279 : simplify-test-imm-branch ( insn -- insn )
280 (simplify-test-imm) ##test-imm-branch new-insn ; inline
282 : >test-imm ( insn ? -- insn' )
283 (>compare-imm) [ vreg>integer ] dip next-vreg
284 ##test-imm new-insn ; inline
286 : >test-imm-branch ( insn ? -- insn' )
287 (>compare-imm-branch) [ vreg>integer ] dip
288 ##test-imm-branch new-insn ; inline
292 { [ dup src1>> vreg-immediate-comparand? ] [ t >test-imm ] }
293 { [ dup src2>> vreg-immediate-comparand? ] [ f >test-imm ] }
294 { [ dup diagonal? ] [
296 { [ dup simplify-test? ] [ simplify-test ] }
297 { [ dup simplify-test-imm? ] [ simplify-test-imm ] }
304 M: ##test-branch rewrite
306 { [ dup src1>> vreg-immediate-comparand? ] [ t >test-imm-branch ] }
307 { [ dup src2>> vreg-immediate-comparand? ] [ f >test-imm-branch ] }
308 { [ dup diagonal? ] [
310 { [ dup simplify-test? ] [ simplify-test-branch ] }
311 { [ dup simplify-test-imm? ] [ simplify-test-imm-branch ] }
318 : fold-test-imm ( insn -- insn' )
319 dup evaluate-test-imm >boolean-insn ;
321 M: ##test-imm rewrite
323 { [ dup fold-test-imm? ] [ fold-test-imm ] }