1 ! Copyright (C) 2008, 2011 Slava Pestov, Daniel Ehrenberg.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.c-types arrays assocs byte-arrays classes classes.algebra
4 classes.tuple classes.tuple.private combinators combinators.short-circuit
5 compiler.tree.propagation.info effects generalizations generic generic.single
6 growable hash-sets hashtables kernel layouts math math.integers.private
7 math.intervals math.order math.partial-dispatch math.private namespaces
8 quotations sequences sequences.generalizations sequences.private sets
9 sets.private stack-checker stack-checker.dependencies strings vectors words ;
11 IN: compiler.tree.propagation.transforms
14 ! If first input has a known type and second input is an
15 ! object, we convert this to [ swap equal? ].
16 in-d>> first2 value-info class>> object class= [
17 value-info class>> \ equal? method-for-class
20 ] "custom-inlining" set-word-prop
22 : rem-custom-inlining ( inputs -- quot/f )
23 dup first value-info class>> integer class<= [
24 second value-info literal>> dup integer?
25 [ power-of-2? [ 1 - bitand ] f ? ] [ drop f ] if
35 in-d>> dup first value-info interval>> [0,inf] interval-subset?
36 [ rem-custom-inlining ] [ drop f ] if
37 ] "custom-inlining" set-word-prop
41 in-d>> rem-custom-inlining
42 ] "custom-inlining" set-word-prop
44 : non-negative-fixnum? ( obj -- ? )
45 { [ fixnum? ] [ 0 >= ] } 1&& ;
47 : simplify-bitand? ( value1 value2 -- ? )
48 [ literal>> non-negative-fixnum? ]
49 [ class>> fixnum swap class<= ]
52 : all-ones? ( n -- ? ) dup 1 + bitand zero? ; inline
54 : redundant-bitand? ( value1 value2 -- ? )
55 [ interval>> ] [ literal>> ] bi* {
58 [ [0,b] interval-subset? ]
61 : zero-bitand? ( value1 value2 -- ? )
62 [ interval>> ] [ literal>> ] bi* {
64 [ nip bitnot all-ones? ]
65 [ 0 swap bitnot [a,b] interval-subset? ]
69 bitand-integer-integer
75 in-d>> first2 [ value-info ] bi@ {
78 [ nip class>> bignum = 0 >bignum 0 ? '[ 2drop _ ] ]
81 [ 2dup swap zero-bitand? ]
82 [ drop class>> bignum = 0 >bignum 0 ? '[ 2drop _ ] ]
85 [ 2dup redundant-bitand? ]
86 [ nip class>> bignum = [ drop >bignum ] [ drop ] ? ]
89 [ 2dup swap redundant-bitand? ]
90 [ drop class>> bignum = [ nip >bignum ] [ nip ] ? ]
93 [ 2dup simplify-bitand? ]
94 [ 2drop [ integer>fixnum fixnum-bitand ] ]
97 [ 2dup swap simplify-bitand? ]
98 [ 2drop [ [ integer>fixnum ] dip fixnum-bitand ] ]
102 ] "custom-inlining" set-word-prop
107 in-d>> first value-info literal>> 1 eq? ;
109 : shift-2^ ( -- quot )
110 cell-bits tag-bits get - 1 -
112 integer>fixnum-strict dup 0 < [ 2drop 0 ] [
113 dup _ < [ fixnum-shift ] [
121 in-d>> second value-info literal>> -1 eq? ;
123 : shift-2/ ( -- quot )
126 { [ over fixnum? ] [ fixnum-shift ] }
127 { [ over bignum? ] [ bignum-shift ] }
128 [ drop \ shift no-method ]
134 { [ dup 2^? ] [ drop shift-2^ ] }
135 { [ dup 2/? ] [ drop shift-2/ ] }
138 ] "custom-inlining" set-word-prop
140 { /i fixnum/i fixnum/i-fast bignum/i } [
142 in-d>> first2 [ value-info ] bi@ {
143 [ drop class>> integer class<= ]
144 [ drop interval>> 0 [a,a] interval>= ]
145 [ nip literal>> integer? ]
146 [ nip literal>> power-of-2? ]
147 } 2&& [ [ log2 neg shift ] ] [ f ] if
148 ] "custom-inlining" set-word-prop
151 ! Generate more efficient code for common idiom
153 in-d>> first value-info literal>> {
154 { V{ } [ [ drop { } 0 vector boa ] ] }
155 { H{ } [ [ drop 0 <hashtable> ] ] }
156 { HS{ } [ [ drop 0 <hash-set> ] ] }
159 ] "custom-inlining" set-word-prop
161 ERROR: bad-partial-eval quot word ;
163 : check-effect ( quot word -- )
164 2dup [ infer ] [ stack-effect ] bi* effect<=
165 [ 2drop ] [ bad-partial-eval ] if ;
167 :: define-partial-eval ( word quot n -- )
171 dup [ literal?>> ] all? [
176 dup word check-effect
179 ] "custom-inlining" set-word-prop ;
181 : inline-new ( class -- quot/f )
184 [ add-depends-on-tuple-layout ]
185 [ drop all-slots [ initial>> literalize ] [ ] map-as ]
191 \ new [ inline-new ] 1 define-partial-eval
197 ! union{ and intersection{ and not{ have useless
198 ! expansions, and recurse infinitely
199 dup { [ length 2 >= ] [ second \ instance? = ] } 1&& [
203 ] 1 define-partial-eval
206 : nths-quot ( indices -- quot )
207 [ [ '[ _ swap nth ] ] map ] [ length ] bi
208 '[ _ cleave _ narray ] ;
211 shuffle-mapping nths-quot
212 ] 1 define-partial-eval
218 H{ } zip-index-as '[ _ at ]
221 ] 1 define-partial-eval
223 : member-eq-quot ( seq -- newquot )
224 [ [ dupd eq? ] curry [ drop t ] ] { } map>assoc
225 [ drop f ] suffix [ cond ] curry ;
228 dup sequence? [ member-eq-quot ] [ drop f ] if
229 ] 1 define-partial-eval
232 : member-quot ( seq -- newquot )
235 [ literalize [ t ] ] { } map>assoc linear-case-quot
241 dup sequence? [ member-quot ] [ drop f ] if
242 ] 1 define-partial-eval
244 ! Fast at for integer maps
245 CONSTANT: lookup-table-at-max 256
247 : lookup-table-at? ( assoc -- ? )
248 ! Can we use a fast byte array test here?
252 [ keys [ integer? ] all? ]
253 [ keys [ 0 lookup-table-at-max between? ] all? ]
256 : lookup-table-seq ( assoc -- table )
257 [ keys supremum 1 + <iota> ] keep '[ _ at ] { } map-as ;
259 : lookup-table-quot ( seq -- newquot )
264 nth-unsafe dup >boolean
269 : fast-lookup-table-at? ( assoc -- ? )
271 [ [ integer? ] all? ]
272 [ [ 0 254 between? ] all? ]
275 : fast-lookup-table-seq ( assoc -- table )
276 lookup-table-seq [ 255 or ] B{ } map-as ;
278 : fast-lookup-table-quot ( seq -- newquot )
279 fast-lookup-table-seq
283 nth-unsafe dup 255 eq? [ drop f f ] [ t ] if
288 : at-quot ( assoc -- quot )
290 dup lookup-table-at? [
291 dup fast-lookup-table-at? [
292 fast-lookup-table-quot
299 \ at* [ at-quot ] 1 define-partial-eval
301 : diff-quot ( seq -- quot: ( seq' -- seq'' ) )
302 [ tester ] keep '[ members _ reject _ set-like ] ;
304 M\ sets:set diff [ diff-quot ] 1 define-partial-eval
306 : intersect-quot ( seq -- quot: ( seq' -- seq'' ) )
307 [ tester ] keep '[ members _ filter _ set-like ] ;
309 M\ sets:set intersect [ intersect-quot ] 1 define-partial-eval
311 : intersects?-quot ( seq -- quot: ( seq' -- seq'' ) )
312 tester '[ members _ any? ] ;
314 M\ sets:set intersects? [ intersects?-quot ] 1 define-partial-eval
316 : bit-quot ( #call -- quot/f )
317 in-d>> second value-info interval>> 0 fixnum-bits [a,b] interval-subset?
318 [ [ integer>fixnum ] dip fixnum-bit? ] f ? ;
320 \ bit? [ bit-quot ] "custom-inlining" set-word-prop
322 ! Speeds up sum-file, sort and reverse-complement benchmarks by
323 ! compiling decoder-readln better
325 in-d>> second value-info class>> growable class<=
326 [ \ push def>> ] [ f ] if
327 ] "custom-inlining" set-word-prop
329 : custom-inline-fixnum ( #call method -- y )
330 [ in-d>> first value-info class>> fixnum \ f class-or class<= ] dip
331 '[ [ dup [ _ no-method ] unless ] ] [ f ] if ;
333 ! Speeds up fasta benchmark
334 { >fixnum integer>fixnum integer>fixnum-strict } [
335 dup '[ _ custom-inline-fixnum ] "custom-inlining" set-word-prop
338 ! We want to constant-fold calls to heap-size, and recompile those
339 ! calls when a C type is redefined
341 [ add-depends-on-c-type ] [ heap-size '[ _ ] ] bi
342 ] 1 define-partial-eval
344 ! Eliminates a few redundant checks here and there
346 in-d>> first2 [ value-info class>> ] bi@ {
347 { [ 2dup [ fixnum classes-intersect? not ] either? ] [ [ 2drop f ] ] }
348 { [ 2dup [ fixnum class<= ] both? ] [ [ 2drop t ] ] }
349 { [ dup fixnum class<= ] [ [ drop fixnum? ] ] }
350 { [ over fixnum class<= ] [ [ nip fixnum? ] ] }
353 ] "custom-inlining" set-word-prop
355 : constant-number-info? ( info -- ? )
356 { [ value-info-state? ] [ literal?>> ] [ class>> integer class<= ] } 1&& ;
358 ! Resize-sequences to existing length can be optimized out
359 { resize-array resize-string resize-byte-array } [
360 in-d>> first2 [ value-info ] bi@ slots>> ?first
361 { [ [ constant-number-info? ] both? ] [ [ literal>> ] bi@ = ] } 2&&
363 ] [ "custom-inlining" set-word-prop ] curry each