compiler.tree.propagation.call-effect: stronger call( inlining; now can inline 'a [ b ] curry call(' where 'a' is literal, [ b ] doesn't infer, but [ a b ] does infer. This simplifies classes.struct:memory>struct

db4
Slava Pestov 2009-09-07 17:45:03 -05:00
parent 1c97d33854
commit a1ae209f81
6 changed files with 86 additions and 47 deletions

View File

@ -316,6 +316,11 @@ STRUCT: struct-test-optimization
[ f ] [ [ memory>struct y>> ] { memory>struct y>> } inlined? ] unit-test
[ t ] [
[ struct-test-optimization <struct> struct-test-optimization <struct> [ x>> ] bi@ ]
{ x>> } inlined?
] unit-test
! Test cloning structs
STRUCT: clone-test-struct { x int } { y char[3] } ;
@ -340,3 +345,4 @@ STRUCT: struct-that's-a-word { x int } ;
: struct-that's-a-word ( -- ) "OOPS" throw ;
[ -77 ] [ S{ struct-that's-a-word { x -77 } } clone x>> ] unit-test

View File

@ -42,11 +42,9 @@ M: struct hashcode*
: struct-prototype ( class -- prototype ) "prototype" word-prop ; foldable
: memory>struct ( ptr class -- struct )
[ 1array ] dip slots>tuple ;
\ memory>struct [
dup struct-class? [ '[ _ boa ] ] [ drop f ] if
] 1 define-partial-eval
! This is sub-optimal if the class is not literal, but gets
! optimized down to efficient code if it is.
'[ _ boa ] call( ptr -- struct ) ; inline
<PRIVATE
: (init-struct) ( class with-prototype: ( prototype -- alien ) sans-prototype: ( class -- alien ) -- alien )

View File

@ -47,9 +47,15 @@ IN: compiler.tree.propagation.call-effect.tests
[ t ] [ [ 2 '[ _ ] 1 '[ _ + ] compose ] final-info first infer-value (( -- object )) effect= ] unit-test
[ t ] [ [ 2 '[ _ + ] ] final-info first infer-value (( object -- object )) effect= ] unit-test
[ f ] [ [ [ [ ] [ 1 ] if ] ] final-info first infer-value ] unit-test
[ f ] [ [ [ 1 ] '[ @ ] ] final-info first infer-value ] unit-test
[ t ] [ [ [ 1 ] '[ @ ] ] final-info first infer-value (( -- object )) effect= ] unit-test
[ f ] [ [ dup drop ] final-info first infer-value ] unit-test
! This should not hang
[ ] [ [ [ dup call( quot -- ) ] dup call( quot -- ) ] final-info drop ] unit-test
[ ] [ [ [ dup curry call( quot -- ) ] dup curry call( quot -- ) ] final-info drop ] unit-test
[ ] [ [ [ dup curry call( quot -- ) ] dup curry call( quot -- ) ] final-info drop ] unit-test
! This should get inlined, because the parameter to the curry is literal even though
! [ boa ] by itself doesn't infer
TUPLE: a-tuple x ;
[ V{ a-tuple } ] [ [ a-tuple '[ _ boa ] call( x -- tuple ) ] final-classes ] unit-test

View File

@ -50,12 +50,12 @@ M: curry cached-effect
M: compose cached-effect
[ first>> ] [ second>> ] bi [ cached-effect ] bi@ compose-effects* ;
: safe-infer ( quot -- effect )
[ infer ] [ 2drop +unknown+ ] recover ;
M: quotation cached-effect
dup cached-effect>>
[ ] [
[ [ infer ] [ 2drop +unknown+ ] recover dup ] keep
(>>cached-effect)
] ?if ;
[ ] [ [ safe-infer dup ] keep (>>cached-effect) ] ?if ;
: call-effect-unsafe? ( quot effect -- ? )
[ cached-effect ] dip
@ -116,6 +116,29 @@ M: quotation cached-effect
: execute-effect>quot ( effect -- quot )
inline-cache new '[ drop _ _ execute-effect-ic ] ;
! Some bookkeeping to make sure that crap like
! [ dup curry call( quot -- ) ] dup curry call( quot -- ) ]
! doesn't hang the compiler.
GENERIC: already-inlined-quot? ( quot -- ? )
M: curry already-inlined-quot? quot>> already-inlined-quot? ;
M: compose already-inlined-quot?
[ first>> already-inlined-quot? ]
[ second>> already-inlined-quot? ] bi or ;
M: quotation already-inlined-quot? already-inlined? ;
GENERIC: add-quot-to-history ( quot -- )
M: curry add-quot-to-history quot>> add-quot-to-history ;
M: compose add-quot-to-history
[ first>> add-quot-to-history ]
[ second>> add-quot-to-history ] bi ;
M: quotation add-quot-to-history add-to-history ;
: last2 ( seq -- penultimate ultimate )
2 tail* first2 ;
@ -129,22 +152,18 @@ ERROR: uninferable ;
(( -- object )) swap compose-effects ;
: (infer-value) ( value-info -- effect )
dup class>> {
{ \ quotation [
literal>> [ uninferable ] unless*
dup already-inlined? [ uninferable ] when
cached-effect dup +unknown+ = [ uninferable ] when
] }
{ \ curry [
slots>> third (infer-value)
remove-effect-input
] }
{ \ compose [
slots>> last2 [ (infer-value) ] bi@
compose-effects
] }
[ uninferable ]
} case ;
dup literal?>> [
literal>>
[ callable? [ uninferable ] unless ]
[ already-inlined-quot? [ uninferable ] when ]
[ safe-infer dup +unknown+ = [ uninferable ] when ] tri
] [
dup class>> {
{ \ curry [ slots>> third (infer-value) remove-effect-input ] }
{ \ compose [ slots>> last2 [ (infer-value) ] bi@ compose-effects ] }
[ uninferable ]
} case
] if ;
: infer-value ( value-info -- effect/f )
[ (infer-value) ]
@ -152,17 +171,20 @@ ERROR: uninferable ;
recover ;
: (value>quot) ( value-info -- quot )
dup class>> {
{ \ quotation [ literal>> dup add-to-history '[ drop @ ] ] }
{ \ curry [
slots>> third (value>quot)
'[ [ obj>> ] [ quot>> @ ] bi ]
] }
{ \ compose [
slots>> last2 [ (value>quot) ] bi@
'[ [ first>> @ ] [ second>> @ ] bi ]
] }
} case ;
dup literal?>> [
literal>> [ add-quot-to-history ] [ '[ drop @ ] ] bi
] [
dup class>> {
{ \ curry [
slots>> third (value>quot)
'[ [ obj>> ] [ quot>> @ ] bi ]
] }
{ \ compose [
slots>> last2 [ (value>quot) ] bi@
'[ [ first>> @ ] [ second>> @ ] bi ]
] }
} case
] if ;
: value>quot ( value-info -- quot: ( code effect -- ) )
(value>quot) '[ drop @ ] ;

View File

@ -97,11 +97,9 @@ SYMBOL: history
:: inline-word ( #call word -- ? )
word already-inlined? [ f ] [
#call word splicing-body [
[
word add-to-history
dup (propagate)
] with-scope
#call (>>body) t
word add-to-history
#call (>>body)
#call propagate-body
] [ f ] if*
] if ;
@ -141,5 +139,7 @@ SYMBOL: history
#! Note the logic here: if there's a custom inlining hook,
#! it is permitted to return f, which means that we try the
#! normal inlining heuristic.
dup custom-inlining? [ 2dup inline-custom ] [ f ] if
[ 2drop t ] [ (do-inlining) ] if ;
[
dup custom-inlining? [ 2dup inline-custom ] [ f ] if
[ 2drop t ] [ (do-inlining) ] if
] with-scope ;

View File

@ -1,6 +1,7 @@
IN: struct-arrays.tests
USING: classes.struct struct-arrays tools.test kernel math sequences
alien.syntax alien.c-types destructors libc accessors sequences.private ;
alien.syntax alien.c-types destructors libc accessors sequences.private
compiler.tree.debugger ;
STRUCT: test-struct-array
{ x int }
@ -52,4 +53,10 @@ STRUCT: fixed-string { text char[100] } ;
ALIEN: 123 4 fixed-string <direct-struct-array> [ (underlying)>> ] { } map-as
] unit-test
[ 10 "int" <struct-array> ] must-fail
[ 10 "int" <struct-array> ] must-fail
STRUCT: wig { x int } ;
: <bacon> ( -- wig ) 0 wig <struct-boa> ; inline
: waterfall ( -- a b ) 1 wig <struct-array> <bacon> swap first x>> ; inline
[ t ] [ [ waterfall ] { x>> } inlined? ] unit-test