1 ! Copyright (C) 2010 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors combinators combinators.short-circuit
4 cpu.architecture fry kernel layouts locals make math sequences
5 compiler.cfg.instructions
8 compiler.cfg.gvn.folding
10 compiler.cfg.gvn.rewrite ;
11 IN: compiler.cfg.gvn.math
13 : f-insn? ( insn -- ? )
14 { [ ##load-reference? ] [ obj>> not ] } 1&& ; inline
16 : zero-insn? ( insn -- ? )
17 { [ ##load-integer? ] [ val>> 0 = ] } 1&& ; inline
19 M: ##tagged>integer rewrite
20 [ dst>> ] [ src>> vreg>insn ] bi {
21 { [ dup ##load-integer? ] [ val>> tag-fixnum \ ##load-integer new-insn ] }
22 { [ dup f-insn? ] [ drop \ f type-number \ ##load-integer new-insn ] }
26 ! XXX src>> vreg>insn src>> not necessarily available
27 : self-inverse ( insn -- insn' )
28 [ dst>> ] [ src>> vreg>insn src>> ] bi <copy> ;
30 : identity ( insn -- insn' )
31 [ dst>> ] [ src1>> ] bi <copy> ;
35 { [ dup src>> vreg>insn ##neg? ] [ self-inverse ] }
36 { [ dup unary-constant-fold? ] [ unary-constant-fold ] }
42 { [ dup src>> vreg>insn ##not? ] [ 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? ] [ \ ##add-imm reassociate-arithmetic ] }
84 : sub-imm>add-imm ( insn -- insn' )
85 [ dst>> ] [ src1>> ] [ src2>> neg ] tri
86 dup immediate-arithmetic?
87 \ ##add-imm ?new-insn ;
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 ! XXX not sure if availability is an issue
106 ! Distribution converts
112 ! Where * is mul or shl, + is add or sub
113 ! Have to make sure that X*Y fits in an immediate
114 :: (distribute) ( outer inner imm temp add-op mul-op -- new-outers/f )
115 imm immediate-arithmetic? [
117 temp inner src1>> outer src2>> mul-op execute
118 outer dst>> temp imm add-op execute
122 : distribute-over-add? ( insn -- ? )
123 src1>> vreg>insn ##add-imm? ;
125 : distribute-over-sub? ( insn -- ? )
126 src1>> vreg>insn ##sub-imm? ;
128 : distribute ( insn add-op mul-op -- new-insns/f )
131 2dup src2>> swap [ src2>> ] keep binary-constant-fold*
133 ] 2dip (distribute) ; inline
137 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
138 { [ dup mul-to-neg? ] [ mul-to-neg ] }
139 { [ dup mul-to-shl? ] [ mul-to-shl ] }
140 { [ dup src1>> vreg>insn ##mul-imm? ] [ \ ##mul-imm reassociate-arithmetic ] }
141 { [ dup distribute-over-add? ] [ \ ##add-imm \ ##mul-imm distribute ] }
142 { [ dup distribute-over-sub? ] [ \ ##sub-imm \ ##mul-imm distribute ] }
148 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
149 { [ dup src1>> vreg>insn ##and-imm? ] [ \ ##and-imm reassociate-bitwise ] }
150 { [ dup src2>> 0 = ] [ dst>> 0 \ ##load-integer new-insn ] }
151 { [ dup src2>> -1 = ] [ identity ] }
157 { [ dup src2>> 0 = ] [ identity ] }
158 { [ dup src2>> -1 = ] [ dst>> -1 \ ##load-integer new-insn ] }
159 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
160 { [ dup src1>> vreg>insn ##or-imm? ] [ \ ##or-imm reassociate-bitwise ] }
166 { [ dup src2>> 0 = ] [ identity ] }
167 { [ dup src2>> -1 = ] [ [ dst>> ] [ src1>> ] bi \ ##not new-insn ] }
168 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
169 { [ dup src1>> vreg>insn ##xor-imm? ] [ \ ##xor-imm reassociate-bitwise ] }
175 { [ dup src2>> 0 = ] [ identity ] }
176 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
177 { [ dup src1>> vreg>insn ##shl-imm? ] [ \ ##shl-imm reassociate-shift ] }
178 { [ dup distribute-over-add? ] [ \ ##add-imm \ ##shl-imm distribute ] }
179 { [ dup distribute-over-sub? ] [ \ ##sub-imm \ ##shl-imm distribute ] }
185 { [ dup src2>> 0 = ] [ identity ] }
186 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
187 { [ dup src1>> vreg>insn ##shr-imm? ] [ \ ##shr-imm reassociate-shift ] }
193 { [ dup src2>> 0 = ] [ identity ] }
194 { [ dup binary-constant-fold? ] [ binary-constant-fold ] }
195 { [ dup src1>> vreg>insn ##sar-imm? ] [ \ ##sar-imm reassociate-shift ] }
202 ! Where * is an operation with an -imm equivalent into
204 : insn>imm-insn ( insn op swap? -- new-insn )
206 [ [ dst>> ] [ src1>> ] [ src2>> ] tri ] dip
207 [ swap ] when vreg>integer
208 ] dip new-insn ; inline
212 { [ dup src2>> vreg-immediate-arithmetic? ] [ \ ##add-imm f insn>imm-insn ] }
213 { [ dup src1>> vreg-immediate-arithmetic? ] [ \ ##add-imm t insn>imm-insn ] }
217 : diagonal? ( insn -- ? )
218 [ src1>> vreg>vn ] [ src2>> vreg>vn ] bi = ; inline
220 ! ##sub 2 1 1 => ##load-integer 2 0
221 : rewrite-subtraction-identity ( insn -- insn' )
222 dst>> 0 \ ##load-integer new-insn ;
228 : sub-to-neg? ( ##sub -- ? )
229 src1>> vreg>insn zero-insn? ;
231 : sub-to-neg ( ##sub -- insn )
232 [ dst>> ] [ src2>> ] bi \ ##neg new-insn ;
236 { [ dup sub-to-neg? ] [ sub-to-neg ] }
237 { [ dup diagonal? ] [ rewrite-subtraction-identity ] }
238 { [ dup src2>> vreg-immediate-arithmetic? ] [ \ ##sub-imm f insn>imm-insn ] }
244 { [ dup src2>> vreg-immediate-arithmetic? ] [ \ ##mul-imm f insn>imm-insn ] }
245 { [ dup src1>> vreg-immediate-arithmetic? ] [ \ ##mul-imm t insn>imm-insn ] }
251 { [ dup diagonal? ] [ identity ] }
252 { [ dup src2>> vreg-immediate-bitwise? ] [ \ ##and-imm f insn>imm-insn ] }
253 { [ dup src1>> vreg-immediate-bitwise? ] [ \ ##and-imm t insn>imm-insn ] }
259 { [ dup diagonal? ] [ identity ] }
260 { [ dup src2>> vreg-immediate-bitwise? ] [ \ ##or-imm f insn>imm-insn ] }
261 { [ dup src1>> vreg-immediate-bitwise? ] [ \ ##or-imm t insn>imm-insn ] }
267 { [ dup diagonal? ] [ dst>> 0 \ ##load-integer new-insn ] }
268 { [ dup src2>> vreg-immediate-bitwise? ] [ \ ##xor-imm f insn>imm-insn ] }
269 { [ dup src1>> vreg-immediate-bitwise? ] [ \ ##xor-imm t insn>imm-insn ] }
275 { [ dup src2>> vreg-immediate-bitwise? ] [ \ ##shl-imm f insn>imm-insn ] }
281 { [ dup src2>> vreg-immediate-bitwise? ] [ \ ##shr-imm f insn>imm-insn ] }
287 { [ dup src2>> vreg-immediate-bitwise? ] [ \ ##sar-imm f insn>imm-insn ] }