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 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 82 96 85.4 %
Date: 2014-11-03 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             : using namespace x86_64;
      58             : 
      59             : /* Register class used for passing given 64bit part of the argument.
      60             :    These represent classes as documented by the PS ABI, with the exception
      61             :    of SSESF, SSEDF classes, that are basically SSE class, just gcc will
      62             :    use SF or DFmode move instead of DImode to avoid reformating penalties.
      63             : 
      64             :    Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
      65             :    whenever possible (upper half does contain padding).
      66             :  */
      67             : enum x86_64_reg_class
      68             : {
      69             :     X86_64_NO_CLASS,
      70             :     X86_64_INTEGER_CLASS,
      71             :     X86_64_INTEGERSI_CLASS,
      72             :     X86_64_SSE_CLASS,
      73             :     X86_64_SSESF_CLASS,
      74             :     X86_64_SSEDF_CLASS,
      75             :     X86_64_SSEUP_CLASS,
      76             :     X86_64_X87_CLASS,
      77             :     X86_64_X87UP_CLASS,
      78             :     X86_64_MEMORY_CLASS
      79             : };
      80             : 
      81             : #define MAX_CLASSES 4
      82             : 
      83             : /* x86-64 register passing implementation.  See x86-64 ABI for details.  Goal
      84             :    of this code is to classify each 8bytes of incoming argument by the register
      85             :    class and assign registers accordingly.  */
      86             : 
      87             : /* Return the union class of CLASS1 and CLASS2.
      88             :    See the x86-64 PS ABI for details.  */
      89             : 
      90             : static enum x86_64_reg_class
      91        6056 : merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
      92             :     throw ()
      93             : {
      94             :     /* Rule #1: If both classes are equal, this is the resulting class.  */
      95        6056 :     if (class1 == class2)
      96         276 :         return class1;
      97             : 
      98             :     /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
      99             :        the other class.  */
     100        5780 :     if (class1 == X86_64_NO_CLASS)
     101           0 :         return class2;
     102        5780 :     if (class2 == X86_64_NO_CLASS)
     103        3520 :         return class1;
     104             : 
     105             :     /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
     106        2260 :     if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
     107           0 :         return X86_64_MEMORY_CLASS;
     108             : 
     109             :     /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
     110        2260 :     if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
     111        2260 :             || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
     112           0 :         return X86_64_INTEGERSI_CLASS;
     113        2260 :     if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
     114          36 :             || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
     115        2224 :         return X86_64_INTEGER_CLASS;
     116             : 
     117             :     /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used.  */
     118          36 :     if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
     119          36 :             || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
     120           0 :         return X86_64_MEMORY_CLASS;
     121             : 
     122             :     /* Rule #6: Otherwise class SSE is used.  */
     123          36 :     return X86_64_SSE_CLASS;
     124             : }
     125             : 
     126             : /* Classify the argument of type TYPE and mode MODE.
     127             :    CLASSES will be filled by the register class used to pass each word
     128             :    of the operand.  The number of words is returned.  In case the parameter
     129             :    should be passed in memory, 0 is returned. As a special case for zero
     130             :    sized containers, classes[0] will be NO_CLASS and 1 is returned.
     131             : 
     132             :    See the x86-64 PS ABI for details.
     133             : */
     134             : static int
     135      568840 : classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset ) throw ()
     136             : {
     137      568840 :     switch ( pTypeRef->eTypeClass )
     138             :     {
     139             :         case typelib_TypeClass_VOID:
     140      123937 :             classes[0] = X86_64_NO_CLASS;
     141      123937 :             return 1;
     142             :         case typelib_TypeClass_CHAR:
     143             :         case typelib_TypeClass_BOOLEAN:
     144             :         case typelib_TypeClass_BYTE:
     145             :         case typelib_TypeClass_SHORT:
     146             :         case typelib_TypeClass_UNSIGNED_SHORT:
     147             :         case typelib_TypeClass_LONG:
     148             :         case typelib_TypeClass_UNSIGNED_LONG:
     149             :         case typelib_TypeClass_HYPER:
     150             :         case typelib_TypeClass_UNSIGNED_HYPER:
     151             :         case typelib_TypeClass_ENUM:
     152      109428 :             if ( ( byteOffset % 8 + pTypeRef->pType->nSize ) <= 4 )
     153      106980 :                 classes[0] = X86_64_INTEGERSI_CLASS;
     154             :             else
     155        2448 :                 classes[0] = X86_64_INTEGER_CLASS;
     156      109428 :             return 1;
     157             :         case typelib_TypeClass_FLOAT:
     158         108 :             if ( ( byteOffset % 8 ) == 0 )
     159          72 :                 classes[0] = X86_64_SSESF_CLASS;
     160             :             else
     161          36 :                 classes[0] = X86_64_SSE_CLASS;
     162         108 :             return 1;
     163             :         case typelib_TypeClass_DOUBLE:
     164         626 :             classes[0] = X86_64_SSEDF_CLASS;
     165         626 :             return 1;
     166             :         /*case LONGDOUBLE:
     167             :             classes[0] = X86_64_X87_CLASS;
     168             :             classes[1] = X86_64_X87UP_CLASS;
     169             :             return 2;*/
     170             :         case typelib_TypeClass_STRING:
     171             :         case typelib_TypeClass_TYPE:
     172             :         case typelib_TypeClass_ANY:
     173             :         case typelib_TypeClass_TYPEDEF:
     174             :         case typelib_TypeClass_SEQUENCE:
     175             :         case typelib_TypeClass_INTERFACE:
     176      319870 :             return 0;
     177             :         case typelib_TypeClass_STRUCT:
     178             :         case typelib_TypeClass_EXCEPTION:
     179             :             {
     180       14871 :                 typelib_TypeDescription * pTypeDescr = 0;
     181       14871 :                 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
     182             : 
     183       14871 :                 const int UNITS_PER_WORD = 8;
     184       14871 :                 int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD;
     185             :                 enum x86_64_reg_class subclasses[MAX_CLASSES];
     186             : 
     187             :                 /* If the struct is larger than 16 bytes, pass it on the stack.  */
     188       14871 :                 if ( pTypeDescr->nSize > 16 )
     189             :                 {
     190       10325 :                     TYPELIB_DANGER_RELEASE( pTypeDescr );
     191       10325 :                     return 0;
     192             :                 }
     193             : 
     194       11592 :                 for ( int i = 0; i < words; i++ )
     195        7046 :                     classes[i] = X86_64_NO_CLASS;
     196             : 
     197        4546 :                 const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
     198             : 
     199             :                 /* Merge the fields of structure.  */
     200       10602 :                 for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
     201             :                 {
     202        7828 :                     typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
     203        7828 :                     int offset = byteOffset + pStruct->pMemberOffsets[ nMember ];
     204             : 
     205        7828 :                     int num = classify_argument( pTypeInStruct, subclasses, offset );
     206             : 
     207        7828 :                     if ( num == 0 )
     208             :                     {
     209        1772 :                         TYPELIB_DANGER_RELEASE( pTypeDescr );
     210        1772 :                         return 0;
     211             :                     }
     212             : 
     213       12112 :                     for ( int i = 0; i < num; i++ )
     214             :                     {
     215        6056 :                         int pos = offset / 8;
     216        6056 :                         classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
     217             :                     }
     218             :                 }
     219             : 
     220        2774 :                 TYPELIB_DANGER_RELEASE( pTypeDescr );
     221             : 
     222             :                 /* Final merger cleanup.  */
     223        7212 :                 for ( int i = 0; i < words; i++ )
     224             :                 {
     225             :                     /* If one class is MEMORY, everything should be passed in
     226             :                        memory.  */
     227        4438 :                     if ( classes[i] == X86_64_MEMORY_CLASS )
     228           0 :                         return 0;
     229             : 
     230             :                     /* The X86_64_SSEUP_CLASS should be always preceded by
     231             :                        X86_64_SSE_CLASS.  */
     232        4438 :                     if ( classes[i] == X86_64_SSEUP_CLASS
     233           0 :                             && ( i == 0 || classes[i - 1] != X86_64_SSE_CLASS ) )
     234           0 :                         classes[i] = X86_64_SSE_CLASS;
     235             : 
     236             :                     /*  X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS.  */
     237        4438 :                     if ( classes[i] == X86_64_X87UP_CLASS
     238           0 :                             && ( i == 0 || classes[i - 1] != X86_64_X87_CLASS ) )
     239           0 :                         classes[i] = X86_64_SSE_CLASS;
     240             :                 }
     241        2774 :                 return words;
     242             :             }
     243             : 
     244             :         default:
     245             : #if OSL_DEBUG_LEVEL > 1
     246             :             OSL_TRACE( "Unhandled case: pType->eTypeClass == %d", pTypeRef->eTypeClass );
     247             : #endif
     248             :             OSL_ASSERT(false);
     249             :     }
     250           0 :     return 0; /* Never reached.  */
     251             : }
     252             : 
     253             : /* Examine the argument and return set number of register required in each
     254             :    class.  Return 0 iff parameter should be passed in memory.  */
     255      560146 : bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedSSE ) throw ()
     256             : {
     257             :     enum x86_64_reg_class classes[MAX_CLASSES];
     258             :     int n;
     259             : 
     260      560146 :     n = classify_argument( pTypeRef, classes, 0 );
     261             : 
     262      560146 :     if ( n == 0 )
     263      330195 :         return false;
     264             : 
     265      229951 :     nUsedGPR = 0;
     266      229951 :     nUsedSSE = 0;
     267      461216 :     for ( n--; n >= 0; n-- )
     268      231265 :         switch ( classes[n] )
     269             :         {
     270             :             case X86_64_INTEGER_CLASS:
     271             :             case X86_64_INTEGERSI_CLASS:
     272      105730 :                 nUsedGPR++;
     273      105730 :                 break;
     274             :             case X86_64_SSE_CLASS:
     275             :             case X86_64_SSESF_CLASS:
     276             :             case X86_64_SSEDF_CLASS:
     277         668 :                 nUsedSSE++;
     278         668 :                 break;
     279             :             case X86_64_NO_CLASS:
     280             :             case X86_64_SSEUP_CLASS:
     281      124867 :                 break;
     282             :             case X86_64_X87_CLASS:
     283             :             case X86_64_X87UP_CLASS:
     284           0 :                 if ( !bInReturn )
     285           0 :                     return false;
     286           0 :                 break;
     287             :             default:
     288             : #if OSL_DEBUG_LEVEL > 1
     289             :             OSL_TRACE( "Unhandled case: classes[n] == %d", classes[n] );
     290             : #endif
     291             :             OSL_ASSERT(false);
     292             :         }
     293      229951 :     return true;
     294             : }
     295             : 
     296      498089 : bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) throw ()
     297             : {
     298             :     int g, s;
     299             : 
     300      498089 :     return !examine_argument( pTypeRef, true, g, s );
     301             : }
     302             : 
     303         866 : void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct ) throw ()
     304             : {
     305             :     enum x86_64_reg_class classes[MAX_CLASSES];
     306             :     int n;
     307             : 
     308         866 :     n = classify_argument( pTypeRef, classes, 0 );
     309             : 
     310         866 :     sal_uInt64 *pStructAlign = reinterpret_cast<sal_uInt64 *>( pStruct );
     311        2082 :     for ( n--; n >= 0; n-- )
     312        1216 :         switch ( classes[n] )
     313             :         {
     314             :             case X86_64_INTEGER_CLASS:
     315             :             case X86_64_INTEGERSI_CLASS:
     316        1198 :                 *pStructAlign++ = *pGPR++;
     317        1198 :                 break;
     318             :             case X86_64_SSE_CLASS:
     319             :             case X86_64_SSESF_CLASS:
     320             :             case X86_64_SSEDF_CLASS:
     321          18 :                 *pStructAlign++ = *reinterpret_cast<const sal_uInt64 *>( pSSE++ );
     322          18 :                 break;
     323             :             default:
     324           0 :                 break;
     325             :         }
     326         866 : }
     327             : 
     328             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10