]> gitweb.factorcode.org Git - factor.git/commitdiff
FFI rewrite part 4: parameter and return value unboxing redesign
authorSlava Pestov <slava@factorcode.org>
Tue, 11 May 2010 23:11:31 +0000 (19:11 -0400)
committerSlava Pestov <slava@factorcode.org>
Tue, 11 May 2010 23:11:44 +0000 (19:11 -0400)
18 files changed:
basis/classes/struct/struct.factor
basis/compiler/alien/alien.factor
basis/compiler/cfg/builder/alien/alien.factor
basis/compiler/cfg/builder/alien/params/authors.txt [new file with mode: 0644]
basis/compiler/cfg/builder/alien/params/params.factor [new file with mode: 0644]
basis/compiler/cfg/instructions/instructions.factor
basis/compiler/cfg/linear-scan/allocation/allocation.factor
basis/compiler/cfg/linear-scan/allocation/splitting/splitting.factor
basis/compiler/cfg/linear-scan/linear-scan-tests.factor
basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor
basis/compiler/codegen/codegen.factor
basis/cpu/architecture/architecture.factor
basis/cpu/ppc/ppc.factor
basis/cpu/x86/32/32.factor
basis/cpu/x86/64/64.factor
basis/cpu/x86/x86.factor
vm/contexts.hpp
vm/math.cpp

index d33f6fa35d85746e299c0f4e2406956b88243ab5..e0a168cb7d22bda2ac7e51af376216faaabecb16 100644 (file)
@@ -166,16 +166,10 @@ INSTANCE: struct-c-type value-type
 
 M: struct-c-type c-type ;
 
-: if-value-struct ( ctype true false -- )
-    [ dup value-struct? ] 2dip '[ drop void* @ ] if ; inline
-
-: if-small-struct ( c-type true false -- ? )
-    [ dup return-struct-in-registers? ] 2dip '[ f swap @ ] if ; inline
-
 M: struct-c-type base-type ;
 
 M: struct-c-type stack-size
-    [ heap-size cell align ] [ stack-size ] if-value-struct ;
+    dup value-struct? [ heap-size cell align ] [ drop cell ] if ;
 
 HOOK: flatten-struct-type cpu ( type -- reps )
 
index 58c5aaf73451c538210c6aa884ad20b2d07e2702..335b8bf5a4801ff2cf713f769a93995543693887 100644 (file)
@@ -9,7 +9,5 @@ IN: compiler.alien
 
 : alien-parameters ( params -- seq )
     dup parameters>>
-    swap return>> large-struct? [ struct-return-pointer-type prefix ] when ;
-
-: alien-return ( params -- type )
-    return>> dup large-struct? [ drop void ] when ;
+    swap return>> large-struct?
+    [ struct-return-on-stack? (stack-value) void* ? prefix ] when ;
index bf674fa9b9be9706381630c2a23c63def58a06dc..6544d656fa719d7996f5dcde6896c28c8e1c9fdc 100644 (file)
 ! Copyright (C) 2008, 2010 Slava Pestov.\r
 ! See http://factorcode.org/license.txt for BSD license.\r
 USING: accessors arrays layouts math math.order math.parser\r
-combinators fry sequences locals alien alien.private\r
+combinators fry make sequences locals alien alien.private\r
 alien.strings alien.c-types alien.libraries classes.struct\r
 namespaces kernel strings libc quotations cpu.architecture\r
 compiler.alien compiler.utilities compiler.tree compiler.cfg\r
-compiler.cfg.builder compiler.cfg.builder.blocks\r
-compiler.cfg.instructions compiler.cfg.stack-frame\r
-compiler.cfg.stacks compiler.cfg.registers\r
-compiler.cfg.hats ;\r
+compiler.cfg.builder compiler.cfg.builder.alien.params\r
+compiler.cfg.builder.blocks compiler.cfg.instructions\r
+compiler.cfg.stack-frame compiler.cfg.stacks\r
+compiler.cfg.registers compiler.cfg.hats ;\r
 FROM: compiler.errors => no-such-symbol no-such-library ;\r
 IN: compiler.cfg.builder.alien\r
 \r
-GENERIC: next-fastcall-param ( rep -- )\r
+! output is triples with shape { vreg rep on-stack? }\r
+GENERIC: unbox ( src c-type -- vregs )\r
 \r
-: ?dummy-stack-params ( rep -- )\r
-    dummy-stack-params? [ rep-size cell align stack-params +@ ] [ drop ] if ;\r
+M: c-type unbox\r
+    [ [ unboxer>> ] [ rep>> ] bi ^^unbox ] [ rep>> ] bi\r
+    f 3array 1array ;\r
 \r
-: ?dummy-int-params ( rep -- )\r
-    dummy-int-params? [ rep-size cell /i 1 max int-regs +@ ] [ drop ] if ;\r
-\r
-: ?dummy-fp-params ( rep -- )\r
-    drop dummy-fp-params? [ float-regs inc ] when ;\r
-\r
-M: int-rep next-fastcall-param\r
-    int-regs inc [ ?dummy-stack-params ] [ ?dummy-fp-params ] bi ;\r
-\r
-M: float-rep next-fastcall-param\r
-    float-regs inc [ ?dummy-stack-params ] [ ?dummy-int-params ] bi ;\r
-\r
-M: double-rep next-fastcall-param\r
-    float-regs inc [ ?dummy-stack-params ] [ ?dummy-int-params ] bi ;\r
-\r
-GENERIC# reg-class-full? 1 ( reg-class abi -- ? )\r
-\r
-M: stack-params reg-class-full? 2drop t ;\r
-\r
-M: reg-class reg-class-full?\r
-    [ get ] swap '[ _ param-regs length ] bi >= ;\r
-\r
-: alloc-stack-param ( rep -- n reg-class rep )\r
-    stack-params get\r
-    [ rep-size cell align stack-params +@ ] dip\r
-    stack-params dup ;\r
-\r
-: alloc-fastcall-param ( rep -- n reg-class rep )\r
-    [ [ reg-class-of get ] [ reg-class-of ] [ next-fastcall-param ] tri ] keep ;\r
-\r
-:: alloc-parameter ( rep abi -- reg rep )\r
-    rep dup reg-class-of abi reg-class-full?\r
-    [ alloc-stack-param ] [ alloc-fastcall-param ] if\r
-    [ abi param-reg ] dip ;\r
-\r
-: reset-fastcall-counts ( -- )\r
-    { int-regs float-regs stack-params } [ 0 swap set ] each ;\r
-\r
-: with-param-regs ( quot -- )\r
-    #! In quot you can call alloc-parameter\r
-    [ reset-fastcall-counts call ] with-scope ; inline\r
-\r
-:: move-parameters ( params word -- )\r
-    #! Moves values from C stack to registers (if word is\r
-    #! ##load-param-reg) and registers to C stack (if word is\r
-    #! ##save-param-reg).\r
-    0 params alien-parameters flatten-c-types [\r
-        [ params abi>> alloc-parameter word execute( offset reg rep -- ) ]\r
-        [ rep-size cell align + ]\r
-        2bi\r
-    ] each drop ; inline\r
-\r
-: parameter-offsets ( types -- offsets )\r
-    0 [ stack-size + ] accumulate nip ;\r
-\r
-: prepare-parameters ( parameters -- offsets types indices )\r
-    [ length iota <reversed> ] [ parameter-offsets ] [ ] tri ;\r
+M: long-long-type unbox\r
+    unboxer>> int-rep ^^unbox\r
+    0 cell\r
+    [\r
+        int-rep f ^^load-memory-imm\r
+        int-rep long-long-on-stack? 3array\r
+    ] bi-curry@ bi 2array ;\r
 \r
-GENERIC: unbox-parameter ( src n c-type -- )\r
+GENERIC: unbox-parameter ( src c-type -- vregs )\r
 \r
-M: c-type unbox-parameter\r
-    [ rep>> ] [ unboxer>> ] bi ##unbox ;\r
+M: c-type unbox-parameter unbox ;\r
 \r
-M: long-long-type unbox-parameter\r
-    unboxer>> ##unbox-long-long ;\r
+M: long-long-type unbox-parameter unbox ;\r
 \r
-M: struct-c-type unbox-parameter\r
-    [ [ ^^unbox-any-c-ptr ] 2dip ##unbox-large-struct ]\r
-    [ base-type unbox-parameter ]\r
-    if-value-struct ;\r
+M:: struct-c-type unbox-parameter ( src c-type -- )\r
+    src ^^unbox-any-c-ptr :> src\r
+    c-type value-struct? [\r
+        c-type flatten-struct-type\r
+        [| rep i |\r
+            src i cells rep f ^^load-memory-imm\r
+            rep struct-on-stack? 3array\r
+        ] map-index\r
+    ] [ { { src int-rep f } } ] if ;\r
 \r
-: unbox-parameters ( offset node -- )\r
-    parameters>> swap\r
-    '[\r
-        prepare-parameters\r
+: unbox-parameters ( parameters -- vregs )\r
+    [\r
+        [ length iota <reversed> ] keep\r
         [\r
-            [ <ds-loc> ^^peek ] [ _ + ] [ base-type ] tri*\r
+            [ <ds-loc> ^^peek ] [ base-type ] bi*\r
             unbox-parameter\r
-        ] 3each\r
+        ] 2map concat\r
     ]\r
-    [ length neg ##inc-d ]\r
-    bi ;\r
+    [ length neg ##inc-d ] bi ;\r
 \r
-: prepare-box-struct ( node -- offset )\r
+: prepare-struct-area ( vregs return -- vregs )\r
     #! Return offset on C stack where to store unboxed\r
     #! parameters. If the C function is returning a structure,\r
     #! the first parameter is an implicit target area pointer,\r
     #! so we need to use a different offset.\r
-    return>> large-struct?\r
-    [ ##prepare-box-struct cell ] [ 0 ] if ;\r
+    large-struct? [\r
+        ^^prepare-struct-area int-rep struct-return-on-stack?\r
+        3array prefix\r
+    ] when ;\r
+\r
+: (objects>registers) ( vregs -- )\r
+    ! Place instructions in reverse order, so that the\r
+    ! ##store-stack-param instructions come first. This is\r
+    ! because they are not clobber-insns and so we avoid some\r
+    ! spills that way.\r
+    [\r
+        first3 [ dup reg-class-of reg-class-full? ] dip or\r
+        [ [ alloc-stack-param ] keep \ ##store-stack-param new-insn ]\r
+        [ [ next-reg-param ] keep \ ##store-reg-param new-insn ]\r
+        if\r
+    ] map reverse % ;\r
 \r
 : objects>registers ( params -- )\r
     #! Generate code for unboxing a list of C types, then\r
     #! generate code for moving these parameters to registers on\r
     #! architectures where parameters are passed in registers.\r
-    [\r
-        [ prepare-box-struct ] keep\r
-        [ unbox-parameters ] keep\r
-        \ ##load-param-reg move-parameters\r
+    [ abi>> ] [ parameters>> ] [ return>> ] tri\r
+    '[ \r
+        _ unbox-parameters\r
+        _ prepare-struct-area\r
+        (objects>registers)\r
     ] with-param-regs ;\r
 \r
 GENERIC: box-return ( c-type -- dst )\r
@@ -126,6 +94,9 @@ M: c-type box-return
 M: long-long-type box-return\r
     [ f ] dip boxer>> ^^box-long-long ;\r
 \r
+: if-small-struct ( c-type true false -- ? )\r
+    [ dup return-struct-in-registers? ] 2dip '[ f swap @ ] if ; inline\r
+\r
 M: struct-c-type box-return\r
     [ ^^box-small-struct ] [ ^^box-large-struct ] if-small-struct ;\r
 \r
@@ -189,13 +160,12 @@ M: array dlsym-valid? '[ _ dlsym ] any? ;
 \r
 M: #alien-invoke emit-node\r
     [\r
-        ! Unbox parameters\r
-        dup objects>registers\r
-        ! Call function\r
-        dup alien-invoke-dlsym ##alien-invoke\r
-        ! Box return value\r
-        dup ##cleanup\r
-        box-return*\r
+        {\r
+            [ objects>registers ]\r
+            [ alien-invoke-dlsym ##alien-invoke ]\r
+            [ stack-cleanup ##cleanup ]\r
+            [ box-return* ]\r
+        } cleave\r
     ] emit-alien-node ;\r
 \r
 M: #alien-indirect emit-node\r
@@ -204,7 +174,7 @@ M: #alien-indirect emit-node
         {\r
             [ drop objects>registers ]\r
             [ nip ##alien-indirect ]\r
-            [ drop ##cleanup ]\r
+            [ drop stack-cleanup ##cleanup ]\r
             [ drop box-return* ]\r
         } 2cleave\r
     ] emit-alien-node ;\r
@@ -225,9 +195,18 @@ M: c-type box-parameter
 M: long-long-type box-parameter\r
     boxer>> ^^box-long-long ;\r
 \r
+: if-value-struct ( ctype true false -- )\r
+    [ dup value-struct? ] 2dip '[ drop void* @ ] if ; inline\r
+\r
 M: struct-c-type box-parameter\r
     [ ^^box-large-struct ] [ base-type box-parameter ] if-value-struct ;\r
 \r
+: parameter-offsets ( types -- offsets )\r
+    0 [ stack-size + ] accumulate nip ;\r
+\r
+: prepare-parameters ( parameters -- offsets types indices )\r
+    [ length iota <reversed> ] [ parameter-offsets ] [ ] tri ;\r
+\r
 : box-parameters ( params -- )\r
     alien-parameters\r
     [ length ##inc-d ]\r
@@ -239,10 +218,21 @@ M: struct-c-type box-parameter
         ] 3each\r
     ] bi ;\r
 \r
-: registers>objects ( node -- )\r
+:: alloc-parameter ( rep -- reg rep )\r
+    rep dup reg-class-of reg-class-full?\r
+    [ alloc-stack-param stack-params ] [ [ next-reg-param ] keep ] if ;\r
+\r
+: (registers>objects) ( params -- )\r
+    [ 0 ] dip alien-parameters flatten-c-types [\r
+        [ alloc-parameter ##save-param-reg ]\r
+        [ rep-size cell align + ]\r
+        2bi\r
+    ] each drop ; inline\r
+\r
+: registers>objects ( params -- )\r
     ! Generate code for boxing input parameters in a callback.\r
-    [\r
-        dup \ ##save-param-reg move-parameters\r
+    dup abi>> [\r
+        dup (registers>objects)\r
         ##begin-callback\r
         next-vreg next-vreg ##restore-context\r
         box-parameters\r
@@ -267,14 +257,13 @@ M: struct-c-type box-parameter
 GENERIC: unbox-return ( src c-type -- )\r
 \r
 M: c-type unbox-return\r
-    [ f ] dip [ rep>> ] [ unboxer>> ] bi ##unbox ;\r
+    unbox first first2 ##store-return ;\r
 \r
 M: long-long-type unbox-return\r
-    [ f ] dip unboxer>> ##unbox-long-long ;\r
+    unbox first2 [ first ] bi@ ##store-long-long-return ;\r
 \r
 M: struct-c-type unbox-return\r
-    [ ^^unbox-any-c-ptr ] dip\r
-    [ ##unbox-small-struct ] [ ##unbox-large-struct ] if-small-struct ;\r
+    [ ^^unbox-any-c-ptr ] dip ##store-struct-return ;\r
 \r
 M: #alien-callback emit-node\r
     dup params>> xt>> dup\r
@@ -284,11 +273,15 @@ M: #alien-callback emit-node
             [ registers>objects ]\r
             [ wrap-callback-quot ##alien-callback ]\r
             [\r
-                alien-return [ ##end-callback ] [\r
-                    [ D 0 ^^peek ] dip\r
-                    ##end-callback\r
-                    base-type unbox-return\r
-                ] if-void\r
+                return>> {\r
+                    { [ dup void eq? ] [ drop ##end-callback ] }\r
+                    { [ dup large-struct? ] [ drop ##end-callback ] }\r
+                    [\r
+                        [ D 0 ^^peek ] dip\r
+                        ##end-callback\r
+                        base-type unbox-return\r
+                    ]\r
+                } cond\r
             ] tri\r
         ] emit-alien-node\r
         ##epilogue\r
diff --git a/basis/compiler/cfg/builder/alien/params/authors.txt b/basis/compiler/cfg/builder/alien/params/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/compiler/cfg/builder/alien/params/params.factor b/basis/compiler/cfg/builder/alien/params/params.factor
new file mode 100644 (file)
index 0000000..85e9176
--- /dev/null
@@ -0,0 +1,49 @@
+! Copyright (C) 2010 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: cpu.architecture fry kernel layouts math math.order
+namespaces sequences vectors ;
+IN: compiler.cfg.builder.alien.params
+
+: alloc-stack-param ( rep -- n )
+    stack-params get
+    [ rep-size cell align stack-params +@ ] dip ;
+
+: ?dummy-stack-params ( rep -- )
+    dummy-stack-params? [ alloc-stack-param drop ] [ drop ] if ;
+
+: ?dummy-int-params ( rep -- )
+    dummy-int-params? [
+        rep-size cell /i 1 max
+        [ int-regs get [ pop* ] unless-empty ] times
+    ] [ drop ] if ;
+
+: ?dummy-fp-params ( rep -- )
+    drop dummy-fp-params? [ float-regs get [ pop* ] unless-empty ] when ;
+
+GENERIC: next-reg-param ( rep -- reg )
+
+M: int-rep next-reg-param
+    [ ?dummy-stack-params ] [ ?dummy-fp-params ] bi int-regs get pop ;
+
+M: float-rep next-reg-param
+    [ ?dummy-stack-params ] [ ?dummy-int-params ] bi float-regs get pop ;
+
+M: double-rep next-reg-param
+    [ ?dummy-stack-params ] [ ?dummy-int-params ] bi float-regs get pop ;
+
+GENERIC: reg-class-full? ( reg-class -- ? )
+
+M: stack-params reg-class-full? drop t ;
+
+M: reg-class reg-class-full? get empty? ;
+
+: init-reg-class ( abi reg-class -- )
+    [ swap param-regs <reversed> >vector ] keep set ;
+
+: with-param-regs ( abi quot -- )
+    '[
+        [ int-regs init-reg-class ]
+        [ float-regs init-reg-class ] bi
+        0 stack-params set
+        @
+    ] with-scope ; inline
index 36e840fc9e400612821e45dd88057f856b38dfc2..28b52e7a4fba5a31cea531ce1b53e6f0a96e846d 100644 (file)
@@ -612,6 +612,33 @@ literal: offset ;
 INSN: ##stack-frame
 literal: stack-frame ;
 
+INSN: ##unbox
+def: dst
+use: src/tagged-rep
+literal: unboxer rep ;
+
+INSN: ##store-reg-param
+use: src
+literal: reg rep ;
+
+INSN: ##store-stack-param
+use: src
+literal: n rep ;
+
+INSN: ##store-return
+use: src
+literal: rep ;
+
+INSN: ##store-struct-return
+use: src/int-rep
+literal: c-type ;
+
+INSN: ##store-long-long-return
+use: src1/int-rep src2/int-rep ;
+
+INSN: ##prepare-struct-area
+def: dst/int-rep ;
+
 INSN: ##box
 def: dst/tagged-rep
 literal: n rep boxer ;
@@ -628,32 +655,11 @@ INSN: ##box-large-struct
 def: dst/tagged-rep
 literal: n c-type ;
 
-INSN: ##unbox
-use: src/tagged-rep
-literal: n rep unboxer ;
-
-INSN: ##unbox-long-long
-use: src/tagged-rep
-literal: n unboxer ;
-
-INSN: ##unbox-large-struct
-use: src/int-rep
-literal: n c-type ;
-
-INSN: ##unbox-small-struct
-use: src/int-rep
-literal: c-type ;
-
-INSN: ##prepare-box-struct ;
-
-INSN: ##load-param-reg
-literal: offset reg rep ;
-
 INSN: ##alien-invoke
 literal: symbols dll ;
 
 INSN: ##cleanup
-literal: params ;
+literal: n ;
 
 INSN: ##alien-indirect
 use: src/int-rep ;
@@ -815,11 +821,10 @@ UNION: clobber-insn
 ##box-small-struct
 ##box-large-struct
 ##unbox
-##unbox-long-long
-##unbox-large-struct
-##unbox-small-struct
-##prepare-box-struct
-##load-param-reg
+##store-reg-param
+##store-return
+##store-struct-return
+##store-long-long-return
 ##alien-invoke
 ##alien-indirect
 ##alien-assembly
index c1b3f04ff451fe6b81a78e7f31bb923159824c44..361f5896fb801bc1df318ac5798a8cdd925aeecf 100644 (file)
@@ -1,7 +1,9 @@
 ! Copyright (C) 2008, 2010 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: accessors assocs heaps kernel namespaces sequences fry math
-math.order combinators arrays sorting compiler.utilities locals
+USING: accessors assocs binary-search combinators
+combinators.short-circuit heaps kernel namespaces
+sequences fry locals math math.order arrays sorting
+compiler.utilities
 compiler.cfg.linear-scan.live-intervals
 compiler.cfg.linear-scan.allocation.spilling
 compiler.cfg.linear-scan.allocation.splitting
@@ -34,15 +36,15 @@ IN: compiler.cfg.linear-scan.allocation
         [ drop assign-blocked-register ]
     } cond ;
 
-: spill-at-sync-point ( live-interval n -- ? )
+: spill-at-sync-point ( n live-interval -- ? )
     ! If the live interval has a definition at 'n', don't spill
-    2dup [ uses>> ] dip
-    '[ [ def-rep>> ] [ n>> _ = ] bi and ] any?
-    [ 2drop t ] [ spill f ] if ;
+    2dup find-use
+    { [ ] [ def-rep>> ] } 1&&
+    [ 2drop t ] [ swap spill f ] if ;
 
 : handle-sync-point ( n -- )
-    [ active-intervals get values ] dip
-    '[ [ _ spill-at-sync-point ] filter! drop ] each ;
+    active-intervals get values
+    [ [ spill-at-sync-point ] with filter! drop ] with each ;
 
 :: handle-progress ( n sync? -- )
     n {
@@ -69,11 +71,7 @@ M: sync-point handle ( sync-point -- )
     } cond ;
 
 : (allocate-registers) ( -- )
-    ! If a live interval begins at the same location as a sync point,
-    ! process the sync point before the live interval. This ensures that the
-    ! return value of C function calls doesn't get spilled and reloaded
-    ! unnecessarily.
-    unhandled-sync-points get unhandled-intervals get smallest-heap
+    unhandled-intervals get unhandled-sync-points get smallest-heap
     dup heap-empty? [ drop ] [ heap-pop drop handle (allocate-registers) ] if ;
 
 : finish-allocation ( -- )
index 6346ea41f513047bdfd490a0b8912ef4b4cbfb38..e3959906d2aad2afbc5875a1f881a2d2336c52a5 100644 (file)
@@ -39,7 +39,7 @@ ERROR: splitting-atomic-interval ;
 : check-split ( live-interval n -- )
     check-allocation? get [
         [ [ start>> ] dip > [ splitting-too-early ] when ]
-        [ [ end>> ] dip <= [ splitting-too-late ] when ]
+        [ [ end>> ] dip < [ splitting-too-late ] when ]
         [ drop [ end>> ] [ start>> ] bi = [ splitting-atomic-interval ] when ]
         2tri
     ] [ 2drop ] if ; inline
index 11e190d22663422c881b95319a4ac46c4607552d..60976eb30593d56fa7c90e9356ecb80661970f33 100644 (file)
@@ -145,25 +145,48 @@ H{
        { vreg 3 }
        { reg-class float-regs }
        { start 0 }
+       { end 2 }
+       { uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 1 f float-rep } } }
+       { ranges V{ T{ live-range f 0 2 } } }
+       { spill-to T{ spill-slot f 8 } }
+       { spill-rep float-rep }
+    }
+    f
+] [
+    T{ live-interval
+       { vreg 3 }
+       { reg-class float-regs }
+       { start 0 }
+       { end 5 }
+       { uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 1 f float-rep } T{ vreg-use f 5 f float-rep } } }
+       { ranges V{ T{ live-range f 0 5 } } }
+    } 5 split-for-spill
+] unit-test
+
+[
+    T{ live-interval
+       { vreg 4 }
+       { reg-class float-regs }
+       { start 0 }
        { end 1 }
        { uses V{ T{ vreg-use f 0 float-rep f } } }
        { ranges V{ T{ live-range f 0 1 } } }
-       { spill-to T{ spill-slot f 8 } }
+       { spill-to T{ spill-slot f 12 } }
        { spill-rep float-rep }
     }
     T{ live-interval
-       { vreg 3 }
+       { vreg 4 }
        { reg-class float-regs }
        { start 20 }
        { end 30 }
        { uses V{ T{ vreg-use f 20 f float-rep } T{ vreg-use f 30 f float-rep } } }
        { ranges V{ T{ live-range f 20 30 } } }
-       { reload-from T{ spill-slot f 8 } }
+       { reload-from T{ spill-slot f 12 } }
        { reload-rep float-rep }
     }
 ] [
     T{ live-interval
-       { vreg 3 }
+       { vreg 4 }
        { reg-class float-regs }
        { start 0 }
        { end 30 }
@@ -175,17 +198,17 @@ H{
 ! Don't insert reload if first usage is a def
 [
     T{ live-interval
-       { vreg 4 }
+       { vreg 5 }
        { reg-class float-regs }
        { start 0 }
        { end 1 }
        { uses V{ T{ vreg-use f 0 float-rep f } } }
        { ranges V{ T{ live-range f 0 1 } } }
-       { spill-to T{ spill-slot f 12 } }
+       { spill-to T{ spill-slot f 16 } }
        { spill-rep float-rep }
     }
     T{ live-interval
-       { vreg 4 }
+       { vreg 5 }
        { reg-class float-regs }
        { start 20 }
        { end 30 }
@@ -194,7 +217,7 @@ H{
     }
 ] [
     T{ live-interval
-       { vreg 4 }
+       { vreg 5 }
        { reg-class float-regs }
        { start 0 }
        { end 30 }
@@ -206,28 +229,28 @@ H{
 ! Multiple representations
 [
     T{ live-interval
-       { vreg 5 }
+       { vreg 6 }
        { reg-class float-regs }
        { start 0 }
        { end 11 }
        { uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 10 double-rep float-rep } } }
        { ranges V{ T{ live-range f 0 11 } } }
-       { spill-to T{ spill-slot f 16 } }
+       { spill-to T{ spill-slot f 24 } }
        { spill-rep double-rep }
     }
     T{ live-interval
-       { vreg 5 }
+       { vreg 6 }
        { reg-class float-regs }
        { start 20 }
        { end 20 }
        { uses V{ T{ vreg-use f 20 f double-rep } } }
        { ranges V{ T{ live-range f 20 20 } } }
-       { reload-from T{ spill-slot f 16 } }
+       { reload-from T{ spill-slot f 24 } }
        { reload-rep double-rep }
     }
 ] [
     T{ live-interval
-       { vreg 5 }
+       { vreg 6 }
        { reg-class float-regs }
        { start 0 }
        { end 20 }
index 50efbd43e43cb1035bf124e2036a47b32a1a3779..3dd9e5a6dbd8761ad77d90f5b3c538ad8540b941 100644 (file)
@@ -54,6 +54,10 @@ M: live-interval covers? ( insn# live-interval -- ? )
         covers?
     ] if ;
 
+:: find-use ( insn# live-interval -- vreg-use )
+    insn# live-interval uses>> [ n>> <=> ] with search nip
+    dup [ dup n>> insn# = [ drop f ] unless ] when ;
+
 : add-new-range ( from to live-interval -- )
     [ <live-range> ] dip ranges>> push ;
 
index 1958c4add184c74984d852cd6e31023369ac0a34..a927fa8ace10350207bb6f767f4df44695e2e537 100755 (executable)
@@ -276,20 +276,21 @@ CONDITIONAL: ##fixnum-sub %fixnum-sub
 CONDITIONAL: ##fixnum-mul %fixnum-mul
 
 ! FFI
+CODEGEN: ##unbox %unbox
+CODEGEN: ##store-reg-param %store-reg-param
+CODEGEN: ##store-stack-param %store-stack-param
+CODEGEN: ##store-return %store-return
+CODEGEN: ##store-struct-return %store-struct-return
+CODEGEN: ##store-long-long-return %store-long-long-return
+CODEGEN: ##prepare-struct-area %prepare-struct-area
 CODEGEN: ##box %box
 CODEGEN: ##box-long-long %box-long-long
 CODEGEN: ##box-large-struct %box-large-struct
 CODEGEN: ##box-small-struct %box-small-struct
-CODEGEN: ##unbox %unbox
-CODEGEN: ##unbox-long-long %unbox-long-long
-CODEGEN: ##unbox-large-struct %unbox-large-struct
-CODEGEN: ##unbox-small-struct %unbox-small-struct
-CODEGEN: ##prepare-box-struct %prepare-box-struct
-CODEGEN: ##load-param-reg %load-param-reg
+CODEGEN: ##save-param-reg %save-param-reg
 CODEGEN: ##alien-invoke %alien-invoke
 CODEGEN: ##cleanup %cleanup
 CODEGEN: ##alien-indirect %alien-indirect
-CODEGEN: ##save-param-reg %save-param-reg
 CODEGEN: ##begin-callback %begin-callback
 CODEGEN: ##alien-callback %alien-callback
 CODEGEN: ##end-callback %end-callback
index ae14e070265bdec9f894c898ff057b245371f0c4..e485cfcb1eed24c949199abd92a61925d1530bbe 100644 (file)
@@ -534,10 +534,6 @@ M: object immediate-comparand? ( n -- ? )
 : immediate-shift-count? ( n -- ? )
     0 cell-bits 1 - between? ;
 
-! What c-type describes the implicit struct return pointer for
-! large structs?
-HOOK: struct-return-pointer-type cpu ( -- c-type )
-
 ! Is this structure small enough to be returned in registers?
 HOOK: return-struct-in-registers? cpu ( c-type -- ? )
 
@@ -553,15 +549,30 @@ HOOK: dummy-int-params? cpu ( -- ? )
 ! If t, all int parameters are shadowed by dummy FP parameters
 HOOK: dummy-fp-params? cpu ( -- ? )
 
+! If t, long longs are never passed in param regs
+HOOK: long-long-on-stack? cpu ( -- ? )
+
+! If t, structs are never passed in param regs
+HOOK: struct-on-stack? cpu ( -- ? )
+
+! If t, the struct return pointer is never passed in a param reg
+HOOK: struct-return-on-stack? cpu ( -- ? )
+
 ! Call a function to convert a tagged pointer into a value that
 ! can be passed to a C function, or returned from a callback
-HOOK: %unbox cpu ( src n rep func -- )
+HOOK: %unbox cpu ( dst src func rep -- )
+
+HOOK: %store-reg-param cpu ( src reg rep -- )
 
-HOOK: %unbox-long-long cpu ( src n func -- )
+HOOK: %store-stack-param cpu ( src n rep -- )
 
-HOOK: %unbox-small-struct cpu ( src c-type -- )
+HOOK: %store-return cpu ( src rep -- )
 
-HOOK: %unbox-large-struct cpu ( src n c-type -- )
+HOOK: %store-struct-return cpu ( src reps -- )
+
+HOOK: %store-long-long-return cpu ( src1 src2 -- )
+
+HOOK: %prepare-struct-area cpu ( dst -- )
 
 ! Call a function to convert a value into a tagged pointer,
 ! possibly allocating a bignum, float, or alien instance,
@@ -570,25 +581,21 @@ HOOK: %box cpu ( dst n rep func -- )
 
 HOOK: %box-long-long cpu ( dst n func -- )
 
-HOOK: %prepare-box-struct cpu ( -- )
-
 HOOK: %box-small-struct cpu ( dst c-type -- )
 
 HOOK: %box-large-struct cpu ( dst n c-type -- )
 
 HOOK: %save-param-reg cpu ( stack reg rep -- )
 
-HOOK: %load-param-reg cpu ( stack reg rep -- )
-
 HOOK: %restore-context cpu ( temp1 temp2 -- )
 
 HOOK: %save-context cpu ( temp1 temp2 -- )
 
 HOOK: %alien-invoke cpu ( function library -- )
 
-HOOK: %cleanup cpu ( params -- )
+HOOK: %cleanup cpu ( n -- )
 
-M: object %cleanup ( params -- ) drop ;
+M: object %cleanup ( n -- ) drop ;
 
 HOOK: %alien-indirect cpu ( src -- )
 
index 3f3276cf0981c39e4c8bba5fcef84e28f94a34f1..233f5eb538db6a4ca248eac1b474663812c68177 100644 (file)
@@ -769,8 +769,6 @@ M: ppc immediate-bitwise? ( n -- ? ) 0 65535 between? ;
 
 M: ppc immediate-store? drop f ;
 
-M: ppc struct-return-pointer-type void* ;
-
 M: ppc return-struct-in-registers? ( c-type -- ? )
     c-type return-in-registers?>> ;
 
index bb091a2fe7f5062d027fc8bf292fd6aaf6f36a30..68957e0f5fd5cb1e4e26993520b0d9dc40baff40 100755 (executable)
@@ -95,17 +95,14 @@ M: x86.32 return-struct-in-registers? ( c-type -- ? )
     os { linux netbsd solaris } member? not
     and or ;
 
-: struct-return@ ( n -- operand )
-    [ next-stack@ ] [ stack-frame get params>> local@ ] if* ;
-
-! On x86, parameters are usually never passed in registers, except with Microsoft's
-! "thiscall" and "fastcall" abis
+! On x86, parameters are usually never passed in registers,
+! except with Microsoft's "thiscall" and "fastcall" abis
 M: int-regs return-reg drop EAX ;
 M: float-regs param-regs 2drop { } ;
 
 M: int-regs param-regs
     nip {
-        { thiscall [ { ECX     } ] }
+        { thiscall [ { ECX } ] }
         { fastcall [ { ECX EDX } ] }
         [ drop { } ]
     } case ;
@@ -133,6 +130,26 @@ M: x86.32 %prologue ( n -- )
 M: x86.32 %prepare-jump
     pic-tail-reg 0 MOV xt-tail-pic-offset rc-absolute-cell rel-here ;
 
+:: call-unbox-func ( src func -- )
+    EAX src tagged-rep %copy
+    4 save-vm-ptr
+    0 stack@ EAX MOV
+    func f %alien-invoke ;
+
+M:: x86.32 %unbox ( dst src func rep -- )
+    src func call-unbox-func
+    dst rep reg-class-of return-reg rep %copy ;
+
+M:: x86.32 %store-long-long-return ( src1 src2 n func -- )
+    src2 EAX = [ src1 src2 XCHG src2 src1 ] [ src1 src2 ] if :> ( src1 src2 )
+    EAX src1 int-rep %copy
+    EDX src2 int-rep %copy ;
+
+M:: x86.32 %store-struct-return ( src c-type -- )
+    EAX src int-rep %copy
+    EDX EAX 4 [+] MOV
+    EAX EAX [] MOV ;
+
 M: stack-params copy-register*
     drop
     {
@@ -142,8 +159,6 @@ M: stack-params copy-register*
 
 M: x86.32 %save-param-reg [ local@ ] 2dip %copy ;
 
-M: x86.32 %load-param-reg [ swap local@ ] dip %copy ;
-
 : (%box) ( n rep -- )
     #! If n is f, push the return register onto the stack; we
     #! are boxing a return value of a C function. If n is an
@@ -172,6 +187,9 @@ M:: x86.32 %box-long-long ( dst n func -- )
     func f %alien-invoke
     dst EAX tagged-rep %copy ;
 
+M: x86.32 struct-return@ ( n -- operand )
+    [ next-stack@ ] [ stack-frame get params>> local@ ] if* ;
+
 M:: x86.32 %box-large-struct ( dst n c-type -- )
     EDX n struct-return@ LEA
     8 save-vm-ptr
@@ -180,12 +198,6 @@ M:: x86.32 %box-large-struct ( dst n c-type -- )
     "from_value_struct" f %alien-invoke
     dst EAX tagged-rep %copy ;
 
-M: x86.32 %prepare-box-struct ( -- )
-    ! Compute target address for value struct return
-    EAX f struct-return@ LEA
-    ! Store it as the first parameter
-    0 local@ EAX MOV ;
-
 M:: x86.32 %box-small-struct ( dst c-type -- )
     #! Box a <= 8-byte struct returned in EAX:EDX. OS X only.
     12 save-vm-ptr
@@ -195,46 +207,6 @@ M:: x86.32 %box-small-struct ( dst c-type -- )
     "from_small_struct" f %alien-invoke
     dst EAX tagged-rep %copy ;
 
-:: call-unbox-func ( src func -- )
-    EAX src tagged-rep %copy
-    4 save-vm-ptr
-    0 stack@ EAX MOV
-    func f %alien-invoke ;
-
-M:: x86.32 %unbox ( src n rep func -- )
-    ! If n is f, we're unboxing a return value about to be
-    ! returned by the callback. Otherwise, we're unboxing
-    ! a parameter to a C function about to be called.
-    src func call-unbox-func
-    ! Store the return value on the C stack
-    n [ n local@ rep store-return-reg ] when ;
-
-M:: x86.32 %unbox-long-long ( src n func -- )
-    src func call-unbox-func
-    ! Store the return value on the C stack
-    n [
-        [ local@ EAX MOV ]
-        [ 4 + local@ EDX MOV ] bi
-    ] when* ;
-
-M: x86 %unbox-small-struct ( src size -- )
-    [ [ EAX ] dip int-rep %copy ]
-    [
-        heap-size 4 > [ EDX EAX 4 [+] MOV ] when
-        EAX EAX [] MOV
-    ] bi* ;
-
-M:: x86.32 %unbox-large-struct ( src n c-type -- )
-    EAX src int-rep %copy
-    EDX n local@ LEA
-    8 stack@ c-type heap-size MOV
-    4 stack@ EAX MOV
-    0 stack@ EDX MOV
-    "memcpy" "libc" load-library %alien-invoke ;
-
-M: x86.32 %alien-indirect ( src -- )
-    ?spill-slot CALL ;
-
 M: x86.32 %begin-callback ( -- )
     0 save-vm-ptr
     4 stack@ 0 MOV
@@ -280,7 +252,7 @@ M:: x86.32 %binary-float-function ( dst src1 src2 func -- )
 : funny-large-struct-return? ( params -- ? )
     #! MINGW ABI incompatibility disaster
     [ return>> large-struct? ]
-    [ abi>> mingw = os windows? not or ]
+    [ abi>> mingw eq? os windows? not or ]
     bi and ;
 
 : stack-arg-size ( params -- n )
@@ -301,8 +273,8 @@ M: x86.32 stack-cleanup ( params -- n )
         [ drop 0 ]
     } cond ;
 
-M: x86.32 %cleanup ( params -- )
-    stack-cleanup [ ESP swap SUB ] unless-zero ;
+M: x86.32 %cleanup ( n -- )
+    [ ESP swap SUB ] unless-zero ;
 
 M:: x86.32 %call-gc ( gc-roots -- )
     4 save-vm-ptr
@@ -315,12 +287,10 @@ M: x86.32 dummy-int-params? f ;
 
 M: x86.32 dummy-fp-params? f ;
 
-! Dreadful
-M: struct-c-type flatten-c-type stack-params (flatten-c-type) ;
-M: long-long-type flatten-c-type stack-params (flatten-c-type) ;
-M: c-type flatten-c-type dup rep>> int-rep? int-rep stack-params ? (flatten-c-type) ;
+M: x86.32 long-long-on-stack? t ;
+
+M: x86.32 structs-on-stack? t ;
 
-M: x86.32 struct-return-pointer-type
-    os linux? void* (stack-value) ? ;
+M: x86.32 struct-return-on-stack? os linux? not ;
 
 check-sse
index 8da9b6ac17ff9707bcb7b4ff7a3d55476c3f56f5..9c42a990963e68fc6fe5a5bdf0744534a0d6c8bf 100644 (file)
@@ -99,16 +99,11 @@ M:: x86.64 %dispatch ( src temp -- )
     [ (align-code) ]
     bi ;
 
-M: stack-params copy-register*
-    drop
-    {
-        { [ dup  integer? ] [ R11 swap next-stack@ MOV  R11 MOV ] }
-        { [ over integer? ] [ R11 swap MOV              param@ R11 MOV ] }
-    } cond ;
-
-M: x86.64 %save-param-reg [ param@ ] 2dip %copy ;
-
-M: x86.64 %load-param-reg [ swap param@ ] dip %copy ;
+M:: x86.64 %unbox ( dst src func rep -- )
+    param-reg-0 src tagged-rep %copy
+    param-reg-1 %mov-vm-ptr
+    func f %alien-invoke
+    dst rep reg-class-of return-reg rep %copy ;
 
 : with-return-regs ( quot -- )
     [
@@ -117,23 +112,13 @@ M: x86.64 %load-param-reg [ swap param@ ] dip %copy ;
         call
     ] with-scope ; inline
 
-M:: x86.64 %unbox ( src n rep func -- )
-    param-reg-0 src tagged-rep %copy
-    param-reg-1 %mov-vm-ptr
-    ! Call the unboxer
-    func f %alien-invoke
-    ! Store the return value on the C stack if this is an
-    ! alien-invoke, otherwise leave it the return register if
-    ! this is the end of alien-callback
-    n [ n rep reg-class-of return-reg rep %save-param-reg ] when ;
-
 : %unbox-struct-field ( rep i -- )
     R11 swap cells [+] swap reg-class-of {
         { int-regs [ int-regs get pop swap MOV ] }
         { float-regs [ float-regs get pop swap MOVSD ] }
     } case ;
 
-M:: x86.64 %unbox-small-struct ( src c-type -- )
+M:: x86.64 %store-struct-return ( src c-type -- )
     ! Move src to R11 so that we don't clobber it.
     R11 src int-rep %copy
     [
@@ -141,26 +126,18 @@ M:: x86.64 %unbox-small-struct ( src c-type -- )
         [ %unbox-struct-field ] each-index
     ] with-return-regs ;
 
-M:: x86.64 %unbox-large-struct ( src n c-type -- )
-    param-reg-1 src int-rep %copy
-    param-reg-0 n param@ LEA
-    param-reg-2 c-type heap-size MOV
-    "memcpy" "libc" load-library %alien-invoke ;
+M: stack-params copy-register*
+    drop
+    {
+        { [ dup  integer? ] [ R11 swap next-stack@ MOV  R11 MOV ] }
+        { [ over integer? ] [ R11 swap MOV              param@ R11 MOV ] }
+    } cond ;
 
-: load-return-value ( rep -- )
-    [ [ 0 ] dip reg-class-of cdecl param-reg ]
-    [ reg-class-of return-reg ]
-    [ ]
-    tri %copy ;
+M: x86.64 %save-param-reg [ param@ ] 2dip %copy ;
 
 M:: x86.64 %box ( dst n rep func -- )
-    n [
-        n
-        0 rep reg-class-of cdecl param-reg
-        rep %load-param-reg
-    ] [
-        rep load-return-value
-    ] if
+    0 rep reg-class-of cdecl param-reg
+    n [ n param@ ] [ rep reg-class-of return-reg ] if rep %copy
     rep int-rep? os windows? or param-reg-1 param-reg-0 ? %mov-vm-ptr
     func f %alien-invoke
     dst RAX tagged-rep %copy ;
@@ -185,7 +162,7 @@ M:: x86.64 %box-small-struct ( dst c-type -- )
         dst RAX tagged-rep %copy
     ] with-return-regs ;
 
-: struct-return@ ( n -- operand )
+M: x86.64 struct-return@ ( n -- operand )
     [ stack-frame get params>> ] unless* param@ ;
 
 M:: x86.64 %box-large-struct ( dst n c-type -- )
@@ -198,20 +175,11 @@ M:: x86.64 %box-large-struct ( dst n c-type -- )
     "from_value_struct" f %alien-invoke
     dst RAX tagged-rep %copy ;
 
-M: x86.64 %prepare-box-struct ( -- )
-    ! Compute target address for value struct return
-    RAX f struct-return@ LEA
-    ! Store it as the first parameter
-    0 param@ RAX MOV ;
-
 M: x86.64 %alien-invoke
     R11 0 MOV
     rc-absolute-cell rel-dlsym
     R11 CALL ;
 
-M: x86.64 %alien-indirect ( src -- )
-    ?spill-slot CALL ;
-
 M: x86.64 %begin-callback ( -- )
     param-reg-0 %mov-vm-ptr
     param-reg-1 0 MOV
@@ -249,7 +217,11 @@ M:: x86.64 %call-gc ( gc-roots -- )
     param-reg-1 %mov-vm-ptr
     "inline_gc" f %alien-invoke ;
 
-M: x86.64 struct-return-pointer-type void* ;
+M: x86.64 long-long-on-stack? f ;
+
+M: x86.64 struct-on-stack? f ;
+
+M: x86.64 struct-return-on-stack? f ;
 
 ! The result of reading 4 bytes from memory is a fixnum on
 ! x86-64.
index 1c3ff57a34f1cd3826c4795e30cf3499fc19c7b9..bdf325a8264b46a2cafd9eab820bf95f4d84736f 100644 (file)
@@ -1443,10 +1443,31 @@ M: x86.64 %scalar>integer ( dst src rep -- )
     } case ;
 
 M: x86 %vector>scalar %copy ;
+
 M: x86 %scalar>vector %copy ;
 
-M:: x86 %spill ( src rep dst -- ) dst src rep %copy ;
-M:: x86 %reload ( dst rep src -- ) dst src rep %copy ;
+M:: x86 %spill ( src rep dst -- )
+    dst src rep %copy ;
+
+M:: x86 %reload ( dst rep src -- )
+    dst src rep %copy ;
+
+M:: x86 %store-reg-param ( src reg rep -- )
+    reg src rep %copy ;
+
+M:: x86 %store-stack-param ( src n rep -- )
+    n param@ src rep %copy ;
+
+M:: x86 %store-return ( src rep -- )
+    rep reg-class-of return-reg src rep %copy ;
+
+HOOK: struct-return@ cpu ( n -- operand )
+
+M: x86 %prepare-struct-area ( dst -- )
+    f struct-return@ LEA ;
+
+M: x86 %alien-indirect ( src -- )
+    ?spill-slot CALL ;
 
 M: x86 %loop-entry 16 alignment [ NOP ] times ;
 
index 582fab173f9bc7a0c7b3c89c161d50ba5b10fca0..80dbf14740f229abc78427b223439ea8ecd8d93c 100644 (file)
@@ -36,6 +36,9 @@ struct context {
        set-context-object primitives */
        cell context_objects[context_object_count];
 
+       /* temporary area used by FFI code generation */
+       s64 long_long_return;
+
        context(cell datastack_size, cell retainstack_size, cell callstack_size);
        ~context();
 
index e64db2690ed43e58da2fca01da78a6606a316b2b..a418cbff1b43d53bf701f903b966901204d74cee 100755 (executable)
@@ -491,9 +491,10 @@ s64 factor_vm::to_signed_8(cell obj)
        }
 }
 
-VM_C_API s64 to_signed_8(cell obj, factor_vm *parent)
+VM_C_API s64 *to_signed_8(cell obj, factor_vm *parent)
 {
-       return parent->to_signed_8(obj);
+       parent->ctx->long_long_return = parent->to_signed_8(obj);
+       return &parent->ctx->long_long_return;
 }
 
 cell factor_vm::from_unsigned_8(u64 n)
@@ -524,9 +525,10 @@ u64 factor_vm::to_unsigned_8(cell obj)
        }
 }
 
-VM_C_API u64 to_unsigned_8(cell obj, factor_vm *parent)
+VM_C_API s64 *to_unsigned_8(cell obj, factor_vm *parent)
 {
-       return parent->to_unsigned_8(obj);
+       parent->ctx->long_long_return = parent->to_unsigned_8(obj);
+       return &parent->ctx->long_long_return;
 }
  
 VM_C_API cell from_float(float flo, factor_vm *parent)