2008-01-12 21:37:44 -05:00
|
|
|
! Copyright (C) 2005, 2008 Slava Pestov.
|
2007-09-20 18:09:08 -04:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
|
|
IN: optimizer.math
|
2008-02-01 00:00:08 -05:00
|
|
|
USING: alien alien.accessors arrays generic hashtables kernel
|
|
|
|
assocs math math.private kernel.private sequences words parser
|
2007-09-20 18:09:08 -04:00
|
|
|
inference.class inference.dataflow vectors strings sbufs io
|
|
|
|
namespaces assocs quotations math.intervals sequences.private
|
2008-02-01 00:00:08 -05:00
|
|
|
combinators splitting layouts math.parser classes generic.math
|
|
|
|
optimizer.pattern-match optimizer.backend optimizer.def-use
|
2008-02-13 21:07:08 -05:00
|
|
|
optimizer.inlining generic.standard system ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
{ + bignum+ float+ fixnum+fast } {
|
|
|
|
{ { number 0 } [ drop ] }
|
|
|
|
{ { 0 number } [ nip ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ fixnum+ } {
|
|
|
|
{ { number 0 } [ drop ] }
|
|
|
|
{ { 0 number } [ nip ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ - fixnum- bignum- float- fixnum-fast } {
|
|
|
|
{ { number 0 } [ drop ] }
|
|
|
|
{ { @ @ } [ 2drop 0 ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ < fixnum< bignum< float< } {
|
|
|
|
{ { @ @ } [ 2drop f ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ <= fixnum<= bignum<= float<= } {
|
|
|
|
{ { @ @ } [ 2drop t ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ > fixnum> bignum> float>= } {
|
|
|
|
{ { @ @ } [ 2drop f ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ >= fixnum>= bignum>= float>= } {
|
|
|
|
{ { @ @ } [ 2drop t ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ * fixnum* bignum* float* } {
|
|
|
|
{ { number 1 } [ drop ] }
|
|
|
|
{ { 1 number } [ nip ] }
|
|
|
|
{ { number 0 } [ nip ] }
|
|
|
|
{ { 0 number } [ drop ] }
|
|
|
|
{ { number -1 } [ drop 0 swap - ] }
|
|
|
|
{ { -1 number } [ nip 0 swap - ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ / fixnum/i bignum/i float/f } {
|
|
|
|
{ { number 1 } [ drop ] }
|
|
|
|
{ { number -1 } [ drop 0 swap - ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ fixnum-mod bignum-mod } {
|
|
|
|
{ { number 1 } [ 2drop 0 ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ bitand fixnum-bitand bignum-bitand } {
|
|
|
|
{ { number -1 } [ drop ] }
|
|
|
|
{ { -1 number } [ nip ] }
|
|
|
|
{ { @ @ } [ drop ] }
|
|
|
|
{ { number 0 } [ nip ] }
|
|
|
|
{ { 0 number } [ drop ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ bitor fixnum-bitor bignum-bitor } {
|
|
|
|
{ { number 0 } [ drop ] }
|
|
|
|
{ { 0 number } [ nip ] }
|
|
|
|
{ { @ @ } [ drop ] }
|
|
|
|
{ { number -1 } [ nip ] }
|
|
|
|
{ { -1 number } [ drop ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
{ bitxor fixnum-bitxor bignum-bitxor } {
|
|
|
|
{ { number 0 } [ drop ] }
|
|
|
|
{ { 0 number } [ nip ] }
|
|
|
|
{ { number -1 } [ drop bitnot ] }
|
|
|
|
{ { -1 number } [ nip bitnot ] }
|
|
|
|
{ { @ @ } [ 2drop 0 ] }
|
|
|
|
} define-identities
|
|
|
|
|
2008-01-12 21:37:44 -05:00
|
|
|
{ shift fixnum-shift fixnum-shift-fast bignum-shift } {
|
2007-09-20 18:09:08 -04:00
|
|
|
{ { 0 number } [ drop ] }
|
|
|
|
{ { number 0 } [ drop ] }
|
|
|
|
} define-identities
|
|
|
|
|
|
|
|
: math-closure ( class -- newclass )
|
|
|
|
{ fixnum integer rational real }
|
2008-01-09 17:36:30 -05:00
|
|
|
[ class< ] with find nip number or ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: fits? ( interval class -- ? )
|
|
|
|
"interval" word-prop dup
|
|
|
|
[ interval-subset? ] [ 2drop t ] if ;
|
|
|
|
|
|
|
|
: math-output-class ( node min -- newclass )
|
|
|
|
#! if min is f, it means we just want to use the declared
|
|
|
|
#! output class from the "infer-effect".
|
|
|
|
dup [
|
|
|
|
swap node-in-d
|
|
|
|
[ value-class* math-closure math-class-max ] each
|
|
|
|
] [
|
|
|
|
2drop f
|
|
|
|
] if ;
|
|
|
|
|
|
|
|
: won't-overflow? ( interval node -- ? )
|
|
|
|
node-in-d [ value-class* fixnum class< ] all?
|
|
|
|
swap fixnum fits? and ;
|
|
|
|
|
|
|
|
: post-process ( class interval node -- classes intervals )
|
|
|
|
dupd won't-overflow?
|
2007-12-08 17:45:51 -05:00
|
|
|
[ >r dup { f integer } member? [ drop fixnum ] when r> ] when
|
2007-09-20 18:09:08 -04:00
|
|
|
[ dup [ 1array ] when ] 2apply ;
|
|
|
|
|
|
|
|
: math-output-interval-1 ( node word -- interval )
|
|
|
|
dup [
|
|
|
|
>r node-in-d first value-interval* dup
|
|
|
|
[ r> execute ] [ r> 2drop f ] if
|
|
|
|
] [
|
|
|
|
2drop f
|
|
|
|
] if ; inline
|
|
|
|
|
|
|
|
: math-output-class/interval-1 ( node min word -- classes intervals )
|
|
|
|
pick >r
|
|
|
|
>r over r>
|
|
|
|
math-output-interval-1
|
|
|
|
>r math-output-class r>
|
|
|
|
r> post-process ; inline
|
|
|
|
|
|
|
|
{
|
|
|
|
{ 1+ integer interval-1+ }
|
|
|
|
{ 1- integer interval-1- }
|
|
|
|
{ neg integer interval-neg }
|
|
|
|
{ shift integer interval-recip }
|
|
|
|
{ bitnot fixnum interval-bitnot }
|
|
|
|
{ fixnum-bitnot f interval-bitnot }
|
|
|
|
{ bignum-bitnot f interval-bitnot }
|
|
|
|
{ 2/ fixnum interval-2/ }
|
|
|
|
{ sq integer f }
|
|
|
|
} [
|
|
|
|
first3 [
|
|
|
|
math-output-class/interval-1
|
|
|
|
] 2curry "output-classes" set-word-prop
|
|
|
|
] each
|
|
|
|
|
|
|
|
: intervals ( node -- i1 i2 )
|
|
|
|
node-in-d first2 [ value-interval* ] 2apply ;
|
|
|
|
|
|
|
|
: math-output-interval-2 ( node word -- interval )
|
|
|
|
dup [
|
|
|
|
>r intervals 2dup and [ r> execute ] [ r> 3drop f ] if
|
|
|
|
] [
|
|
|
|
2drop f
|
|
|
|
] if ; inline
|
|
|
|
|
|
|
|
: math-output-class/interval-2 ( node min word -- classes intervals )
|
|
|
|
pick >r
|
|
|
|
>r over r>
|
|
|
|
math-output-interval-2
|
|
|
|
>r math-output-class r>
|
|
|
|
r> post-process ; inline
|
|
|
|
|
|
|
|
{
|
|
|
|
{ + integer interval+ }
|
|
|
|
{ - integer interval- }
|
|
|
|
{ * integer interval* }
|
|
|
|
{ / rational interval/ }
|
|
|
|
{ /i integer interval/i }
|
|
|
|
|
|
|
|
{ fixnum+ f interval+ }
|
|
|
|
{ fixnum+fast f interval+ }
|
|
|
|
{ fixnum- f interval- }
|
|
|
|
{ fixnum-fast f interval- }
|
|
|
|
{ fixnum* f interval* }
|
|
|
|
{ fixnum*fast f interval* }
|
|
|
|
{ fixnum/i f interval/i }
|
|
|
|
|
|
|
|
{ bignum+ f interval+ }
|
|
|
|
{ bignum- f interval- }
|
|
|
|
{ bignum* f interval* }
|
|
|
|
{ bignum/i f interval/i }
|
|
|
|
{ bignum-shift f interval-shift-safe }
|
|
|
|
|
|
|
|
{ float+ f interval+ }
|
|
|
|
{ float- f interval- }
|
|
|
|
{ float* f interval* }
|
|
|
|
{ float/f f interval/ }
|
|
|
|
|
|
|
|
{ min fixnum interval-min }
|
|
|
|
{ max fixnum interval-max }
|
|
|
|
} [
|
|
|
|
first3 [
|
|
|
|
math-output-class/interval-2
|
|
|
|
] 2curry "output-classes" set-word-prop
|
|
|
|
] each
|
|
|
|
|
2008-01-12 21:37:44 -05:00
|
|
|
{ fixnum-shift fixnum-shift-fast shift } [
|
2007-09-20 18:09:08 -04:00
|
|
|
[
|
|
|
|
dup
|
|
|
|
node-in-d second value-interval*
|
|
|
|
-1./0. 0 [a,b] interval-subset? fixnum integer ?
|
|
|
|
\ interval-shift-safe
|
|
|
|
math-output-class/interval-2
|
|
|
|
] "output-classes" set-word-prop
|
|
|
|
] each
|
|
|
|
|
|
|
|
: real-value? ( value -- n ? )
|
|
|
|
dup value? [ value-literal dup real? ] [ drop f f ] if ;
|
|
|
|
|
|
|
|
: mod-range ( n -- interval )
|
|
|
|
dup neg swap (a,b) ;
|
|
|
|
|
|
|
|
: rem-range ( n -- interval )
|
|
|
|
0 swap [a,b) ;
|
|
|
|
|
|
|
|
: bitand-range ( n -- interval )
|
|
|
|
dup 0 < [ drop f ] [ 0 swap [a,b] ] if ;
|
|
|
|
|
|
|
|
: math-output-interval-special ( node word -- interval )
|
|
|
|
dup [
|
|
|
|
>r node-in-d second real-value?
|
|
|
|
[ r> execute ] [ r> 2drop f ] if
|
|
|
|
] [
|
|
|
|
2drop f
|
|
|
|
] if ; inline
|
|
|
|
|
|
|
|
: math-output-class/interval-special ( node min word -- classes intervals )
|
|
|
|
pick >r
|
|
|
|
>r over r>
|
|
|
|
math-output-interval-special
|
|
|
|
>r math-output-class r>
|
|
|
|
r> post-process ; inline
|
|
|
|
|
|
|
|
{
|
|
|
|
{ mod fixnum mod-range }
|
|
|
|
{ fixnum-mod f mod-range }
|
|
|
|
{ bignum-mod f mod-range }
|
|
|
|
{ float-mod f mod-range }
|
|
|
|
|
|
|
|
{ rem integer rem-range }
|
|
|
|
|
|
|
|
{ bitand fixnum bitand-range }
|
|
|
|
{ fixnum-bitand f bitand-range }
|
|
|
|
|
|
|
|
{ bitor fixnum f }
|
|
|
|
{ bitxor fixnum f }
|
|
|
|
} [
|
|
|
|
first3 [
|
|
|
|
math-output-class/interval-special
|
|
|
|
] 2curry "output-classes" set-word-prop
|
|
|
|
] each
|
|
|
|
|
|
|
|
: twiddle-interval ( i1 -- i2 )
|
|
|
|
dup [
|
|
|
|
node get node-in-d
|
|
|
|
[ value-class* integer class< ] all?
|
|
|
|
[ integral-closure ] when
|
|
|
|
] when ;
|
|
|
|
|
|
|
|
: (comparison-constraints) ( i1 i2 word class -- )
|
|
|
|
node get [
|
|
|
|
>r execute twiddle-interval 0 `input interval,
|
|
|
|
r> 0 `output class,
|
|
|
|
] set-constraints ; inline
|
|
|
|
|
|
|
|
: comparison-constraints ( node true false -- )
|
|
|
|
>r >r dup node set intervals dup [
|
|
|
|
2dup
|
|
|
|
r> general-t (comparison-constraints)
|
|
|
|
r> \ f (comparison-constraints)
|
|
|
|
] [
|
|
|
|
r> r> 2drop 2drop
|
|
|
|
] if ; inline
|
|
|
|
|
|
|
|
{
|
|
|
|
{ < assume< assume>= }
|
|
|
|
{ <= assume<= assume> }
|
|
|
|
{ > assume> assume<= }
|
|
|
|
{ >= assume>= assume< }
|
|
|
|
|
|
|
|
{ fixnum< assume< assume>= }
|
|
|
|
{ fixnum<= assume<= assume> }
|
|
|
|
{ fixnum> assume> assume<= }
|
|
|
|
{ fixnum>= assume>= assume< }
|
|
|
|
|
|
|
|
{ bignum< assume< assume>= }
|
|
|
|
{ bignum<= assume<= assume> }
|
|
|
|
{ bignum> assume> assume<= }
|
|
|
|
{ bignum>= assume>= assume< }
|
|
|
|
|
|
|
|
{ float< assume< assume>= }
|
|
|
|
{ float<= assume<= assume> }
|
|
|
|
{ float> assume> assume<= }
|
|
|
|
{ float>= assume>= assume< }
|
|
|
|
} [
|
|
|
|
first3
|
|
|
|
[
|
|
|
|
[ comparison-constraints ] with-scope
|
|
|
|
] 2curry "constraints" set-word-prop
|
|
|
|
] each
|
|
|
|
|
|
|
|
{
|
|
|
|
alien-signed-1
|
|
|
|
alien-unsigned-1
|
|
|
|
alien-signed-2
|
|
|
|
alien-unsigned-2
|
|
|
|
alien-signed-4
|
|
|
|
alien-unsigned-4
|
|
|
|
alien-signed-8
|
|
|
|
alien-unsigned-8
|
|
|
|
} [
|
|
|
|
dup word-name {
|
|
|
|
{
|
|
|
|
[ "alien-signed-" ?head ]
|
|
|
|
[ string>number 8 * 1- 2^ dup neg swap 1- [a,b] ]
|
|
|
|
}
|
|
|
|
{
|
|
|
|
[ "alien-unsigned-" ?head ]
|
|
|
|
[ string>number 8 * 2^ 1- 0 swap [a,b] ]
|
|
|
|
}
|
|
|
|
} cond 1array
|
|
|
|
[ nip f swap ] curry "output-classes" set-word-prop
|
|
|
|
] each
|
|
|
|
|
|
|
|
! Associate intervals to classes
|
|
|
|
\ fixnum
|
|
|
|
most-negative-fixnum most-positive-fixnum [a,b]
|
|
|
|
"interval" set-word-prop
|
|
|
|
|
|
|
|
\ array-capacity
|
|
|
|
0 max-array-capacity [a,b]
|
|
|
|
"interval" set-word-prop
|
|
|
|
|
|
|
|
{
|
|
|
|
{ >fixnum fixnum }
|
|
|
|
{ >bignum bignum }
|
|
|
|
{ >float float }
|
|
|
|
} [
|
|
|
|
[
|
|
|
|
over node-in-d first value-interval*
|
|
|
|
dup pick fits? [ drop f ] unless
|
|
|
|
rot post-process
|
|
|
|
] curry "output-classes" set-word-prop
|
|
|
|
] assoc-each
|
|
|
|
|
|
|
|
! Removing overflow checks
|
|
|
|
: remove-overflow-check? ( #call -- ? )
|
|
|
|
dup node-out-d first node-class fixnum class< ;
|
|
|
|
|
|
|
|
{
|
|
|
|
{ + [ fixnum+fast ] }
|
|
|
|
{ - [ fixnum-fast ] }
|
|
|
|
{ * [ fixnum*fast ] }
|
|
|
|
{ fixnum+ [ fixnum+fast ] }
|
|
|
|
{ fixnum- [ fixnum-fast ] }
|
|
|
|
{ fixnum* [ fixnum*fast ] }
|
|
|
|
! these are here as an optimization. if they weren't given
|
|
|
|
! explicitly, the same would be inferred after an extra
|
|
|
|
! optimization step (see optimistic-inline?)
|
|
|
|
{ 1+ [ 1 fixnum+fast ] }
|
|
|
|
{ 1- [ 1 fixnum-fast ] }
|
|
|
|
{ 2/ [ -1 fixnum-shift ] }
|
|
|
|
{ neg [ 0 swap fixnum-fast ] }
|
|
|
|
} [
|
|
|
|
[
|
|
|
|
[ dup remove-overflow-check? ] ,
|
2008-02-16 19:50:16 -05:00
|
|
|
[ f splice-quot ] curry ,
|
2007-09-20 18:09:08 -04:00
|
|
|
] { } make 1array define-optimizers
|
|
|
|
] assoc-each
|
|
|
|
|
|
|
|
! Remove redundant comparisons
|
2008-03-07 22:27:00 -05:00
|
|
|
: intervals-first2 ( #call -- first second )
|
2007-09-20 18:09:08 -04:00
|
|
|
dup dup node-in-d first node-interval
|
2008-03-07 22:27:00 -05:00
|
|
|
swap dup node-in-d second node-interval ;
|
|
|
|
|
|
|
|
: known-comparison? ( #call -- ? )
|
|
|
|
intervals-first2 and ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: perform-comparison ( #call word -- result )
|
2008-03-07 22:27:00 -05:00
|
|
|
>r intervals-first2 r> execute ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-02-21 15:15:45 -05:00
|
|
|
: foldable-comparison? ( #call word -- ? )
|
2007-09-20 18:09:08 -04:00
|
|
|
>r dup known-comparison? [
|
|
|
|
r> perform-comparison incomparable eq? not
|
|
|
|
] [
|
|
|
|
r> 2drop f
|
|
|
|
] if ; inline
|
|
|
|
|
|
|
|
: fold-comparison ( #call word -- node )
|
|
|
|
dupd perform-comparison 1array inline-literals ;
|
|
|
|
|
|
|
|
{
|
|
|
|
{ < interval< }
|
|
|
|
{ <= interval<= }
|
|
|
|
{ > interval> }
|
|
|
|
{ >= interval>= }
|
|
|
|
|
|
|
|
{ fixnum< interval< }
|
|
|
|
{ fixnum<= interval<= }
|
|
|
|
{ fixnum> interval> }
|
|
|
|
{ fixnum>= interval>= }
|
|
|
|
|
|
|
|
{ bignum< interval< }
|
|
|
|
{ bignum<= interval<= }
|
|
|
|
{ bignum> interval> }
|
|
|
|
{ bignum>= interval>= }
|
|
|
|
|
|
|
|
{ float< interval< }
|
|
|
|
{ float<= interval<= }
|
|
|
|
{ float> interval> }
|
|
|
|
{ float>= interval>= }
|
|
|
|
} [
|
|
|
|
[
|
|
|
|
dup [ dupd foldable-comparison? ] curry ,
|
|
|
|
[ fold-comparison ] curry ,
|
|
|
|
] { } make 1array define-optimizers
|
|
|
|
] assoc-each
|
|
|
|
|
|
|
|
! The following words are handled in a similar way except if
|
|
|
|
! the only consumer is a >fixnum we remove the overflow check
|
|
|
|
! too
|
|
|
|
: consumed-by? ( node word -- ? )
|
|
|
|
swap sole-consumer
|
|
|
|
dup #call? [ node-param eq? ] [ 2drop f ] if ;
|
|
|
|
|
|
|
|
: coereced-to-fixnum? ( #call -- ? )
|
|
|
|
\ >fixnum consumed-by? ;
|
|
|
|
|
|
|
|
{
|
|
|
|
{ fixnum+ [ fixnum+fast ] }
|
|
|
|
{ fixnum- [ fixnum-fast ] }
|
|
|
|
{ fixnum* [ fixnum*fast ] }
|
|
|
|
} [
|
|
|
|
[
|
|
|
|
[
|
|
|
|
dup remove-overflow-check?
|
|
|
|
over coereced-to-fixnum? or
|
|
|
|
] ,
|
2008-02-16 19:50:16 -05:00
|
|
|
[ f splice-quot ] curry ,
|
2007-09-20 18:09:08 -04:00
|
|
|
] { } make 1array define-optimizers
|
|
|
|
] assoc-each
|
2008-01-12 21:37:44 -05:00
|
|
|
|
|
|
|
: fixnum-shift-fast-pos? ( node -- ? )
|
|
|
|
#! Shifting 1 to the left won't overflow if the shift
|
|
|
|
#! count is small enough
|
|
|
|
dup dup node-in-d first node-literal 1 = [
|
|
|
|
dup node-in-d second node-interval
|
|
|
|
0 cell-bits tag-bits get - 2 - [a,b] interval-subset?
|
|
|
|
] [ drop f ] if ;
|
|
|
|
|
|
|
|
: fixnum-shift-fast-neg? ( node -- ? )
|
|
|
|
#! Shifting any number to the right won't overflow if the
|
|
|
|
#! shift count is small enough
|
|
|
|
dup node-in-d second node-interval
|
|
|
|
cell-bits 1- neg 0 [a,b] interval-subset? ;
|
|
|
|
|
|
|
|
: fixnum-shift-fast? ( node -- ? )
|
|
|
|
dup fixnum-shift-fast-pos?
|
|
|
|
[ drop t ] [ fixnum-shift-fast-neg? ] if ;
|
|
|
|
|
|
|
|
\ fixnum-shift {
|
|
|
|
{
|
|
|
|
[ dup fixnum-shift-fast? ]
|
2008-02-16 19:50:16 -05:00
|
|
|
[ [ fixnum-shift-fast ] f splice-quot ]
|
2008-01-12 21:37:44 -05:00
|
|
|
}
|
|
|
|
} define-optimizers
|