LCOV - code coverage report
Current view: top level - bridges/source/cpp_uno/gcc3_linux_x86-64 - abi.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 82 96 85.4 %
Date: 2015-06-13 12:38:46 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : // This is an implementation of the x86-64 ABI as described in 'System V
      22             : // Application Binary Interface, AMD64 Architecture Processor Supplement'
      23             : // (http://www.x86-64.org/documentation/abi-0.95.pdf)
      24             : //
      25             : // The code in this file is a modification of src/x86/ffi64.c from libffi
      26             : // (http://sources.redhat.com/libffi/) which is under the following license:
      27             : 
      28             : /* -----------------------------------------------------------------------
      29             :    ffi.c - Copyright (c) 2002  Bo Thorsen <bo@suse.de>
      30             : 
      31             :    x86-64 Foreign Function Interface
      32             : 
      33             :    Permission is hereby granted, free of charge, to any person obtaining
      34             :    a copy of this software and associated documentation files (the
      35             :    ``Software''), to deal in the Software without restriction, including
      36             :    without limitation the rights to use, copy, modify, merge, publish,
      37             :    distribute, sublicense, and/or sell copies of the Software, and to
      38             :    permit persons to whom the Software is furnished to do so, subject to
      39             :    the following conditions:
      40             : 
      41             :    The above copyright notice and this permission notice shall be included
      42             :    in all copies or substantial portions of the Software.
      43             : 
      44             :    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
      45             :    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      46             :    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      47             :    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
      48             :    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      49             :    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      50             :    OTHER DEALINGS IN THE SOFTWARE.
      51             :    ----------------------------------------------------------------------- */
      52             : 
      53             : #include "sal/config.h"
      54             : 
      55             : #include "abi.hxx"
      56             : 
      57             : #include <sal/log.hxx>
      58             : 
      59             : using namespace x86_64;
      60             : 
      61             : /* Register class used for passing given 64bit part of the argument.
      62             :    These represent classes as documented by the PS ABI, with the exception
      63             :    of SSESF, SSEDF classes, that are basically SSE class, just gcc will
      64             :    use SF or DFmode move instead of DImode to avoid reformating penalties.
      65             : 
      66             :    Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
      67             :    whenever possible (upper half does contain padding).
      68             :  */
      69             : enum x86_64_reg_class
      70             : {
      71             :     X86_64_NO_CLASS,
      72             :     X86_64_INTEGER_CLASS,
      73             :     X86_64_INTEGERSI_CLASS,
      74             :     X86_64_SSE_CLASS,
      75             :     X86_64_SSESF_CLASS,
      76             :     X86_64_SSEDF_CLASS,
      77             :     X86_64_SSEUP_CLASS,
      78             :     X86_64_X87_CLASS,
      79             :     X86_64_X87UP_CLASS,
      80             :     X86_64_MEMORY_CLASS
      81             : };
      82             : 
      83             : #define MAX_CLASSES 4
      84             : 
      85             : /* x86-64 register passing implementation.  See x86-64 ABI for details.  Goal
      86             :    of this code is to classify each 8bytes of incoming argument by the register
      87             :    class and assign registers accordingly.  */
      88             : 
      89             : /* Return the union class of CLASS1 and CLASS2.
      90             :    See the x86-64 PS ABI for details.  */
      91             : 
      92             : static enum x86_64_reg_class
      93        3420 : merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
      94             :     throw ()
      95             : {
      96             :     /* Rule #1: If both classes are equal, this is the resulting class.  */
      97        3420 :     if (class1 == class2)
      98         252 :         return class1;
      99             : 
     100             :     /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
     101             :        the other class.  */
     102        3168 :     if (class1 == X86_64_NO_CLASS)
     103           0 :         return class2;
     104        3168 :     if (class2 == X86_64_NO_CLASS)
     105        1900 :         return class1;
     106             : 
     107             :     /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
     108        1268 :     if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
     109           0 :         return X86_64_MEMORY_CLASS;
     110             : 
     111             :     /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
     112        1268 :     if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
     113        1268 :             || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
     114           0 :         return X86_64_INTEGERSI_CLASS;
     115        1268 :     if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
     116          18 :             || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
     117        1250 :         return X86_64_INTEGER_CLASS;
     118             : 
     119             :     /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used.  */
     120          18 :     if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
     121          18 :             || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
     122           0 :         return X86_64_MEMORY_CLASS;
     123             : 
     124             :     /* Rule #6: Otherwise class SSE is used.  */
     125          18 :     return X86_64_SSE_CLASS;
     126             : }
     127             : 
     128             : /* Classify the argument of type TYPE and mode MODE.
     129             :    CLASSES will be filled by the register class used to pass each word
     130             :    of the operand.  The number of words is returned.  In case the parameter
     131             :    should be passed in memory, 0 is returned. As a special case for zero
     132             :    sized containers, classes[0] will be NO_CLASS and 1 is returned.
     133             : 
     134             :    See the x86-64 PS ABI for details.
     135             : */
     136             : static int
     137     1234802 : classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset ) throw ()
     138             : {
     139     1234802 :     switch ( pTypeRef->eTypeClass )
     140             :     {
     141             :         case typelib_TypeClass_VOID:
     142      153728 :             classes[0] = X86_64_NO_CLASS;
     143      153728 :             return 1;
     144             :         case typelib_TypeClass_CHAR:
     145             :         case typelib_TypeClass_BOOLEAN:
     146             :         case typelib_TypeClass_BYTE:
     147             :         case typelib_TypeClass_SHORT:
     148             :         case typelib_TypeClass_UNSIGNED_SHORT:
     149             :         case typelib_TypeClass_LONG:
     150             :         case typelib_TypeClass_UNSIGNED_LONG:
     151             :         case typelib_TypeClass_HYPER:
     152             :         case typelib_TypeClass_UNSIGNED_HYPER:
     153             :         case typelib_TypeClass_ENUM:
     154      441647 :             if ( ( byteOffset % 8 + pTypeRef->pType->nSize ) <= 4 )
     155      440261 :                 classes[0] = X86_64_INTEGERSI_CLASS;
     156             :             else
     157        1386 :                 classes[0] = X86_64_INTEGER_CLASS;
     158      441647 :             return 1;
     159             :         case typelib_TypeClass_FLOAT:
     160          56 :             if ( ( byteOffset % 8 ) == 0 )
     161          38 :                 classes[0] = X86_64_SSESF_CLASS;
     162             :             else
     163          18 :                 classes[0] = X86_64_SSE_CLASS;
     164          56 :             return 1;
     165             :         case typelib_TypeClass_DOUBLE:
     166         432 :             classes[0] = X86_64_SSEDF_CLASS;
     167         432 :             return 1;
     168             :         /*case LONGDOUBLE:
     169             :             classes[0] = X86_64_X87_CLASS;
     170             :             classes[1] = X86_64_X87UP_CLASS;
     171             :             return 2;*/
     172             :         case typelib_TypeClass_STRING:
     173             :         case typelib_TypeClass_TYPE:
     174             :         case typelib_TypeClass_ANY:
     175             :         case typelib_TypeClass_TYPEDEF:
     176             :         case typelib_TypeClass_SEQUENCE:
     177             :         case typelib_TypeClass_INTERFACE:
     178      631771 :             return 0;
     179             :         case typelib_TypeClass_STRUCT:
     180             :         case typelib_TypeClass_EXCEPTION:
     181             :             {
     182        7168 :                 typelib_TypeDescription * pTypeDescr = 0;
     183        7168 :                 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
     184             : 
     185        7168 :                 const int UNITS_PER_WORD = 8;
     186        7168 :                 int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD;
     187             :                 enum x86_64_reg_class subclasses[MAX_CLASSES];
     188             : 
     189             :                 /* If the struct is larger than 16 bytes, pass it on the stack.  */
     190        7168 :                 if ( pTypeDescr->nSize > 16 )
     191             :                 {
     192        4714 :                     TYPELIB_DANGER_RELEASE( pTypeDescr );
     193        4714 :                     return 0;
     194             :                 }
     195             : 
     196        6178 :                 for ( int i = 0; i < words; i++ )
     197        3724 :                     classes[i] = X86_64_NO_CLASS;
     198             : 
     199        2454 :                 const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
     200             : 
     201             :                 /* Merge the fields of structure.  */
     202        5874 :                 for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
     203             :                 {
     204        4363 :                     typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
     205        4363 :                     int offset = byteOffset + pStruct->pMemberOffsets[ nMember ];
     206             : 
     207        4363 :                     int num = classify_argument( pTypeInStruct, subclasses, offset );
     208             : 
     209        4363 :                     if ( num == 0 )
     210             :                     {
     211         943 :                         TYPELIB_DANGER_RELEASE( pTypeDescr );
     212         943 :                         return 0;
     213             :                     }
     214             : 
     215        6840 :                     for ( int i = 0; i < num; i++ )
     216             :                     {
     217        3420 :                         int pos = offset / 8;
     218        3420 :                         classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
     219             :                     }
     220             :                 }
     221             : 
     222        1511 :                 TYPELIB_DANGER_RELEASE( pTypeDescr );
     223             : 
     224             :                 /* Final merger cleanup.  */
     225        3874 :                 for ( int i = 0; i < words; i++ )
     226             :                 {
     227             :                     /* If one class is MEMORY, everything should be passed in
     228             :                        memory.  */
     229        2363 :                     if ( classes[i] == X86_64_MEMORY_CLASS )
     230           0 :                         return 0;
     231             : 
     232             :                     /* The X86_64_SSEUP_CLASS should be always preceded by
     233             :                        X86_64_SSE_CLASS.  */
     234        2363 :                     if ( classes[i] == X86_64_SSEUP_CLASS
     235           0 :                             && ( i == 0 || classes[i - 1] != X86_64_SSE_CLASS ) )
     236           0 :                         classes[i] = X86_64_SSE_CLASS;
     237             : 
     238             :                     /*  X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS.  */
     239        2363 :                     if ( classes[i] == X86_64_X87UP_CLASS
     240           0 :                             && ( i == 0 || classes[i - 1] != X86_64_X87_CLASS ) )
     241           0 :                         classes[i] = X86_64_SSE_CLASS;
     242             :                 }
     243        1511 :                 return words;
     244             :             }
     245             : 
     246             :         default:
     247             :             SAL_WARN("bridges", "Unhandled case: pType->eTypeClass == "
     248             :                     << pTypeRef->eTypeClass);
     249             :             assert(false);
     250             :     }
     251           0 :     return 0; /* Never reached.  */
     252             : }
     253             : 
     254             : /* Examine the argument and return set number of register required in each
     255             :    class.  Return 0 iff parameter should be passed in memory.  */
     256     1229969 : bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedSSE ) throw ()
     257             : {
     258             :     enum x86_64_reg_class classes[MAX_CLASSES];
     259             :     int n;
     260             : 
     261     1229969 :     n = classify_argument( pTypeRef, classes, 0 );
     262             : 
     263     1229971 :     if ( n == 0 )
     264      636488 :         return false;
     265             : 
     266      593483 :     nUsedGPR = 0;
     267      593483 :     nUsedSSE = 0;
     268     1187639 :     for ( n--; n >= 0; n-- )
     269      594153 :         switch ( classes[n] )
     270             :         {
     271             :             case X86_64_INTEGER_CLASS:
     272             :             case X86_64_INTEGERSI_CLASS:
     273      439504 :                 nUsedGPR++;
     274      439504 :                 break;
     275             :             case X86_64_SSE_CLASS:
     276             :             case X86_64_SSESF_CLASS:
     277             :             case X86_64_SSEDF_CLASS:
     278         455 :                 nUsedSSE++;
     279         455 :                 break;
     280             :             case X86_64_NO_CLASS:
     281             :             case X86_64_SSEUP_CLASS:
     282      154197 :                 break;
     283             :             case X86_64_X87_CLASS:
     284             :             case X86_64_X87UP_CLASS:
     285           0 :                 if ( !bInReturn )
     286           0 :                     return false;
     287           0 :                 break;
     288             :             default:
     289             :             SAL_WARN("bridges", "Unhandled case: classes[n] == " << classes[n]);
     290             :             assert(false);
     291             :         }
     292      593486 :     return true;
     293             : }
     294             : 
     295      946999 : bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) throw ()
     296             : {
     297             :     int g, s;
     298             : 
     299      946999 :     return !examine_argument( pTypeRef, true, g, s );
     300             : }
     301             : 
     302         473 : void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct ) throw ()
     303             : {
     304             :     enum x86_64_reg_class classes[MAX_CLASSES];
     305             :     int n;
     306             : 
     307         473 :     n = classify_argument( pTypeRef, classes, 0 );
     308             : 
     309         473 :     sal_uInt64 *pStructAlign = static_cast<sal_uInt64 *>( pStruct );
     310        1128 :     for ( n--; n >= 0; n-- )
     311         655 :         switch ( classes[n] )
     312             :         {
     313             :             case X86_64_INTEGER_CLASS:
     314             :             case X86_64_INTEGERSI_CLASS:
     315         646 :                 *pStructAlign++ = *pGPR++;
     316         646 :                 break;
     317             :             case X86_64_SSE_CLASS:
     318             :             case X86_64_SSESF_CLASS:
     319             :             case X86_64_SSEDF_CLASS:
     320           9 :                 *pStructAlign++ = *reinterpret_cast<const sal_uInt64 *>( pSSE++ );
     321           9 :                 break;
     322             :             default:
     323           0 :                 break;
     324             :         }
     325         473 : }
     326             : 
     327             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11