1 ! Copyright (C) 2005, 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
4 USING: alien alien.accessors arrays generic hashtables kernel
5 assocs math math.private kernel.private sequences words parser
6 inference.class inference.dataflow vectors strings sbufs io
7 namespaces assocs quotations math.intervals sequences.private
8 combinators splitting layouts math.parser classes
9 classes.algebra generic.math optimizer.pattern-match
10 optimizer.backend optimizer.def-use optimizer.inlining
11 optimizer.math.partial generic.standard system accessors ;
13 : define-math-identities ( word identities -- )
14 >r all-derived-ops r> define-identities ;
17 { { @ @ } [ 2drop t ] }
18 } define-math-identities
21 { { number 0 } [ drop ] }
22 { { 0 number } [ nip ] }
23 } define-math-identities
26 { { number 0 } [ drop ] }
27 { { @ @ } [ 2drop 0 ] }
28 } define-math-identities
31 { { @ @ } [ 2drop f ] }
32 } define-math-identities
35 { { @ @ } [ 2drop t ] }
36 } define-math-identities
39 { { @ @ } [ 2drop f ] }
40 } define-math-identities
43 { { @ @ } [ 2drop t ] }
44 } define-math-identities
47 { { number 1 } [ drop ] }
48 { { 1 number } [ nip ] }
49 { { number 0 } [ nip ] }
50 { { 0 number } [ drop ] }
51 { { number -1 } [ drop 0 swap - ] }
52 { { -1 number } [ nip 0 swap - ] }
53 } define-math-identities
56 { { number 1 } [ drop ] }
57 { { number -1 } [ drop 0 swap - ] }
58 } define-math-identities
61 { { integer 1 } [ 2drop 0 ] }
62 } define-math-identities
65 { { integer 1 } [ 2drop 0 ] }
66 } define-math-identities
69 { { number -1 } [ drop ] }
70 { { -1 number } [ nip ] }
72 { { number 0 } [ nip ] }
73 { { 0 number } [ drop ] }
74 } define-math-identities
77 { { number 0 } [ drop ] }
78 { { 0 number } [ nip ] }
80 { { number -1 } [ nip ] }
81 { { -1 number } [ drop ] }
82 } define-math-identities
85 { { number 0 } [ drop ] }
86 { { 0 number } [ nip ] }
87 { { number -1 } [ drop bitnot ] }
88 { { -1 number } [ nip bitnot ] }
89 { { @ @ } [ 2drop 0 ] }
90 } define-math-identities
93 { { 0 number } [ drop ] }
94 { { number 0 } [ drop ] }
95 } define-math-identities
97 : math-closure ( class -- newclass )
98 { null fixnum bignum integer rational float real number }
99 [ class<= ] with find nip number or ;
101 : fits? ( interval class -- ? )
102 "interval" word-prop dup
103 [ interval-subset? ] [ 2drop t ] if ;
105 : math-output-class ( node upgrades -- newclass )
107 in-d>> null [ value-class* math-closure math-class-max ] reduce
110 : won't-overflow? ( interval node -- ? )
111 node-in-d [ value-class* fixnum class<= ] all?
112 swap fixnum fits? and ;
114 : post-process ( class interval node -- classes intervals )
116 [ >r dup { f integer } member? [ drop fixnum ] when r> ] when
117 [ dup [ 1array ] when ] bi@ ;
119 : math-output-interval-1 ( node word -- interval )
121 >r node-in-d first value-interval* dup
122 [ r> execute ] [ r> 2drop f ] if
127 : math-output-class/interval-1 ( node word -- classes intervals )
128 [ drop { } math-output-class 1array ]
129 [ math-output-interval-1 1array ] 2bi ;
132 { bitnot interval-bitnot }
133 { fixnum-bitnot interval-bitnot }
134 { bignum-bitnot interval-bitnot }
136 [ math-output-class/interval-1 ] curry
137 "output-classes" set-word-prop
140 : intervals ( node -- i1 i2 )
141 node-in-d first2 [ value-interval* ] bi@ ;
143 : math-output-interval-2 ( node word -- interval )
145 >r intervals 2dup and [ r> execute ] [ r> 3drop f ] if
150 : math-output-class/interval-2 ( node upgrades word -- classes intervals )
153 math-output-interval-2
154 >r math-output-class r>
155 r> post-process ; inline
158 { + { { fixnum integer } } interval+ }
159 { - { { fixnum integer } } interval- }
160 { * { { fixnum integer } } interval* }
161 { / { { fixnum rational } { integer rational } } interval/ }
162 { /i { { fixnum integer } } interval/i }
163 { shift { { fixnum integer } } interval-shift-safe }
167 math-output-class/interval-2
168 ] 2curry "output-classes" set-word-prop
169 ] 2curry each-derived-op
172 : real-value? ( value -- n ? )
173 dup value? [ value-literal dup real? ] [ drop f f ] if ;
175 : mod-range ( n -- interval )
178 : rem-range ( n -- interval )
181 : bitand-range ( n -- interval )
182 dup 0 < [ drop f ] [ 0 swap [a,b] ] if ;
184 : math-output-interval-special ( node word -- interval )
186 >r node-in-d second real-value?
187 [ r> execute ] [ r> 2drop f ] if
192 : math-output-class/interval-special ( node min word -- classes intervals )
195 math-output-interval-special
196 >r math-output-class r>
197 r> post-process ; inline
200 { mod { } mod-range }
201 { rem { { fixnum integer } } rem-range }
203 { bitand { } bitand-range }
209 math-output-class/interval-special
210 ] 2curry "output-classes" set-word-prop
211 ] 2curry each-derived-op
214 : twiddle-interval ( i1 -- i2 )
217 [ value-class* integer class<= ] all?
218 [ integral-closure ] when
221 : (comparison-constraints) ( i1 i2 word class -- )
223 >r execute twiddle-interval 0 `input interval,
225 ] set-constraints ; inline
227 : comparison-constraints ( node true false -- )
228 >r >r dup node set intervals dup [
230 r> \ f class-not (comparison-constraints)
231 r> \ f (comparison-constraints)
237 { < assume< assume>= }
238 { <= assume<= assume> }
239 { > assume> assume<= }
240 { >= assume>= assume< }
244 [ comparison-constraints ] with-scope
245 ] 2curry "constraints" set-word-prop
246 ] 2curry each-derived-op
261 [ "alien-signed-" ?head ]
262 [ string>number 8 * 1- 2^ dup neg swap 1- [a,b] ]
265 [ "alien-unsigned-" ?head ]
266 [ string>number 8 * 2^ 1- 0 swap [a,b] ]
269 [ nip f swap ] curry "output-classes" set-word-prop
272 ! Associate intervals to classes
274 most-negative-fixnum most-positive-fixnum [a,b]
275 "interval" set-word-prop
278 0 max-array-capacity [a,b]
279 "interval" set-word-prop
287 over node-in-d first value-interval*
288 dup pick fits? [ drop f ] unless
290 ] curry "output-classes" set-word-prop
293 ! Removing overflow checks
294 : remove-overflow-check? ( #call -- ? )
295 dup out-d>> first node-class
296 [ fixnum class<= ] [ null eq? not ] bi and ;
299 { + [ fixnum+fast ] }
300 { +-integer-fixnum [ fixnum+fast ] }
301 { - [ fixnum-fast ] }
302 { * [ fixnum*fast ] }
303 { *-integer-fixnum [ fixnum*fast ] }
304 { shift [ fixnum-shift-fast ] }
305 { fixnum+ [ fixnum+fast ] }
306 { fixnum- [ fixnum-fast ] }
307 { fixnum* [ fixnum*fast ] }
308 { fixnum-shift [ fixnum-shift-fast ] }
311 [ dup remove-overflow-check? ] ,
312 [ f splice-quot ] curry ,
313 ] { } make 1array define-optimizers
316 ! Remove redundant comparisons
317 : intervals-first2 ( #call -- first second )
318 dup dup node-in-d first node-interval
319 swap dup node-in-d second node-interval ;
321 : known-comparison? ( #call -- ? )
322 intervals-first2 and ;
324 : perform-comparison ( #call word -- result )
325 >r intervals-first2 r> execute ; inline
327 : foldable-comparison? ( #call word -- ? )
328 >r dup known-comparison? [
329 r> perform-comparison incomparable eq? not
334 : fold-comparison ( #call word -- node )
335 dupd perform-comparison 1array inline-literals ;
345 dup [ dupd foldable-comparison? ] curry ,
346 [ fold-comparison ] curry ,
347 ] { } make 1array define-optimizers
348 ] curry each-derived-op
351 ! The following words are handled in a similar way except if
352 ! the only consumer is a >fixnum we remove the overflow check
354 : consumed-by? ( node word -- ? )
356 dup #call? [ node-param eq? ] [ 2drop f ] if ;
358 : coerced-to-fixnum? ( #call -- ? )
359 dup dup node-in-d [ node-class integer class<= ] with all?
360 [ \ >fixnum consumed-by? ] [ drop f ] if ;
363 { + [ [ >fixnum ] bi@ fixnum+fast ] }
364 { - [ [ >fixnum ] bi@ fixnum-fast ] }
365 { * [ [ >fixnum ] bi@ fixnum*fast ] }
370 dup remove-overflow-check?
371 over coerced-to-fixnum? or
373 [ f splice-quot ] curry ,
374 ] { } make 1array define-optimizers
378 : convert-rem-to-and? ( #call -- ? )
380 { [ 2dup first node-class integer class<= not ] [ f ] }
381 { [ 2dup second node-literal integer? not ] [ f ] }
382 { [ 2dup second node-literal power-of-2? not ] [ f ] }
386 : convert-mod-to-and? ( #call -- ? )
387 dup dup node-in-d first node-interval 0 [a,inf] interval-subset?
388 [ convert-rem-to-and? ] [ drop f ] if ;
390 : convert-mod-to-and ( #call -- node )
392 dup node-in-d second node-literal 1-
393 [ nip bitand ] curry f splice-quot ;
398 [ dup convert-mod-to-and? ]
399 [ convert-mod-to-and ]
406 [ dup convert-rem-to-and? ]
407 [ convert-mod-to-and ]
411 : fixnumify-bitand? ( #call -- ? )
412 dup node-in-d second node-interval fixnum fits? ;
414 : fixnumify-bitand ( #call -- node )
415 [ [ >fixnum ] bi@ fixnum-bitand ] f splice-quot ;
419 [ dup fixnumify-bitand? ]