12755751fSHerbert Dürr /**************************************************************
22755751fSHerbert Dürr  *
32755751fSHerbert Dürr  * Licensed to the Apache Software Foundation (ASF) under one
42755751fSHerbert Dürr  * or more contributor license agreements.  See the NOTICE file
52755751fSHerbert Dürr  * distributed with this work for additional information
62755751fSHerbert Dürr  * regarding copyright ownership.  The ASF licenses this file
72755751fSHerbert Dürr  * to you under the Apache License, Version 2.0 (the
82755751fSHerbert Dürr  * "License"); you may not use this file except in compliance
92755751fSHerbert Dürr  * with the License.  You may obtain a copy of the License at
102755751fSHerbert Dürr  *
112755751fSHerbert Dürr  *   http://www.apache.org/licenses/LICENSE-2.0
122755751fSHerbert Dürr  *
132755751fSHerbert Dürr  * Unless required by applicable law or agreed to in writing,
142755751fSHerbert Dürr  * software distributed under the License is distributed on an
152755751fSHerbert Dürr  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
162755751fSHerbert Dürr  * KIND, either express or implied.  See the License for the
172755751fSHerbert Dürr  * specific language governing permissions and limitations
182755751fSHerbert Dürr  * under the License.
192755751fSHerbert Dürr  *
202755751fSHerbert Dürr  *************************************************************/
212755751fSHerbert Dürr 
222755751fSHerbert Dürr 
232755751fSHerbert Dürr 
242755751fSHerbert Dürr // MARKER(update_precomp.py): autogen include statement, do not remove
252755751fSHerbert Dürr #include "precompiled_bridges.hxx"
262755751fSHerbert Dürr 
272755751fSHerbert Dürr // This is an implementation of the x86-64 ABI as described in 'System V
282755751fSHerbert Dürr // Application Binary Interface, AMD64 Architecture Processor Supplement'
292755751fSHerbert Dürr // (http://www.x86-64.org/documentation/abi-0.95.pdf)
302755751fSHerbert Dürr //
312755751fSHerbert Dürr // The code in this file is a modification of src/x86/ffi64.c from libffi
322755751fSHerbert Dürr // (http://sources.redhat.com/libffi/) which is under the following license:
332755751fSHerbert Dürr 
342755751fSHerbert Dürr /* -----------------------------------------------------------------------
352755751fSHerbert Dürr    ffi.c - Copyright (c) 2002  Bo Thorsen <bo@suse.de>
362755751fSHerbert Dürr 
372755751fSHerbert Dürr    x86-64 Foreign Function Interface
382755751fSHerbert Dürr 
392755751fSHerbert Dürr    Permission is hereby granted, free of charge, to any person obtaining
402755751fSHerbert Dürr    a copy of this software and associated documentation files (the
412755751fSHerbert Dürr    ``Software''), to deal in the Software without restriction, including
422755751fSHerbert Dürr    without limitation the rights to use, copy, modify, merge, publish,
432755751fSHerbert Dürr    distribute, sublicense, and/or sell copies of the Software, and to
442755751fSHerbert Dürr    permit persons to whom the Software is furnished to do so, subject to
452755751fSHerbert Dürr    the following conditions:
462755751fSHerbert Dürr 
472755751fSHerbert Dürr    The above copyright notice and this permission notice shall be included
482755751fSHerbert Dürr    in all copies or substantial portions of the Software.
492755751fSHerbert Dürr 
502755751fSHerbert Dürr    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
512755751fSHerbert Dürr    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
522755751fSHerbert Dürr    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
532755751fSHerbert Dürr    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
542755751fSHerbert Dürr    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
552755751fSHerbert Dürr    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
562755751fSHerbert Dürr    OTHER DEALINGS IN THE SOFTWARE.
572755751fSHerbert Dürr    ----------------------------------------------------------------------- */
582755751fSHerbert Dürr 
592755751fSHerbert Dürr #include "abi.hxx"
602755751fSHerbert Dürr 
612755751fSHerbert Dürr #include <rtl/ustring.hxx>
622755751fSHerbert Dürr 
632755751fSHerbert Dürr using namespace x86_64;
642755751fSHerbert Dürr 
652755751fSHerbert Dürr typedef struct
662755751fSHerbert Dürr {
672755751fSHerbert Dürr     /* Registers for argument passing.  */
682755751fSHerbert Dürr     long gpr[MAX_GPR_REGS];
692755751fSHerbert Dürr     __int128_t sse[MAX_SSE_REGS];
702755751fSHerbert Dürr 
712755751fSHerbert Dürr     /* Stack space for arguments.  */
722755751fSHerbert Dürr     char argspace[0];
732755751fSHerbert Dürr } stackLayout;
742755751fSHerbert Dürr 
752755751fSHerbert Dürr /* Register class used for passing given 64bit part of the argument.
762755751fSHerbert Dürr    These represent classes as documented by the PS ABI, with the exception
772755751fSHerbert Dürr    of SSESF, SSEDF classes, that are basically SSE class, just gcc will
782755751fSHerbert Dürr    use SF or DFmode move instead of DImode to avoid reformating penalties.
792755751fSHerbert Dürr 
802755751fSHerbert Dürr    Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
812755751fSHerbert Dürr    whenever possible (upper half does contain padding).
822755751fSHerbert Dürr  */
832755751fSHerbert Dürr enum x86_64_reg_class
842755751fSHerbert Dürr {
852755751fSHerbert Dürr     X86_64_NO_CLASS,
862755751fSHerbert Dürr     X86_64_INTEGER_CLASS,
872755751fSHerbert Dürr     X86_64_INTEGERSI_CLASS,
882755751fSHerbert Dürr     X86_64_SSE_CLASS,
892755751fSHerbert Dürr     X86_64_SSESF_CLASS,
902755751fSHerbert Dürr     X86_64_SSEDF_CLASS,
912755751fSHerbert Dürr     X86_64_SSEUP_CLASS,
922755751fSHerbert Dürr     X86_64_X87_CLASS,
932755751fSHerbert Dürr     X86_64_X87UP_CLASS,
942755751fSHerbert Dürr     X86_64_MEMORY_CLASS
952755751fSHerbert Dürr };
962755751fSHerbert Dürr 
972755751fSHerbert Dürr #define MAX_CLASSES 4
982755751fSHerbert Dürr 
992755751fSHerbert Dürr /* x86-64 register passing implementation.  See x86-64 ABI for details.  Goal
1002755751fSHerbert Dürr    of this code is to classify each 8bytes of incoming argument by the register
1012755751fSHerbert Dürr    class and assign registers accordingly.  */
1022755751fSHerbert Dürr 
1032755751fSHerbert Dürr /* Return the union class of CLASS1 and CLASS2.
1042755751fSHerbert Dürr    See the x86-64 PS ABI for details.  */
1052755751fSHerbert Dürr 
1062755751fSHerbert Dürr static enum x86_64_reg_class
merge_classes(enum x86_64_reg_class class1,enum x86_64_reg_class class2)1072755751fSHerbert Dürr merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
1082755751fSHerbert Dürr {
1092755751fSHerbert Dürr     /* Rule #1: If both classes are equal, this is the resulting class.  */
1102755751fSHerbert Dürr     if (class1 == class2)
1112755751fSHerbert Dürr         return class1;
1122755751fSHerbert Dürr 
1132755751fSHerbert Dürr     /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
1142755751fSHerbert Dürr        the other class.  */
1152755751fSHerbert Dürr     if (class1 == X86_64_NO_CLASS)
1162755751fSHerbert Dürr         return class2;
1172755751fSHerbert Dürr     if (class2 == X86_64_NO_CLASS)
1182755751fSHerbert Dürr         return class1;
1192755751fSHerbert Dürr 
1202755751fSHerbert Dürr     /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
1212755751fSHerbert Dürr     if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
1222755751fSHerbert Dürr         return X86_64_MEMORY_CLASS;
1232755751fSHerbert Dürr 
1242755751fSHerbert Dürr     /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
1252755751fSHerbert Dürr     if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
1262755751fSHerbert Dürr             || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
1272755751fSHerbert Dürr         return X86_64_INTEGERSI_CLASS;
1282755751fSHerbert Dürr     if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
1292755751fSHerbert Dürr             || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
1302755751fSHerbert Dürr         return X86_64_INTEGER_CLASS;
1312755751fSHerbert Dürr 
1322755751fSHerbert Dürr     /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used.  */
1332755751fSHerbert Dürr     if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
1342755751fSHerbert Dürr             || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
1352755751fSHerbert Dürr         return X86_64_MEMORY_CLASS;
1362755751fSHerbert Dürr 
1372755751fSHerbert Dürr     /* Rule #6: Otherwise class SSE is used.  */
1382755751fSHerbert Dürr     return X86_64_SSE_CLASS;
1392755751fSHerbert Dürr }
1402755751fSHerbert Dürr 
1412755751fSHerbert Dürr /* Classify the argument of type TYPE and mode MODE.
1422755751fSHerbert Dürr    CLASSES will be filled by the register class used to pass each word
1432755751fSHerbert Dürr    of the operand.  The number of words is returned.  In case the parameter
1442755751fSHerbert Dürr    should be passed in memory, 0 is returned. As a special case for zero
1452755751fSHerbert Dürr    sized containers, classes[0] will be NO_CLASS and 1 is returned.
1462755751fSHerbert Dürr 
1472755751fSHerbert Dürr    See the x86-64 PS ABI for details.
1482755751fSHerbert Dürr */
1492755751fSHerbert Dürr static int
classify_argument(typelib_TypeDescriptionReference * pTypeRef,enum x86_64_reg_class classes[],int byteOffset)1502755751fSHerbert Dürr classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset )
1512755751fSHerbert Dürr {
1522755751fSHerbert Dürr     switch ( pTypeRef->eTypeClass )
1532755751fSHerbert Dürr     {
1542755751fSHerbert Dürr         case typelib_TypeClass_VOID:
1552755751fSHerbert Dürr             classes[0] = X86_64_NO_CLASS;
1562755751fSHerbert Dürr             return 1;
1572755751fSHerbert Dürr         case typelib_TypeClass_CHAR:
1582755751fSHerbert Dürr         case typelib_TypeClass_BOOLEAN:
1592755751fSHerbert Dürr         case typelib_TypeClass_BYTE:
1602755751fSHerbert Dürr         case typelib_TypeClass_SHORT:
1612755751fSHerbert Dürr         case typelib_TypeClass_UNSIGNED_SHORT:
1622755751fSHerbert Dürr         case typelib_TypeClass_LONG:
1632755751fSHerbert Dürr         case typelib_TypeClass_UNSIGNED_LONG:
1642755751fSHerbert Dürr         case typelib_TypeClass_HYPER:
1652755751fSHerbert Dürr         case typelib_TypeClass_UNSIGNED_HYPER:
1662755751fSHerbert Dürr         case typelib_TypeClass_ENUM:
1672755751fSHerbert Dürr             if ( ( byteOffset % 8 + pTypeRef->pType->nSize ) <= 4 )
1682755751fSHerbert Dürr                 classes[0] = X86_64_INTEGERSI_CLASS;
1692755751fSHerbert Dürr             else
1702755751fSHerbert Dürr                 classes[0] = X86_64_INTEGER_CLASS;
1712755751fSHerbert Dürr             return 1;
1722755751fSHerbert Dürr         case typelib_TypeClass_FLOAT:
1732755751fSHerbert Dürr             if ( ( byteOffset % 8 ) == 0 )
1742755751fSHerbert Dürr                 classes[0] = X86_64_SSESF_CLASS;
1752755751fSHerbert Dürr             else
1762755751fSHerbert Dürr                 classes[0] = X86_64_SSE_CLASS;
1772755751fSHerbert Dürr             return 1;
1782755751fSHerbert Dürr         case typelib_TypeClass_DOUBLE:
1792755751fSHerbert Dürr             classes[0] = X86_64_SSEDF_CLASS;
1802755751fSHerbert Dürr             return 1;
1812755751fSHerbert Dürr         /*case LONGDOUBLE:
1822755751fSHerbert Dürr             classes[0] = X86_64_X87_CLASS;
1832755751fSHerbert Dürr             classes[1] = X86_64_X87UP_CLASS;
1842755751fSHerbert Dürr             return 2;*/
1852755751fSHerbert Dürr         case typelib_TypeClass_STRING:
1862755751fSHerbert Dürr         case typelib_TypeClass_TYPE:
1872755751fSHerbert Dürr         case typelib_TypeClass_ANY:
1882755751fSHerbert Dürr         case typelib_TypeClass_TYPEDEF:
1892755751fSHerbert Dürr         case typelib_TypeClass_UNION:
1902755751fSHerbert Dürr         case typelib_TypeClass_SEQUENCE:
1912755751fSHerbert Dürr         case typelib_TypeClass_ARRAY:
1922755751fSHerbert Dürr         case typelib_TypeClass_INTERFACE:
1932755751fSHerbert Dürr             return 0;
1942755751fSHerbert Dürr         case typelib_TypeClass_STRUCT:
1952755751fSHerbert Dürr         case typelib_TypeClass_EXCEPTION:
1962755751fSHerbert Dürr             {
1972755751fSHerbert Dürr                 typelib_TypeDescription * pTypeDescr = 0;
1982755751fSHerbert Dürr                 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
1992755751fSHerbert Dürr 
2002755751fSHerbert Dürr                 const int UNITS_PER_WORD = 8;
2012755751fSHerbert Dürr                 int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD;
2022755751fSHerbert Dürr                 enum x86_64_reg_class subclasses[MAX_CLASSES];
2032755751fSHerbert Dürr 
2042755751fSHerbert Dürr                 /* If the struct is larger than 16 bytes, pass it on the stack.  */
2052755751fSHerbert Dürr                 if ( pTypeDescr->nSize > 16 )
2062755751fSHerbert Dürr                 {
2072755751fSHerbert Dürr                     TYPELIB_DANGER_RELEASE( pTypeDescr );
2082755751fSHerbert Dürr                     return 0;
2092755751fSHerbert Dürr                 }
2102755751fSHerbert Dürr 
2112755751fSHerbert Dürr                 for ( int i = 0; i < words; i++ )
2122755751fSHerbert Dürr                     classes[i] = X86_64_NO_CLASS;
2132755751fSHerbert Dürr 
2142755751fSHerbert Dürr                 const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
2152755751fSHerbert Dürr 
2162755751fSHerbert Dürr                 /* Merge the fields of structure.  */
2172755751fSHerbert Dürr                 for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
2182755751fSHerbert Dürr                 {
2192755751fSHerbert Dürr                     typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
2202755751fSHerbert Dürr                     int offset = byteOffset + pStruct->pMemberOffsets[ nMember ];
2212755751fSHerbert Dürr 
2222755751fSHerbert Dürr                     int num = classify_argument( pTypeInStruct, subclasses, offset );
2232755751fSHerbert Dürr 
2242755751fSHerbert Dürr                     if ( num == 0 )
2252755751fSHerbert Dürr                     {
2262755751fSHerbert Dürr                         TYPELIB_DANGER_RELEASE( pTypeDescr );
2272755751fSHerbert Dürr                         return 0;
2282755751fSHerbert Dürr                     }
2292755751fSHerbert Dürr 
2302755751fSHerbert Dürr                     for ( int i = 0; i < num; i++ )
2312755751fSHerbert Dürr                     {
2322755751fSHerbert Dürr                         int pos = offset / 8;
2332755751fSHerbert Dürr                         classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
2342755751fSHerbert Dürr                     }
2352755751fSHerbert Dürr                 }
2362755751fSHerbert Dürr 
2372755751fSHerbert Dürr                 TYPELIB_DANGER_RELEASE( pTypeDescr );
2382755751fSHerbert Dürr 
2392755751fSHerbert Dürr                 /* Final merger cleanup.  */
2402755751fSHerbert Dürr                 for ( int i = 0; i < words; i++ )
2412755751fSHerbert Dürr                 {
2422755751fSHerbert Dürr                     /* If one class is MEMORY, everything should be passed in
2432755751fSHerbert Dürr                        memory.  */
2442755751fSHerbert Dürr                     if ( classes[i] == X86_64_MEMORY_CLASS )
2452755751fSHerbert Dürr                         return 0;
2462755751fSHerbert Dürr 
2472755751fSHerbert Dürr                     /* The X86_64_SSEUP_CLASS should be always preceded by
2482755751fSHerbert Dürr                        X86_64_SSE_CLASS.  */
2492755751fSHerbert Dürr                     if ( classes[i] == X86_64_SSEUP_CLASS
2502755751fSHerbert Dürr                             && ( i == 0 || classes[i - 1] != X86_64_SSE_CLASS ) )
2512755751fSHerbert Dürr                         classes[i] = X86_64_SSE_CLASS;
2522755751fSHerbert Dürr 
2532755751fSHerbert Dürr                     /*  X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS.  */
2542755751fSHerbert Dürr                     if ( classes[i] == X86_64_X87UP_CLASS
2552755751fSHerbert Dürr                             && ( i == 0 || classes[i - 1] != X86_64_X87_CLASS ) )
2562755751fSHerbert Dürr                         classes[i] = X86_64_SSE_CLASS;
2572755751fSHerbert Dürr                 }
2582755751fSHerbert Dürr                 return words;
2592755751fSHerbert Dürr             }
2602755751fSHerbert Dürr 
2612755751fSHerbert Dürr         default:
2622755751fSHerbert Dürr #if OSL_DEBUG_LEVEL > 1
2632755751fSHerbert Dürr             OSL_TRACE( "Unhandled case: pType->eTypeClass == %d\n", pTypeRef->eTypeClass );
2642755751fSHerbert Dürr #endif
2652755751fSHerbert Dürr             OSL_ASSERT(0);
2662755751fSHerbert Dürr     }
2672755751fSHerbert Dürr     return 0; /* Never reached.  */
2682755751fSHerbert Dürr }
2692755751fSHerbert Dürr 
2702755751fSHerbert Dürr /* Examine the argument and return set number of register required in each
2712755751fSHerbert Dürr    class.  Return 0 iff parameter should be passed in memory.  */
examine_argument(typelib_TypeDescriptionReference * pTypeRef,bool bInReturn,int & nUsedGPR,int & nUsedSSE)2722755751fSHerbert Dürr bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedSSE )
2732755751fSHerbert Dürr {
2742755751fSHerbert Dürr     enum x86_64_reg_class classes[MAX_CLASSES];
2752755751fSHerbert Dürr     int n;
2762755751fSHerbert Dürr 
2772755751fSHerbert Dürr     n = classify_argument( pTypeRef, classes, 0 );
2782755751fSHerbert Dürr 
2792755751fSHerbert Dürr     if ( n == 0 )
2802755751fSHerbert Dürr         return false;
2812755751fSHerbert Dürr 
2822755751fSHerbert Dürr     nUsedGPR = 0;
2832755751fSHerbert Dürr     nUsedSSE = 0;
2842755751fSHerbert Dürr     for ( n--; n >= 0; n-- )
2852755751fSHerbert Dürr         switch ( classes[n] )
2862755751fSHerbert Dürr         {
2872755751fSHerbert Dürr             case X86_64_INTEGER_CLASS:
2882755751fSHerbert Dürr             case X86_64_INTEGERSI_CLASS:
2892755751fSHerbert Dürr                 nUsedGPR++;
2902755751fSHerbert Dürr                 break;
2912755751fSHerbert Dürr             case X86_64_SSE_CLASS:
2922755751fSHerbert Dürr             case X86_64_SSESF_CLASS:
2932755751fSHerbert Dürr             case X86_64_SSEDF_CLASS:
2942755751fSHerbert Dürr                 nUsedSSE++;
2952755751fSHerbert Dürr                 break;
2962755751fSHerbert Dürr             case X86_64_NO_CLASS:
2972755751fSHerbert Dürr             case X86_64_SSEUP_CLASS:
2982755751fSHerbert Dürr                 break;
2992755751fSHerbert Dürr             case X86_64_X87_CLASS:
3002755751fSHerbert Dürr             case X86_64_X87UP_CLASS:
3012755751fSHerbert Dürr                 if ( !bInReturn )
3022755751fSHerbert Dürr                     return false;
3032755751fSHerbert Dürr                 break;
3042755751fSHerbert Dürr             default:
3052755751fSHerbert Dürr #if OSL_DEBUG_LEVEL > 1
3062755751fSHerbert Dürr             OSL_TRACE( "Unhandled case: classes[n] == %d\n", classes[n] );
3072755751fSHerbert Dürr #endif
3082755751fSHerbert Dürr             OSL_ASSERT(0);
3092755751fSHerbert Dürr         }
3102755751fSHerbert Dürr     return true;
3112755751fSHerbert Dürr }
3122755751fSHerbert Dürr 
return_in_hidden_param(typelib_TypeDescriptionReference * pTypeRef)3132755751fSHerbert Dürr bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef )
3142755751fSHerbert Dürr {
3152755751fSHerbert Dürr     int g, s;
3162755751fSHerbert Dürr 
3172755751fSHerbert Dürr     return examine_argument( pTypeRef, true, g, s ) == 0;
3182755751fSHerbert Dürr }
3192755751fSHerbert Dürr 
fill_struct(typelib_TypeDescriptionReference * pTypeRef,const sal_uInt64 * pGPR,const double * pSSE,void * pStruct)3202755751fSHerbert Dürr void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct )
3212755751fSHerbert Dürr {
3222755751fSHerbert Dürr     enum x86_64_reg_class classes[MAX_CLASSES];
3232755751fSHerbert Dürr     int n;
3242755751fSHerbert Dürr 
3252755751fSHerbert Dürr     n = classify_argument( pTypeRef, classes, 0 );
3262755751fSHerbert Dürr 
3272755751fSHerbert Dürr     sal_uInt64 *pStructAlign = reinterpret_cast<sal_uInt64 *>( pStruct );
3282755751fSHerbert Dürr     for ( n--; n >= 0; n-- )
3292755751fSHerbert Dürr         switch ( classes[n] )
3302755751fSHerbert Dürr         {
3312755751fSHerbert Dürr             case X86_64_INTEGER_CLASS:
3322755751fSHerbert Dürr             case X86_64_INTEGERSI_CLASS:
3332755751fSHerbert Dürr                 *pStructAlign++ = *pGPR++;
3342755751fSHerbert Dürr                 break;
3352755751fSHerbert Dürr             case X86_64_SSE_CLASS:
3362755751fSHerbert Dürr             case X86_64_SSESF_CLASS:
3372755751fSHerbert Dürr             case X86_64_SSEDF_CLASS:
3382755751fSHerbert Dürr                 *pStructAlign++ = *reinterpret_cast<const sal_uInt64 *>( pSSE++ );
3392755751fSHerbert Dürr                 break;
3402755751fSHerbert Dürr             default:
3412755751fSHerbert Dürr                 break;
3422755751fSHerbert Dürr         }
3432755751fSHerbert Dürr }
3442755751fSHerbert Dürr 
3452755751fSHerbert Dürr #if 0
3462755751fSHerbert Dürr 
3472755751fSHerbert Dürr /* Functions to load floats and double to an SSE register placeholder.  */
3482755751fSHerbert Dürr extern void float2sse (float, __int128_t *);
3492755751fSHerbert Dürr extern void double2sse (double, __int128_t *);
3502755751fSHerbert Dürr extern void floatfloat2sse (void *, __int128_t *);
3512755751fSHerbert Dürr 
3522755751fSHerbert Dürr /* Functions to put the floats and doubles back.  */
3532755751fSHerbert Dürr extern float sse2float (__int128_t *);
3542755751fSHerbert Dürr extern double sse2double (__int128_t *);
3552755751fSHerbert Dürr extern void sse2floatfloat(__int128_t *, void *);
3562755751fSHerbert Dürr 
3572755751fSHerbert Dürr /*@-exportheader@*/
3582755751fSHerbert Dürr void
3592755751fSHerbert Dürr ffi_prep_args (stackLayout *stack, extended_cif *ecif)
3602755751fSHerbert Dürr /*@=exportheader@*/
3612755751fSHerbert Dürr {
3622755751fSHerbert Dürr   int gprcount, ssecount, i, g, s;
3632755751fSHerbert Dürr   void **p_argv;
3642755751fSHerbert Dürr   void *argp = &stack->argspace;
3652755751fSHerbert Dürr   ffi_type **p_arg;
3662755751fSHerbert Dürr 
3672755751fSHerbert Dürr   /* First check if the return value should be passed in memory. If so,
3682755751fSHerbert Dürr      pass the pointer as the first argument.  */
3692755751fSHerbert Dürr   gprcount = ssecount = 0;
3702755751fSHerbert Dürr   if (ecif->cif->rtype->type != FFI_TYPE_VOID
3712755751fSHerbert Dürr       && examine_argument (ecif->cif->rtype, 1, &g, &s) == 0)
3722755751fSHerbert Dürr     (void *)stack->gpr[gprcount++] = ecif->rvalue;
3732755751fSHerbert Dürr 
3742755751fSHerbert Dürr   for (i=ecif->cif->nargs, p_arg=ecif->cif->arg_types, p_argv = ecif->avalue;
3752755751fSHerbert Dürr        i!=0; i--, p_arg++, p_argv++)
3762755751fSHerbert Dürr     {
3772755751fSHerbert Dürr       int in_register = 0;
3782755751fSHerbert Dürr 
3792755751fSHerbert Dürr       switch ((*p_arg)->type)
3802755751fSHerbert Dürr 	{
3812755751fSHerbert Dürr 	case FFI_TYPE_SINT8:
3822755751fSHerbert Dürr 	case FFI_TYPE_SINT16:
3832755751fSHerbert Dürr 	case FFI_TYPE_SINT32:
3842755751fSHerbert Dürr 	case FFI_TYPE_SINT64:
3852755751fSHerbert Dürr 	case FFI_TYPE_UINT8:
3862755751fSHerbert Dürr 	case FFI_TYPE_UINT16:
3872755751fSHerbert Dürr 	case FFI_TYPE_UINT32:
3882755751fSHerbert Dürr 	case FFI_TYPE_UINT64:
3892755751fSHerbert Dürr 	case FFI_TYPE_POINTER:
3902755751fSHerbert Dürr 	  if (gprcount < MAX_GPR_REGS)
3912755751fSHerbert Dürr 	    {
3922755751fSHerbert Dürr 	      stack->gpr[gprcount] = 0;
3932755751fSHerbert Dürr 	      stack->gpr[gprcount++] = *(long long *)(*p_argv);
3942755751fSHerbert Dürr 	      in_register = 1;
3952755751fSHerbert Dürr 	    }
3962755751fSHerbert Dürr 	  break;
3972755751fSHerbert Dürr 
3982755751fSHerbert Dürr 	case FFI_TYPE_FLOAT:
3992755751fSHerbert Dürr 	  if (ssecount < MAX_SSE_REGS)
4002755751fSHerbert Dürr 	    {
4012755751fSHerbert Dürr 	      float2sse (*(float *)(*p_argv), &stack->sse[ssecount++]);
4022755751fSHerbert Dürr 	      in_register = 1;
4032755751fSHerbert Dürr 	    }
4042755751fSHerbert Dürr 	  break;
4052755751fSHerbert Dürr 
4062755751fSHerbert Dürr 	case FFI_TYPE_DOUBLE:
4072755751fSHerbert Dürr 	  if (ssecount < MAX_SSE_REGS)
4082755751fSHerbert Dürr 	    {
4092755751fSHerbert Dürr 	      double2sse (*(double *)(*p_argv), &stack->sse[ssecount++]);
4102755751fSHerbert Dürr 	      in_register = 1;
4112755751fSHerbert Dürr 	    }
4122755751fSHerbert Dürr 	  break;
4132755751fSHerbert Dürr 	}
4142755751fSHerbert Dürr 
4152755751fSHerbert Dürr       if (in_register)
4162755751fSHerbert Dürr 	continue;
4172755751fSHerbert Dürr 
4182755751fSHerbert Dürr       /* Either all places in registers where filled, or this is a
4192755751fSHerbert Dürr 	 type that potentially goes into a memory slot.  */
4202755751fSHerbert Dürr       if (examine_argument (*p_arg, 0, &g, &s) == 0
4212755751fSHerbert Dürr 	  || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
4222755751fSHerbert Dürr 	{
4232755751fSHerbert Dürr 	  /* Pass this argument in memory.  */
4242755751fSHerbert Dürr 	  argp = (void *)ALIGN(argp, (*p_arg)->alignment);
4252755751fSHerbert Dürr 	  memcpy (argp, *p_argv, (*p_arg)->size);
4262755751fSHerbert Dürr 	  argp += (*p_arg)->size;
4272755751fSHerbert Dürr 	}
4282755751fSHerbert Dürr       else
4292755751fSHerbert Dürr 	{
4302755751fSHerbert Dürr 	  /* All easy cases are eliminated. Now fire the big guns.  */
4312755751fSHerbert Dürr 
4322755751fSHerbert Dürr 	  enum x86_64_reg_class classes[MAX_CLASSES];
4332755751fSHerbert Dürr 	  int j, num;
4342755751fSHerbert Dürr 	  void *a;
4352755751fSHerbert Dürr 
4362755751fSHerbert Dürr 	  num = classify_argument (*p_arg, classes, 0);
4372755751fSHerbert Dürr 	  for (j=0, a=*p_argv; j<num; j++, a+=8)
4382755751fSHerbert Dürr 	    {
4392755751fSHerbert Dürr 	      switch (classes[j])
4402755751fSHerbert Dürr 		{
4412755751fSHerbert Dürr 		case X86_64_INTEGER_CLASS:
4422755751fSHerbert Dürr 		case X86_64_INTEGERSI_CLASS:
4432755751fSHerbert Dürr 		  stack->gpr[gprcount++] = *(long long *)a;
4442755751fSHerbert Dürr 		  break;
4452755751fSHerbert Dürr 		case X86_64_SSE_CLASS:
4462755751fSHerbert Dürr 		  floatfloat2sse (a, &stack->sse[ssecount++]);
4472755751fSHerbert Dürr 		  break;
4482755751fSHerbert Dürr 		case X86_64_SSESF_CLASS:
4492755751fSHerbert Dürr 		  float2sse (*(float *)a, &stack->sse[ssecount++]);
4502755751fSHerbert Dürr 		  break;
4512755751fSHerbert Dürr 		case X86_64_SSEDF_CLASS:
4522755751fSHerbert Dürr 		  double2sse (*(double *)a, &stack->sse[ssecount++]);
4532755751fSHerbert Dürr 		  break;
4542755751fSHerbert Dürr 		default:
4552755751fSHerbert Dürr 		  abort();
4562755751fSHerbert Dürr 		}
4572755751fSHerbert Dürr 	    }
4582755751fSHerbert Dürr 	}
4592755751fSHerbert Dürr     }
4602755751fSHerbert Dürr }
4612755751fSHerbert Dürr 
4622755751fSHerbert Dürr /* Perform machine dependent cif processing.  */
4632755751fSHerbert Dürr ffi_status
4642755751fSHerbert Dürr ffi_prep_cif_machdep (ffi_cif *cif)
4652755751fSHerbert Dürr {
4662755751fSHerbert Dürr   int gprcount, ssecount, i, g, s;
4672755751fSHerbert Dürr 
4682755751fSHerbert Dürr   gprcount = ssecount = 0;
4692755751fSHerbert Dürr 
4702755751fSHerbert Dürr   /* Reset the byte count. We handle this size estimation here.  */
4712755751fSHerbert Dürr   cif->bytes = 0;
4722755751fSHerbert Dürr 
4732755751fSHerbert Dürr   /* If the return value should be passed in memory, pass the pointer
4742755751fSHerbert Dürr      as the first argument. The actual memory isn't allocated here.  */
4752755751fSHerbert Dürr   if (cif->rtype->type != FFI_TYPE_VOID
4762755751fSHerbert Dürr       && examine_argument (cif->rtype, 1, &g, &s) == 0)
4772755751fSHerbert Dürr     gprcount = 1;
4782755751fSHerbert Dürr 
4792755751fSHerbert Dürr   /* Go over all arguments and determine the way they should be passed.
4802755751fSHerbert Dürr      If it's in a register and there is space for it, let that be so. If
4812755751fSHerbert Dürr      not, add it's size to the stack byte count.  */
4822755751fSHerbert Dürr   for (i=0; i<cif->nargs; i++)
4832755751fSHerbert Dürr     {
4842755751fSHerbert Dürr       if (examine_argument (cif->arg_types[i], 0, &g, &s) == 0
4852755751fSHerbert Dürr 	  || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
4862755751fSHerbert Dürr 	{
4872755751fSHerbert Dürr 	  /* This is passed in memory. First align to the basic type.  */
4882755751fSHerbert Dürr 	  cif->bytes = ALIGN(cif->bytes, cif->arg_types[i]->alignment);
4892755751fSHerbert Dürr 
4902755751fSHerbert Dürr 	  /* Stack arguments are *always* at least 8 byte aligned.  */
4912755751fSHerbert Dürr 	  cif->bytes = ALIGN(cif->bytes, 8);
4922755751fSHerbert Dürr 
4932755751fSHerbert Dürr 	  /* Now add the size of this argument.  */
4942755751fSHerbert Dürr 	  cif->bytes += cif->arg_types[i]->size;
4952755751fSHerbert Dürr 	}
4962755751fSHerbert Dürr       else
4972755751fSHerbert Dürr 	{
4982755751fSHerbert Dürr 	  gprcount += g;
4992755751fSHerbert Dürr 	  ssecount += s;
5002755751fSHerbert Dürr 	}
5012755751fSHerbert Dürr     }
5022755751fSHerbert Dürr 
5032755751fSHerbert Dürr   /* Set the flag for the closures return.  */
5042755751fSHerbert Dürr     switch (cif->rtype->type)
5052755751fSHerbert Dürr     {
5062755751fSHerbert Dürr     case FFI_TYPE_VOID:
5072755751fSHerbert Dürr     case FFI_TYPE_STRUCT:
5082755751fSHerbert Dürr     case FFI_TYPE_SINT64:
5092755751fSHerbert Dürr     case FFI_TYPE_FLOAT:
5102755751fSHerbert Dürr     case FFI_TYPE_DOUBLE:
5112755751fSHerbert Dürr     case FFI_TYPE_LONGDOUBLE:
5122755751fSHerbert Dürr       cif->flags = (unsigned) cif->rtype->type;
5132755751fSHerbert Dürr       break;
5142755751fSHerbert Dürr 
5152755751fSHerbert Dürr     case FFI_TYPE_UINT64:
5162755751fSHerbert Dürr       cif->flags = FFI_TYPE_SINT64;
5172755751fSHerbert Dürr       break;
5182755751fSHerbert Dürr 
5192755751fSHerbert Dürr     default:
5202755751fSHerbert Dürr       cif->flags = FFI_TYPE_INT;
5212755751fSHerbert Dürr       break;
5222755751fSHerbert Dürr     }
5232755751fSHerbert Dürr 
5242755751fSHerbert Dürr   return FFI_OK;
5252755751fSHerbert Dürr }
5262755751fSHerbert Dürr 
5272755751fSHerbert Dürr typedef struct
5282755751fSHerbert Dürr {
5292755751fSHerbert Dürr   long gpr[2];
5302755751fSHerbert Dürr   __int128_t sse[2];
5312755751fSHerbert Dürr   long double st0;
5322755751fSHerbert Dürr } return_value;
5332755751fSHerbert Dürr 
5342755751fSHerbert Dürr //#endif
5352755751fSHerbert Dürr 
5362755751fSHerbert Dürr void
5372755751fSHerbert Dürr ffi_fill_return_value (return_value *rv, extended_cif *ecif)
5382755751fSHerbert Dürr {
5392755751fSHerbert Dürr     enum x86_64_reg_class classes[MAX_CLASSES];
5402755751fSHerbert Dürr     int i = 0, num;
5412755751fSHerbert Dürr     long *gpr = rv->gpr;
5422755751fSHerbert Dürr     __int128_t *sse = rv->sse;
5432755751fSHerbert Dürr     signed char sc;
5442755751fSHerbert Dürr     signed short ss;
5452755751fSHerbert Dürr 
5462755751fSHerbert Dürr     /* This is needed because of the way x86-64 handles signed short
5472755751fSHerbert Dürr        integers.  */
5482755751fSHerbert Dürr     switch (ecif->cif->rtype->type)
5492755751fSHerbert Dürr     {
5502755751fSHerbert Dürr         case FFI_TYPE_SINT8:
5512755751fSHerbert Dürr             sc = *(signed char *)gpr;
5522755751fSHerbert Dürr             *(long long *)ecif->rvalue = (long long)sc;
5532755751fSHerbert Dürr             return;
5542755751fSHerbert Dürr         case FFI_TYPE_SINT16:
5552755751fSHerbert Dürr             ss = *(signed short *)gpr;
5562755751fSHerbert Dürr             *(long long *)ecif->rvalue = (long long)ss;
5572755751fSHerbert Dürr             return;
5582755751fSHerbert Dürr         default:
5592755751fSHerbert Dürr             /* Just continue.  */
5602755751fSHerbert Dürr             ;
5612755751fSHerbert Dürr     }
5622755751fSHerbert Dürr 
5632755751fSHerbert Dürr     num = classify_argument (ecif->cif->rtype, classes, 0);
5642755751fSHerbert Dürr 
5652755751fSHerbert Dürr     if (num == 0)
5662755751fSHerbert Dürr         /* Return in memory.  */
5672755751fSHerbert Dürr         ecif->rvalue = (void *) rv->gpr[0];
5682755751fSHerbert Dürr     else if (num == 2 && classes[0] == X86_64_X87_CLASS &&
5692755751fSHerbert Dürr             classes[1] == X86_64_X87UP_CLASS)
5702755751fSHerbert Dürr         /* This is a long double (this is easiest to handle this way instead
5712755751fSHerbert Dürr            of an eightbyte at a time as in the loop below.  */
5722755751fSHerbert Dürr         *((long double *)ecif->rvalue) = rv->st0;
5732755751fSHerbert Dürr     else
5742755751fSHerbert Dürr     {
5752755751fSHerbert Dürr         void *a;
5762755751fSHerbert Dürr 
5772755751fSHerbert Dürr         for (i=0, a=ecif->rvalue; i<num; i++, a+=8)
5782755751fSHerbert Dürr         {
5792755751fSHerbert Dürr             switch (classes[i])
5802755751fSHerbert Dürr             {
5812755751fSHerbert Dürr                 case X86_64_INTEGER_CLASS:
5822755751fSHerbert Dürr                 case X86_64_INTEGERSI_CLASS:
5832755751fSHerbert Dürr                     *(long long *)a = *gpr;
5842755751fSHerbert Dürr                     gpr++;
5852755751fSHerbert Dürr                     break;
5862755751fSHerbert Dürr                 case X86_64_SSE_CLASS:
5872755751fSHerbert Dürr                     sse2floatfloat (sse++, a);
5882755751fSHerbert Dürr                     break;
5892755751fSHerbert Dürr                 case X86_64_SSESF_CLASS:
5902755751fSHerbert Dürr                     *(float *)a = sse2float (sse++);
5912755751fSHerbert Dürr                     break;
5922755751fSHerbert Dürr                 case X86_64_SSEDF_CLASS:
5932755751fSHerbert Dürr                     *(double *)a = sse2double (sse++);
5942755751fSHerbert Dürr                     break;
5952755751fSHerbert Dürr                 default:
5962755751fSHerbert Dürr                     abort();
5972755751fSHerbert Dürr             }
5982755751fSHerbert Dürr         }
5992755751fSHerbert Dürr     }
6002755751fSHerbert Dürr }
6012755751fSHerbert Dürr 
6022755751fSHerbert Dürr //#if 0
6032755751fSHerbert Dürr 
6042755751fSHerbert Dürr /*@-declundef@*/
6052755751fSHerbert Dürr /*@-exportheader@*/
6062755751fSHerbert Dürr extern void ffi_call_UNIX64(void (*)(stackLayout *, extended_cif *),
6072755751fSHerbert Dürr 			    void (*) (return_value *, extended_cif *),
6082755751fSHerbert Dürr 			    /*@out@*/ extended_cif *,
6092755751fSHerbert Dürr 			    unsigned, /*@out@*/ unsigned *, void (*fn)());
6102755751fSHerbert Dürr /*@=declundef@*/
6112755751fSHerbert Dürr /*@=exportheader@*/
6122755751fSHerbert Dürr 
6132755751fSHerbert Dürr void ffi_call(/*@dependent@*/ ffi_cif *cif,
6142755751fSHerbert Dürr 	      void (*fn)(),
6152755751fSHerbert Dürr 	      /*@out@*/ void *rvalue,
6162755751fSHerbert Dürr 	      /*@dependent@*/ void **avalue)
6172755751fSHerbert Dürr {
6182755751fSHerbert Dürr   extended_cif ecif;
6192755751fSHerbert Dürr   int dummy;
6202755751fSHerbert Dürr 
6212755751fSHerbert Dürr   ecif.cif = cif;
6222755751fSHerbert Dürr   ecif.avalue = avalue;
6232755751fSHerbert Dürr 
6242755751fSHerbert Dürr   /* If the return value is a struct and we don't have a return	*/
6252755751fSHerbert Dürr   /* value address then we need to make one		        */
6262755751fSHerbert Dürr 
6272755751fSHerbert Dürr   if ((rvalue == NULL) &&
6282755751fSHerbert Dürr       (examine_argument (cif->rtype, 1, &dummy, &dummy) == 0))
6292755751fSHerbert Dürr     {
6302755751fSHerbert Dürr       /*@-sysunrecog@*/
6312755751fSHerbert Dürr       ecif.rvalue = alloca(cif->rtype->size);
6322755751fSHerbert Dürr       /*@=sysunrecog@*/
6332755751fSHerbert Dürr     }
6342755751fSHerbert Dürr   else
6352755751fSHerbert Dürr     ecif.rvalue = rvalue;
6362755751fSHerbert Dürr 
6372755751fSHerbert Dürr   /* Stack must always be 16byte aligned. Make it so.  */
6382755751fSHerbert Dürr   cif->bytes = ALIGN(cif->bytes, 16);
6392755751fSHerbert Dürr 
6402755751fSHerbert Dürr   switch (cif->abi)
6412755751fSHerbert Dürr     {
6422755751fSHerbert Dürr     case FFI_SYSV:
6432755751fSHerbert Dürr       /* Calling 32bit code from 64bit is not possible  */
6442755751fSHerbert Dürr       FFI_ASSERT(0);
6452755751fSHerbert Dürr       break;
6462755751fSHerbert Dürr 
6472755751fSHerbert Dürr     case FFI_UNIX64:
6482755751fSHerbert Dürr       /*@-usedef@*/
6492755751fSHerbert Dürr       ffi_call_UNIX64 (ffi_prep_args, ffi_fill_return_value, &ecif,
6502755751fSHerbert Dürr 		       cif->bytes, ecif.rvalue, fn);
6512755751fSHerbert Dürr       /*@=usedef@*/
6522755751fSHerbert Dürr       break;
6532755751fSHerbert Dürr 
6542755751fSHerbert Dürr     default:
6552755751fSHerbert Dürr       FFI_ASSERT(0);
6562755751fSHerbert Dürr       break;
6572755751fSHerbert Dürr     }
6582755751fSHerbert Dürr }
6592755751fSHerbert Dürr 
6602755751fSHerbert Dürr extern void ffi_closure_UNIX64(void);
6612755751fSHerbert Dürr 
6622755751fSHerbert Dürr ffi_status
6632755751fSHerbert Dürr ffi_prep_closure (ffi_closure* closure,
6642755751fSHerbert Dürr 		  ffi_cif* cif,
6652755751fSHerbert Dürr 		  void (*fun)(ffi_cif*, void*, void**, void*),
6662755751fSHerbert Dürr 		  void *user_data)
6672755751fSHerbert Dürr {
6682755751fSHerbert Dürr   volatile unsigned short *tramp;
6692755751fSHerbert Dürr 
6702755751fSHerbert Dürr   /* FFI_ASSERT (cif->abi == FFI_OSF);  */
6712755751fSHerbert Dürr 
6722755751fSHerbert Dürr   tramp = (volatile unsigned short *) &closure->tramp[0];
6732755751fSHerbert Dürr   tramp[0] = 0xbb49;		/* mov <code>, %r11	*/
6742755751fSHerbert Dürr   tramp[5] = 0xba49;		/* mov <data>, %r10	*/
6752755751fSHerbert Dürr   tramp[10] = 0xff49;		/* jmp *%r11	*/
6762755751fSHerbert Dürr   tramp[11] = 0x00e3;
6772755751fSHerbert Dürr   *(void * volatile *) &tramp[1] = ffi_closure_UNIX64;
6782755751fSHerbert Dürr   *(void * volatile *) &tramp[6] = closure;
6792755751fSHerbert Dürr 
6802755751fSHerbert Dürr   closure->cif = cif;
6812755751fSHerbert Dürr   closure->fun = fun;
6822755751fSHerbert Dürr   closure->user_data = user_data;
6832755751fSHerbert Dürr 
6842755751fSHerbert Dürr   return FFI_OK;
6852755751fSHerbert Dürr }
6862755751fSHerbert Dürr 
6872755751fSHerbert Dürr int
6882755751fSHerbert Dürr ffi_closure_UNIX64_inner(ffi_closure *closure, va_list l, void *rp)
6892755751fSHerbert Dürr {
6902755751fSHerbert Dürr   ffi_cif *cif;
6912755751fSHerbert Dürr   void **avalue;
6922755751fSHerbert Dürr   ffi_type **arg_types;
6932755751fSHerbert Dürr   long i, avn, argn;
6942755751fSHerbert Dürr 
6952755751fSHerbert Dürr   cif = closure->cif;
6962755751fSHerbert Dürr   avalue = alloca(cif->nargs * sizeof(void *));
6972755751fSHerbert Dürr 
6982755751fSHerbert Dürr   argn = 0;
6992755751fSHerbert Dürr 
7002755751fSHerbert Dürr   i = 0;
7012755751fSHerbert Dürr   avn = cif->nargs;
7022755751fSHerbert Dürr   arg_types = cif->arg_types;
7032755751fSHerbert Dürr 
7042755751fSHerbert Dürr   /* Grab the addresses of the arguments from the stack frame.  */
7052755751fSHerbert Dürr   while (i < avn)
7062755751fSHerbert Dürr     {
7072755751fSHerbert Dürr       switch (arg_types[i]->type)
7082755751fSHerbert Dürr 	{
7092755751fSHerbert Dürr 	case FFI_TYPE_SINT8:
7102755751fSHerbert Dürr 	case FFI_TYPE_UINT8:
7112755751fSHerbert Dürr 	case FFI_TYPE_SINT16:
7122755751fSHerbert Dürr 	case FFI_TYPE_UINT16:
7132755751fSHerbert Dürr 	case FFI_TYPE_SINT32:
7142755751fSHerbert Dürr 	case FFI_TYPE_UINT32:
7152755751fSHerbert Dürr 	case FFI_TYPE_SINT64:
7162755751fSHerbert Dürr 	case FFI_TYPE_UINT64:
7172755751fSHerbert Dürr 	case FFI_TYPE_POINTER:
7182755751fSHerbert Dürr 	  {
7192755751fSHerbert Dürr 	    if (l->gp_offset > 48-8)
7202755751fSHerbert Dürr 	      {
7212755751fSHerbert Dürr 		avalue[i] = l->overflow_arg_area;
7222755751fSHerbert Dürr 		l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
7232755751fSHerbert Dürr 	      }
7242755751fSHerbert Dürr 	    else
7252755751fSHerbert Dürr 	      {
7262755751fSHerbert Dürr 		avalue[i] = (char *)l->reg_save_area + l->gp_offset;
7272755751fSHerbert Dürr 		l->gp_offset += 8;
7282755751fSHerbert Dürr 	      }
7292755751fSHerbert Dürr 	  }
7302755751fSHerbert Dürr 	  break;
7312755751fSHerbert Dürr 
7322755751fSHerbert Dürr 	case FFI_TYPE_STRUCT:
7332755751fSHerbert Dürr 	  /* FIXME  */
7342755751fSHerbert Dürr 	  FFI_ASSERT(0);
7352755751fSHerbert Dürr 	  break;
7362755751fSHerbert Dürr 
7372755751fSHerbert Dürr 	case FFI_TYPE_DOUBLE:
7382755751fSHerbert Dürr 	  {
7392755751fSHerbert Dürr 	    if (l->fp_offset > 176-16)
7402755751fSHerbert Dürr 	      {
7412755751fSHerbert Dürr 		avalue[i] = l->overflow_arg_area;
7422755751fSHerbert Dürr 		l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
7432755751fSHerbert Dürr 	      }
7442755751fSHerbert Dürr 	    else
7452755751fSHerbert Dürr 	      {
7462755751fSHerbert Dürr 		avalue[i] = (char *)l->reg_save_area + l->fp_offset;
7472755751fSHerbert Dürr 		l->fp_offset += 16;
7482755751fSHerbert Dürr 	      }
7492755751fSHerbert Dürr 	  }
7502755751fSHerbert Dürr #if DEBUG_FFI
7512755751fSHerbert Dürr 	  fprintf (stderr, "double arg %d = %g\n", i, *(double *)avalue[i]);
7522755751fSHerbert Dürr #endif
7532755751fSHerbert Dürr 	  break;
7542755751fSHerbert Dürr 
7552755751fSHerbert Dürr 	case FFI_TYPE_FLOAT:
7562755751fSHerbert Dürr 	  {
7572755751fSHerbert Dürr 	    if (l->fp_offset > 176-16)
7582755751fSHerbert Dürr 	      {
7592755751fSHerbert Dürr 		avalue[i] = l->overflow_arg_area;
7602755751fSHerbert Dürr 		l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
7612755751fSHerbert Dürr 	      }
7622755751fSHerbert Dürr 	    else
7632755751fSHerbert Dürr 	      {
7642755751fSHerbert Dürr 		avalue[i] = (char *)l->reg_save_area + l->fp_offset;
7652755751fSHerbert Dürr 		l->fp_offset += 16;
7662755751fSHerbert Dürr 	      }
7672755751fSHerbert Dürr 	  }
7682755751fSHerbert Dürr #if DEBUG_FFI
7692755751fSHerbert Dürr 	  fprintf (stderr, "float arg %d = %g\n", i, *(float *)avalue[i]);
7702755751fSHerbert Dürr #endif
7712755751fSHerbert Dürr 	  break;
7722755751fSHerbert Dürr 
7732755751fSHerbert Dürr 	default:
7742755751fSHerbert Dürr 	  FFI_ASSERT(0);
7752755751fSHerbert Dürr 	}
7762755751fSHerbert Dürr 
7772755751fSHerbert Dürr       argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG;
7782755751fSHerbert Dürr       i++;
7792755751fSHerbert Dürr     }
7802755751fSHerbert Dürr 
7812755751fSHerbert Dürr   /* Invoke the closure.  */
7822755751fSHerbert Dürr   (closure->fun) (cif, rp, avalue, closure->user_data);
7832755751fSHerbert Dürr 
7842755751fSHerbert Dürr   /* FIXME: Structs not supported.  */
7852755751fSHerbert Dürr   FFI_ASSERT(cif->rtype->type != FFI_TYPE_STRUCT);
7862755751fSHerbert Dürr 
7872755751fSHerbert Dürr   /* Tell ffi_closure_UNIX64 how to perform return type promotions.  */
7882755751fSHerbert Dürr 
7892755751fSHerbert Dürr   return cif->rtype->type;
7902755751fSHerbert Dürr }
7912755751fSHerbert Dürr 
7922755751fSHerbert Dürr #endif
793