compiler.tree.escape-analysis: if the output of an #introduce node has an immutable tuple class type declaration, and it is not passed to any subroutine calls, or returned from the word, then unbox it. This speeds up vector arithmetic words on specialized arrays, because the specialized array is unboxed up-front, eliminating an indirection on every loop iteration

db4
Slava Pestov 2009-08-09 16:29:21 -05:00
parent d19c403fee
commit 8a9c15ab0b
14 changed files with 164 additions and 41 deletions

View File

@ -246,3 +246,5 @@ M: #copy emit-node drop ;
M: #enter-recursive emit-node drop ; M: #enter-recursive emit-node drop ;
M: #phi emit-node drop ; M: #phi emit-node drop ;
M: #declare emit-node drop ;

View File

@ -49,19 +49,18 @@ PRIVATE>
: build-tree ( word/quot -- nodes ) : build-tree ( word/quot -- nodes )
[ f ] dip build-tree-with ; [ f ] dip build-tree-with ;
:: build-sub-tree ( #call word/quot -- nodes/f ) :: build-sub-tree ( in-d out-d word/quot -- nodes/f )
#! We don't want methods on mixins to have a declaration for that mixin. #! We don't want methods on mixins to have a declaration for that mixin.
#! This slows down compiler.tree.propagation.inlining since then every #! This slows down compiler.tree.propagation.inlining since then every
#! inlined usage of a method has an inline-dependency on the mixin, and #! inlined usage of a method has an inline-dependency on the mixin, and
#! not the more specific type at the call site. #! not the more specific type at the call site.
f specialize-method? [ f specialize-method? [
[ [
#call in-d>> word/quot build-tree-with unclip-last in-d>> :> in-d in-d word/quot build-tree-with unclip-last in-d>> :> in-d'
{ {
{ [ dup not ] [ ] } { [ dup not ] [ ] }
{ [ dup ends-with-terminate? ] [ #call out-d>> [ f swap #push ] map append ] } { [ dup ends-with-terminate? ] [ out-d [ f swap #push ] map append ] }
[ in-d #call out-d>> #copy suffix ] [ in-d' out-d [ [ length ] bi@ assert= ] [ #copy suffix ] 2bi ]
} cond } cond
] [ dup inference-error? [ drop f ] [ rethrow ] if ] recover ] [ dup inference-error? [ drop f ] [ rethrow ] if ] recover
] with-variable ; ] with-variable ;

View File

@ -89,8 +89,6 @@ M: #call cleanup*
[ ] [ ]
} cond ; } cond ;
M: #declare cleanup* drop f ;
: delete-unreachable-branches ( #branch -- ) : delete-unreachable-branches ( #branch -- )
dup live-branches>> '[ dup live-branches>> '[
_ _

View File

@ -43,7 +43,7 @@ GENERIC: node-uses-values ( node -- values )
M: #introduce node-uses-values drop f ; M: #introduce node-uses-values drop f ;
M: #push node-uses-values drop f ; M: #push node-uses-values drop f ;
M: #phi node-uses-values phi-in-d>> concat remove-bottom prune ; M: #phi node-uses-values phi-in-d>> concat remove-bottom prune ;
M: #declare node-uses-values declaration>> keys ; M: #declare node-uses-values drop f ;
M: #terminate node-uses-values [ in-d>> ] [ in-r>> ] bi append ; M: #terminate node-uses-values [ in-d>> ] [ in-r>> ] bi append ;
M: #shuffle node-uses-values [ in-d>> ] [ in-r>> ] bi append ; M: #shuffle node-uses-values [ in-d>> ] [ in-r>> ] bi append ;
M: #alien-callback node-uses-values drop f ; M: #alien-callback node-uses-values drop f ;

View File

@ -1,9 +1,16 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs namespaces sequences kernel math USING: accessors assocs namespaces sequences kernel math
combinators sets disjoint-sets fry stack-checker.values ; combinators sets disjoint-sets fry stack-checker.values ;
IN: compiler.tree.escape-analysis.allocations IN: compiler.tree.escape-analysis.allocations
! A map from values to classes. Only for #introduce outputs
SYMBOL: value-classes
: value-class ( value -- class ) value-classes get at ;
: set-value-class ( class value -- ) value-classes get set-at ;
! A map from values to one of the following: ! A map from values to one of the following:
! - f -- initial status, assigned to values we have not seen yet; ! - f -- initial status, assigned to values we have not seen yet;
! may potentially become an allocation later ! may potentially become an allocation later

View File

@ -0,0 +1,27 @@
IN: compiler.tree.escape-analysis.check.tests
USING: compiler.tree.escape-analysis.check tools.test accessors kernel
kernel.private math compiler.tree.builder compiler.tree.normalization
compiler.tree.propagation compiler.tree.cleanup ;
: test-checker ( quot -- ? )
build-tree normalize propagate cleanup run-escape-analysis? ;
[ t ] [
[ { complex } declare [ real>> ] [ imaginary>> ] bi ]
test-checker
] unit-test
[ t ] [
[ complex boa [ real>> ] [ imaginary>> ] bi ]
test-checker
] unit-test
[ t ] [
[ [ complex boa [ real>> ] [ imaginary>> ] bi ] when ]
test-checker
] unit-test
[ f ] [
[ swap 1 2 ? ]
test-checker
] unit-test

View File

@ -1,22 +1,32 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: classes classes.tuple math math.private accessors USING: classes classes.tuple math math.private accessors sequences
combinators kernel compiler.tree compiler.tree.combinators combinators.short-circuit kernel compiler.tree
compiler.tree.propagation.info ; compiler.tree.combinators compiler.tree.propagation.info ;
IN: compiler.tree.escape-analysis.check IN: compiler.tree.escape-analysis.check
GENERIC: run-escape-analysis* ( node -- ? ) GENERIC: run-escape-analysis* ( node -- ? )
M: #push run-escape-analysis* : unbox-inputs? ( nodes -- ? )
literal>> [ class immutable-tuple-class? ] [ complex? ] bi or ;
M: #call run-escape-analysis*
{ {
{ [ dup immutable-tuple-boa? ] [ t ] } [ length 2 >= ]
[ f ] [ first #introduce? ]
} cond nip ; [ second #declare? ]
} 1&& ;
M: node run-escape-analysis* drop f ;
: run-escape-analysis? ( nodes -- ? ) : run-escape-analysis? ( nodes -- ? )
[ run-escape-analysis* ] contains-node? ; { [ unbox-inputs? ] [ [ run-escape-analysis* ] any? ] } 1|| ;
M: #push run-escape-analysis*
literal>> class immutable-tuple-class? ;
M: #call run-escape-analysis*
immutable-tuple-boa? ;
M: #recursive run-escape-analysis*
child>> run-escape-analysis? ;
M: #branch run-escape-analysis*
children>> [ run-escape-analysis? ] any? ;
M: node run-escape-analysis* drop f ;

View File

@ -9,7 +9,7 @@ quotations.private prettyprint classes.tuple.private classes
classes.tuple namespaces classes.tuple namespaces
compiler.tree.propagation.info stack-checker.errors compiler.tree.propagation.info stack-checker.errors
compiler.tree.checker compiler.tree.checker
kernel.private ; kernel.private vectors ;
GENERIC: count-unboxed-allocations* ( m node -- n ) GENERIC: count-unboxed-allocations* ( m node -- n )
@ -24,6 +24,9 @@ M: #push count-unboxed-allocations*
dup literal>> class immutable-tuple-class? dup literal>> class immutable-tuple-class?
[ (count-unboxed-allocations) ] [ drop ] if ; [ (count-unboxed-allocations) ] [ drop ] if ;
M: #introduce count-unboxed-allocations*
out-d>> [ escaping-allocation? [ 1+ ] unless ] each ;
M: node count-unboxed-allocations* drop ; M: node count-unboxed-allocations* drop ;
: count-unboxed-allocations ( quot -- sizes ) : count-unboxed-allocations ( quot -- sizes )
@ -328,3 +331,17 @@ C: <ro-box> ro-box
TUPLE: empty-tuple ; TUPLE: empty-tuple ;
[ ] [ [ empty-tuple boa layout-of ] count-unboxed-allocations drop ] unit-test [ ] [ [ empty-tuple boa layout-of ] count-unboxed-allocations drop ] unit-test
! New feature!
[ 1 ] [ [ { complex } declare real>> ] count-unboxed-allocations ] unit-test
[ 1 ] [
[ { complex } declare [ real>> ] [ imaginary>> ] bi ]
count-unboxed-allocations
] unit-test
[ 0 ] [
[ { vector } declare length>> ]
count-unboxed-allocations
] unit-test

View File

@ -15,5 +15,6 @@ IN: compiler.tree.escape-analysis
init-escaping-values init-escaping-values
H{ } clone allocations set H{ } clone allocations set
H{ } clone slot-accesses set H{ } clone slot-accesses set
H{ } clone value-classes set
dup (escape-analysis) dup (escape-analysis)
compute-escaping-allocations ; compute-escaping-allocations ;

View File

@ -1,6 +1,6 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences USING: kernel sequences fry math namespaces
compiler.tree compiler.tree
compiler.tree.def-use compiler.tree.def-use
compiler.tree.escape-analysis.allocations ; compiler.tree.escape-analysis.allocations ;
@ -8,9 +8,14 @@ IN: compiler.tree.escape-analysis.nodes
GENERIC: escape-analysis* ( node -- ) GENERIC: escape-analysis* ( node -- )
SYMBOL: next-node
: each-with-next ( seq quot: ( elt -- ) -- )
dupd '[ 1 + _ ?nth next-node set @ ] each-index ; inline
: (escape-analysis) ( node -- ) : (escape-analysis) ( node -- )
[ [
[ node-defs-values introduce-values ] [ node-defs-values introduce-values ]
[ escape-analysis* ] [ escape-analysis* ]
bi bi
] each ; ] each-with-next ;

View File

@ -1,20 +1,36 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors sequences classes.tuple USING: kernel accessors sequences classes.tuple
classes.tuple.private arrays math math.private slots.private classes.tuple.private arrays math math.private slots.private
combinators deques search-deques namespaces fry classes combinators deques search-deques namespaces fry classes
classes.algebra stack-checker.state classes.algebra assocs stack-checker.state
compiler.tree compiler.tree
compiler.tree.propagation.info compiler.tree.propagation.info
compiler.tree.escape-analysis.nodes compiler.tree.escape-analysis.nodes
compiler.tree.escape-analysis.allocations ; compiler.tree.escape-analysis.allocations ;
IN: compiler.tree.escape-analysis.simple IN: compiler.tree.escape-analysis.simple
M: #declare escape-analysis* drop ;
M: #terminate escape-analysis* drop ; M: #terminate escape-analysis* drop ;
M: #renaming escape-analysis* inputs/outputs copy-values ; M: #renaming escape-analysis* inputs/outputs copy-values ;
M: #introduce escape-analysis* out-d>> unknown-allocations ; : declared-class ( value -- class/f )
next-node get dup #declare? [ declaration>> at ] [ 2drop f ] if ;
: record-param-allocation ( value class -- )
dup immutable-tuple-class? [
[ swap set-value-class ] [
all-slots [
[ <slot-value> dup ] [ class>> ] bi*
record-param-allocation
] map swap record-allocation
] 2bi
] [ drop unknown-allocation ] if ;
M: #introduce escape-analysis*
out-d>> [ dup declared-class record-param-allocation ] each ;
DEFER: record-literal-allocation DEFER: record-literal-allocation
@ -24,7 +40,6 @@ DEFER: record-literal-allocation
: object-slots ( object -- slots/f ) : object-slots ( object -- slots/f )
{ {
{ [ dup class immutable-tuple-class? ] [ tuple-slots ] } { [ dup class immutable-tuple-class? ] [ tuple-slots ] }
{ [ dup complex? ] [ [ real-part ] [ imaginary-part ] bi 2array ] }
[ drop f ] [ drop f ]
} cond ; } cond ;

View File

@ -31,8 +31,11 @@ SYMBOL: inlining-count
: splicing-call ( #call word -- nodes ) : splicing-call ( #call word -- nodes )
[ [ in-d>> ] [ out-d>> ] bi ] dip #call 1array ; [ [ in-d>> ] [ out-d>> ] bi ] dip #call 1array ;
: open-code-#call ( #call word/quot -- nodes/f )
[ [ in-d>> ] [ out-d>> ] bi ] dip build-sub-tree ;
: splicing-body ( #call quot/word -- nodes/f ) : splicing-body ( #call quot/word -- nodes/f )
build-sub-tree dup [ analyze-recursive normalize ] when ; open-code-#call dup [ analyze-recursive normalize ] when ;
! Dispatch elimination ! Dispatch elimination
: undo-inlining ( #call -- ? ) : undo-inlining ( #call -- ? )

View File

@ -1,12 +1,15 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: namespaces assocs accessors kernel combinators USING: namespaces assocs accessors kernel kernel.private combinators
classes.algebra sequences slots.private fry vectors classes.algebra sequences slots.private fry vectors
classes.tuple.private math math.private arrays classes.tuple.private math math.private arrays
stack-checker.branches stack-checker.branches stack-checker.values
compiler.utilities compiler.utilities
compiler.tree compiler.tree
compiler.tree.builder
compiler.tree.cleanup
compiler.tree.combinators compiler.tree.combinators
compiler.tree.propagation
compiler.tree.propagation.info compiler.tree.propagation.info
compiler.tree.escape-analysis.simple compiler.tree.escape-analysis.simple
compiler.tree.escape-analysis.allocations ; compiler.tree.escape-analysis.allocations ;
@ -72,8 +75,8 @@ M: #call unbox-tuples*
} case ; } case ;
M: #declare unbox-tuples* M: #declare unbox-tuples*
#! We don't look at declarations after propagation anyway. #! We don't look at declarations after escape analysis anyway.
f >>declaration ; drop f ;
M: #copy unbox-tuples* M: #copy unbox-tuples*
[ flatten-values ] change-in-d [ flatten-values ] change-in-d
@ -113,6 +116,44 @@ M: #return-recursive unbox-tuples*
[ flatten-values ] change-in-d [ flatten-values ] change-in-d
[ flatten-values ] change-out-d ; [ flatten-values ] change-out-d ;
: value-declaration ( value -- quot )
value-class [ 1array '[ _ declare ] ] [ [ ] ] if* ;
: unbox-parameter-quot ( allocation -- quot )
dup unboxed-allocation {
{ [ dup not ] [ 2drop [ ] ] }
{ [ dup array? ] [
[ value-declaration ] [
[
[ unbox-parameter-quot ] [ 2 + '[ _ slot ] ] bi*
prepose
] map-index
] bi* '[ @ _ cleave ]
] }
} cond ;
: unbox-parameters-quot ( values -- quot )
[ unbox-parameter-quot ] map
dup [ [ ] = ] all? [ drop [ ] ] [ '[ _ spread ] ] if ;
: unbox-parameters-nodes ( new-values old-values -- nodes )
[ flatten-values ] [ unbox-parameters-quot ] bi build-sub-tree ;
: new-and-old-values ( values -- new-values old-values )
[ length [ <value> ] replicate ] keep ;
: unbox-hairy-introduce ( #introduce -- nodes )
dup out-d>> new-and-old-values
[ drop >>out-d ] [ unbox-parameters-nodes ] 2bi
swap prefix propagate ;
M: #introduce unbox-tuples*
! For every output that is unboxed, insert slot accessors
! to convert the stack value into its unboxed form
dup out-d>> [ unboxed-allocation ] any? [
unbox-hairy-introduce
] when ;
! These nodes never participate in unboxing ! These nodes never participate in unboxing
: assert-not-unboxed ( values -- ) : assert-not-unboxed ( values -- )
dup array? dup array?
@ -123,8 +164,6 @@ M: #branch unbox-tuples* dup in-d>> assert-not-unboxed ;
M: #return unbox-tuples* dup in-d>> assert-not-unboxed ; M: #return unbox-tuples* dup in-d>> assert-not-unboxed ;
M: #introduce unbox-tuples* dup out-d>> assert-not-unboxed ;
M: #alien-invoke unbox-tuples* dup in-d>> assert-not-unboxed ; M: #alien-invoke unbox-tuples* dup in-d>> assert-not-unboxed ;
M: #alien-indirect unbox-tuples* dup in-d>> assert-not-unboxed ; M: #alien-indirect unbox-tuples* dup in-d>> assert-not-unboxed ;

View File

@ -9,7 +9,7 @@ IN: compiler.utilities
dup dup
'[ '[
@ [ @ [
dup array? dup [ array? ] [ vector? ] bi or
[ _ push-all ] [ _ push ] if [ _ push-all ] [ _ push ] if
] when* ] when*
] ]