1 ! Copyright (C) 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: kernel effects accessors math math.private
4 math.integers.private math.partial-dispatch math.intervals
5 math.parser math.order layouts words sequences sequences.private
6 arrays assocs classes classes.algebra combinators generic.math
7 splitting fry locals classes.tuple alien.accessors
8 classes.tuple.private slots.private definitions strings.private
9 vectors hashtables generic quotations
11 compiler.tree.comparisons
12 compiler.tree.propagation.info
13 compiler.tree.propagation.nodes
14 compiler.tree.propagation.slots
15 compiler.tree.propagation.simple
16 compiler.tree.propagation.constraints
17 compiler.tree.propagation.call-effect ;
18 IN: compiler.tree.propagation.known-words
21 most-negative-fixnum most-positive-fixnum [a,b]
22 "interval" set-word-prop
25 0 max-array-capacity [a,b]
26 "interval" set-word-prop
29 [ { number number } "input-classes" set-word-prop ] each
32 [ { real real } "input-classes" set-word-prop ] each
35 [ { rational rational } "input-classes" set-word-prop ] each
37 { bitand bitor bitxor bitnot shift }
38 [ { integer integer } "input-classes" set-word-prop ] each
40 \ bitnot { integer } "input-classes" set-word-prop
42 : ?change-interval ( info quot -- quot' )
43 over interval>> [ [ clone ] dip change-interval ] [ 2drop ] if ; inline
45 { bitnot fixnum-bitnot bignum-bitnot } [
46 [ [ interval-bitnot ] ?change-interval ] "outputs" set-word-prop
49 \ abs [ [ interval-abs ] ?change-interval ] "outputs" set-word-prop
51 : math-closure ( class -- newclass )
52 { fixnum bignum integer rational float real number object }
53 [ class<= ] with find nip ;
55 : fits? ( interval class -- ? )
56 "interval" word-prop interval-subset? ;
58 : binary-op-class ( info1 info2 -- newclass )
60 2dup [ null-class? ] either? [ 2drop null ] [
61 [ math-closure ] bi@ math-class-max
64 : binary-op-interval ( info1 info2 quot -- newinterval )
65 [ [ interval>> ] bi@ ] dip call ; inline
67 : won't-overflow? ( class interval -- ? )
68 [ fixnum class<= ] [ fixnum fits? ] bi* and ;
70 : may-overflow ( class interval -- class' interval' )
73 [ [ integer math-class-max ] dip ] unless
76 : may-be-rational ( class interval -- class' interval' )
78 [ rational math-class-max ] dip
81 : ensure-math-class ( class must-be -- class' )
84 : number-valued ( class interval -- class' interval' )
85 [ number ensure-math-class ] dip ;
87 : integer-valued ( class interval -- class' interval' )
88 [ integer ensure-math-class ] dip ;
90 : real-valued ( class interval -- class' interval' )
91 [ real ensure-math-class ] dip ;
93 : float-valued ( class interval -- class' interval' )
98 : binary-op ( word interval-quot post-proc-quot -- )
100 [ binary-op-class ] [ _ binary-op-interval ] 2bi
102 <class/interval-info>
103 ] "outputs" set-word-prop ;
105 \ + [ [ interval+ ] [ may-overflow number-valued ] binary-op ] each-derived-op
106 \ + [ [ interval+ ] [ number-valued ] binary-op ] each-fast-derived-op
108 \ - [ [ interval- ] [ may-overflow number-valued ] binary-op ] each-derived-op
109 \ - [ [ interval- ] [ number-valued ] binary-op ] each-fast-derived-op
111 \ * [ [ interval* ] [ may-overflow number-valued ] binary-op ] each-derived-op
112 \ * [ [ interval* ] [ number-valued ] binary-op ] each-fast-derived-op
114 \ / [ [ interval/-safe ] [ may-be-rational number-valued ] binary-op ] each-derived-op
115 \ /i [ [ interval/i ] [ may-overflow integer-valued ] binary-op ] each-derived-op
116 \ /f [ [ interval/f ] [ float-valued ] binary-op ] each-derived-op
118 \ mod [ [ interval-mod ] [ real-valued ] binary-op ] each-derived-op
119 \ rem [ [ interval-rem ] [ may-overflow real-valued ] binary-op ] each-derived-op
121 { /mod fixnum/mod } [
123 [ "outputs" word-prop ] bi@
124 '[ _ _ 2bi ] "outputs" set-word-prop
127 \ shift [ [ interval-shift-safe ] [ may-overflow integer-valued ] binary-op ] each-derived-op
128 \ shift [ [ interval-shift-safe ] [ integer-valued ] binary-op ] each-fast-derived-op
130 \ bitand [ [ interval-bitand ] [ integer-valued ] binary-op ] each-derived-op
131 \ bitor [ [ interval-bitor ] [ integer-valued ] binary-op ] each-derived-op
132 \ bitxor [ [ interval-bitxor ] [ integer-valued ] binary-op ] each-derived-op
134 :: (comparison-constraints) ( in1 in2 op -- constraint )
135 [let | i1 [ in1 value-info interval>> ]
136 i2 [ in2 value-info interval>> ] |
137 in1 i1 i2 op assumption is-in-interval
138 in2 i2 i1 op swap-comparison assumption is-in-interval
142 :: comparison-constraints ( in1 in2 out op -- constraint )
143 in1 in2 op (comparison-constraints) out t-->
144 in1 in2 op negate-comparison (comparison-constraints) out f--> /\ ;
146 : define-comparison-constraints ( word op -- )
147 '[ _ comparison-constraints ] "constraints" set-word-prop ;
150 [ dup '[ _ define-comparison-constraints ] each-derived-op ] each
152 ! Remove redundant comparisons
153 : fold-comparison ( info1 info2 word -- info )
154 [ [ interval>> ] bi@ ] dip interval-comparison {
155 { incomparable [ object-info ] }
156 { t [ t <literal-info> ] }
157 { f [ f <literal-info> ] }
162 [ _ fold-comparison ] "outputs" set-word-prop
166 generic-comparison-ops [
167 dup specific-comparison
168 '[ _ fold-comparison ] "outputs" set-word-prop
171 : maybe-or-never ( ? -- info )
172 [ object-info ] [ f <literal-info> ] if ;
174 : info-intervals-intersect? ( info1 info2 -- ? )
175 [ interval>> ] bi@ intervals-intersect? ;
177 { number= bignum= float= } [
179 info-intervals-intersect? maybe-or-never
180 ] "outputs" set-word-prop
183 : info-classes-intersect? ( info1 info2 -- ? )
184 [ class>> ] bi@ classes-intersect? ;
187 over value-info literal>> fixnum? [
188 [ value-info literal>> is-equal-to ] dip t-->
190 ] "constraints" set-word-prop
193 [ info-intervals-intersect? ]
194 [ info-classes-intersect? ]
195 2bi and maybe-or-never
196 ] "outputs" set-word-prop
200 { [ 2dup [ fixnum classes-intersect? not ] either? ] [ f <literal-info> ] }
201 { [ 2dup [ fixnum class<= ] both? ] [ t <literal-info> ] }
204 ] "outputs" set-word-prop
208 { bignum>fixnum fixnum }
211 { fixnum>bignum bignum }
212 { float>bignum bignum }
215 { fixnum>float float }
216 { bignum>float float }
223 [ interval>> ] [ class-interval ] bi*
226 <class/interval-info>
227 ] "outputs" set-word-prop
230 : rem-custom-inlining ( #call -- quot/f )
231 second value-info literal>> dup integer?
232 [ power-of-2? [ 1- bitand ] f ? ] [ drop f ] if ;
241 in-d>> dup first value-info interval>> [0,inf] interval-subset?
242 [ rem-custom-inlining ] [ drop f ] if
243 ] "custom-inlining" set-word-prop
247 in-d>> rem-custom-inlining
248 ] "custom-inlining" set-word-prop
251 bitand-integer-integer
252 bitand-integer-fixnum
253 bitand-fixnum-integer
256 in-d>> second value-info >literal< [
257 0 most-positive-fixnum between?
258 [ [ >fixnum ] bi@ fixnum-bitand ] f ?
260 ] "custom-inlining" set-word-prop
263 { numerator denominator }
264 [ [ drop integer <class-info> ] "outputs" set-word-prop ] each
266 { (log2) fixnum-log2 bignum-log2 } [
268 [ class>> ] [ interval>> interval-log2 ] bi <class/interval-info>
269 ] "outputs" set-word-prop
273 2drop fixnum 0 23 2^ [a,b] <class/interval-info>
274 ] "outputs" set-word-prop
288 [ "alien-signed-" ?head ]
289 [ string>number 8 * 1- 2^ dup neg swap 1- [a,b] ]
292 [ "alien-unsigned-" ?head ]
293 [ string>number 8 * 2^ 1- 0 swap [a,b] ]
296 [ fixnum fits? fixnum integer ? ] keep <class/interval-info>
297 '[ 2drop _ ] "outputs" set-word-prop
300 { <tuple> <tuple-boa> } [
302 literal>> dup array? [ first ] [ drop tuple ] if <class-info>
304 ] "outputs" set-word-prop
308 literal>> dup tuple-class? [ drop tuple ] unless <class-info>
309 ] "outputs" set-word-prop
311 ! the output of clone has the same type as the input
313 [ clone f >>literal f >>literal? ]
314 "outputs" set-word-prop
317 ! Generate more efficient code for common idiom
319 in-d>> first value-info literal>> {
320 { V{ } [ [ drop { } 0 vector boa ] ] }
321 { H{ } [ [ drop 0 <hashtable> ] ] }
324 ] "custom-inlining" set-word-prop
328 [ literal>> swap value-info-slot ] [ 2drop object-info ] if
329 ] "outputs" set-word-prop
332 [ value-info ] dip over literal>> class? [
333 [ literal>> ] dip predicate-constraints
335 ] "constraints" set-word-prop
338 ! We need to force the caller word to recompile when the class
339 ! is redefined, since now we're making assumptions but the
340 ! class definition itself.
344 [ inlined-dependency depends-on ]
345 [ predicate-output-infos ]
347 ] [ 2drop object-info ] if
348 ] "outputs" set-word-prop
351 in-d>> second value-info literal>> dup class?
352 [ "predicate" word-prop '[ drop @ ] ] [ drop f ] if
353 ] "custom-inlining" set-word-prop
356 ! If first input has a known type and second input is an
357 ! object, we convert this to [ swap equal? ].
358 in-d>> first2 value-info class>> object class= [
359 value-info class>> \ equal? specific-method
362 ] "custom-inlining" set-word-prop
364 : inline-new ( class -- quot/f )
366 dup inlined-dependency depends-on
367 [ all-slots [ initial>> literalize ] map ]
368 [ tuple-layout '[ _ <tuple-boa> ] ]
369 bi append [ drop ] prepend >quotation
373 in-d>> first value-info literal>> inline-new
374 ] "custom-inlining" set-word-prop