1 ! Copyright (C) 2010 Slava Pestov, 2011 Alex Vondrak.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors combinators combinators.short-circuit
4 compiler.cfg.gvn.avail compiler.cfg.gvn.folding
5 compiler.cfg.gvn.graph compiler.cfg.gvn.rewrite
6 compiler.cfg.instructions compiler.cfg.registers
7 compiler.cfg.utilities cpu.architecture kernel layouts make math
9 IN: compiler.cfg.gvn.math
11 : f-insn? ( insn -- ? )
12 { [ ##load-reference? ] [ obj>> not ] } 1&& ; inline
14 : zero-insn? ( insn -- ? )
15 { [ ##load-integer? ] [ val>> 0 = ] } 1&& ; inline
17 M: ##tagged>integer rewrite
18 [ dst>> ] [ src>> vreg>insn ] bi {
19 { [ dup ##load-integer? ] [ val>> tag-fixnum ##load-integer new-insn ] }
20 { [ dup f-insn? ] [ drop \ f type-number ##load-integer new-insn ] }
24 : self-inverse? ( insn quot -- ? )
25 [ src>> vreg>insn ] dip with-available-uses? ; inline
27 : self-inverse ( insn -- insn' )
28 [ dst>> ] [ src>> vreg>insn src>> ] bi <copy> ;
30 : identity ( insn -- insn' )
31 [ dst>> ] [ src1>> ] bi <copy> ;
35 { [ dup [ ##neg? ] self-inverse? ] [ self-inverse ] }
36 { [ dup unary-constant-fold? ] [ unary-constant-fold ] }
42 { [ dup [ ##not? ] self-inverse? ] [ self-inverse ] }
43 { [ dup unary-constant-fold? ] [ unary-constant-fold ] }
47 ! Reassociation converts
51 ! ## *-imm 3 1 (X $ Y)
52 ! If * is associative, then $ is the same operation as *.
53 ! In the case of shifts, $ is addition.
54 : (reassociate) ( insn -- dst src1 src2' src2'' )
57 [ src1>> vreg>insn [ src1>> ] [ src2>> ] bi ]
61 : reassociate ( insn -- dst src1 src2 )
62 [ (reassociate) ] keep binary-constant-fold* ;
64 : ?new-insn ( dst src1 src2 ? class -- insn/f )
65 '[ _ new-insn ] [ 3drop f ] if ; inline
67 : reassociate-arithmetic ( insn new-insn -- insn/f )
68 [ reassociate dup immediate-arithmetic? ] dip ?new-insn ; inline
70 : reassociate-bitwise ( insn new-insn -- insn/f )
71 [ reassociate dup immediate-bitwise? ] dip ?new-insn ; inline
73 : reassociate-shift ( insn new-insn -- insn/f )
74 [ (reassociate) + dup immediate-shift-count? ] dip ?new-insn ; inline
78 { [ dup src2>> 0 = ] [ identity ] }
79 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
80 { [ dup src1>> vreg>insn [ ##add-imm? ] with-available-uses? ] [ ##add-imm reassociate-arithmetic ] }
84 : sub-imm>add-imm ( insn -- insn' )
85 [ dst>> ] [ src1>> ] [ src2>> neg ] tri
86 dup immediate-arithmetic?
89 M: ##sub-imm rewrite sub-imm>add-imm ;
91 ! Convert ##mul-imm -1 => ##neg
92 : mul-to-neg? ( insn -- ? )
95 : mul-to-neg ( insn -- insn' )
96 [ dst>> ] [ src1>> ] bi ##neg new-insn ;
98 ! Convert ##mul-imm 2^X => ##shl-imm X
99 : mul-to-shl? ( insn -- ? )
102 : mul-to-shl ( insn -- insn' )
103 [ [ dst>> ] [ src1>> ] bi ] [ src2>> log2 ] bi ##shl-imm new-insn ;
105 ! Distribution converts
111 ! Where * is mul or shl, + is add or sub
112 ! Have to make sure that X*Y fits in an immediate
113 :: (distribute) ( outer inner imm temp add-op mul-op -- new-outers/f )
114 imm immediate-arithmetic? [
116 temp inner src1>> outer src2>> mul-op execute
117 outer dst>> temp imm add-op execute
121 : distribute-over-add? ( insn -- ? )
122 final-iteration? get [
123 src1>> vreg>insn [ ##add-imm? ] with-available-uses?
126 : distribute-over-sub? ( insn -- ? )
127 final-iteration? get [
128 src1>> vreg>insn [ ##sub-imm? ] with-available-uses?
131 ! XXX next-vreg makes vregs>vns change on every iteration
132 : distribute ( insn add-op mul-op -- new-insns/f )
135 2dup src2>> swap [ src2>> ] keep binary-constant-fold*
137 ] 2dip (distribute) ; inline
141 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
142 { [ dup mul-to-neg? ] [ mul-to-neg ] }
143 { [ dup mul-to-shl? ] [ mul-to-shl ] }
144 { [ dup src1>> vreg>insn [ ##mul-imm? ] with-available-uses? ] [ ##mul-imm reassociate-arithmetic ] }
145 { [ dup distribute-over-add? ] [ \ ##add-imm, \ ##mul-imm, distribute ] }
146 { [ dup distribute-over-sub? ] [ \ ##sub-imm, \ ##mul-imm, distribute ] }
152 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
153 { [ dup src1>> vreg>insn [ ##and-imm? ] with-available-uses? ] [ ##and-imm reassociate-bitwise ] }
154 { [ dup src2>> 0 = ] [ dst>> 0 ##load-integer new-insn ] }
155 { [ dup src2>> -1 = ] [ identity ] }
161 { [ dup src2>> 0 = ] [ identity ] }
162 { [ dup src2>> -1 = ] [ dst>> -1 ##load-integer new-insn ] }
163 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
164 { [ dup src1>> vreg>insn [ ##or-imm? ] with-available-uses? ] [ ##or-imm reassociate-bitwise ] }
170 { [ dup src2>> 0 = ] [ identity ] }
171 { [ dup src2>> -1 = ] [ [ dst>> ] [ src1>> ] bi ##not new-insn ] }
172 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
173 { [ dup src1>> vreg>insn [ ##xor-imm? ] with-available-uses? ] [ ##xor-imm reassociate-bitwise ] }
179 { [ dup src2>> 0 = ] [ identity ] }
180 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
181 { [ dup src1>> vreg>insn [ ##shl-imm? ] with-available-uses? ] [ ##shl-imm reassociate-shift ] }
182 { [ dup distribute-over-add? ] [ \ ##add-imm, \ ##shl-imm, distribute ] }
183 { [ dup distribute-over-sub? ] [ \ ##sub-imm, \ ##shl-imm, distribute ] }
189 { [ dup src2>> 0 = ] [ identity ] }
190 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
191 { [ dup src1>> vreg>insn [ ##shr-imm? ] with-available-uses? ] [ ##shr-imm reassociate-shift ] }
197 { [ dup src2>> 0 = ] [ identity ] }
198 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
199 { [ dup src1>> vreg>insn [ ##sar-imm? ] with-available-uses? ] [ ##sar-imm reassociate-shift ] }
206 ! Where * is an operation with an -imm equivalent into
208 : insn>imm-insn ( insn op swap? -- new-insn )
210 [ [ dst>> ] [ src1>> ] [ src2>> ] tri ] dip
211 [ swap ] when vreg>integer
212 ] dip new-insn ; inline
216 { [ dup src2>> vreg-immediate-arithmetic? ] [ ##add-imm f insn>imm-insn ] }
217 { [ dup src1>> vreg-immediate-arithmetic? ] [ ##add-imm t insn>imm-insn ] }
221 : diagonal? ( insn -- ? )
222 [ src1>> vreg>vn ] [ src2>> vreg>vn ] bi = ; inline
224 ! ##sub 2 1 1 => ##load-integer 2 0
225 : rewrite-subtraction-identity ( insn -- insn' )
226 dst>> 0 ##load-integer new-insn ;
232 : sub-to-neg? ( ##sub -- ? )
233 src1>> vreg>insn zero-insn? ;
235 : sub-to-neg ( ##sub -- insn )
236 [ dst>> ] [ src2>> ] bi ##neg new-insn ;
240 { [ dup sub-to-neg? ] [ sub-to-neg ] }
241 { [ dup diagonal? ] [ rewrite-subtraction-identity ] }
242 { [ dup src2>> vreg-immediate-arithmetic? ] [ ##sub-imm f insn>imm-insn ] }
248 { [ dup src2>> vreg-immediate-arithmetic? ] [ ##mul-imm f insn>imm-insn ] }
249 { [ dup src1>> vreg-immediate-arithmetic? ] [ ##mul-imm t insn>imm-insn ] }
255 { [ dup diagonal? ] [ identity ] }
256 { [ dup src2>> vreg-immediate-bitwise? ] [ ##and-imm f insn>imm-insn ] }
257 { [ dup src1>> vreg-immediate-bitwise? ] [ ##and-imm t insn>imm-insn ] }
263 { [ dup diagonal? ] [ identity ] }
264 { [ dup src2>> vreg-immediate-bitwise? ] [ ##or-imm f insn>imm-insn ] }
265 { [ dup src1>> vreg-immediate-bitwise? ] [ ##or-imm t insn>imm-insn ] }
271 { [ dup diagonal? ] [ dst>> 0 ##load-integer new-insn ] }
272 { [ dup src2>> vreg-immediate-bitwise? ] [ ##xor-imm f insn>imm-insn ] }
273 { [ dup src1>> vreg-immediate-bitwise? ] [ ##xor-imm t insn>imm-insn ] }
279 { [ dup src2>> vreg-immediate-bitwise? ] [ ##shl-imm f insn>imm-insn ] }
285 { [ dup src2>> vreg-immediate-bitwise? ] [ ##shr-imm f insn>imm-insn ] }
291 { [ dup src2>> vreg-immediate-bitwise? ] [ ##sar-imm f insn>imm-insn ] }