[Libreoffice-commits] .: bridges/source

Jani Monoses janimo at kemper.freedesktop.org
Thu Feb 16 06:30:58 PST 2012


 bridges/source/cpp_uno/gcc3_linux_arm/armhelper.S |   18 +++
 bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx |   34 ++++++-
 bridges/source/cpp_uno/gcc3_linux_arm/share.hxx   |    2 
 bridges/source/cpp_uno/gcc3_linux_arm/uno2cpp.cxx |  105 +++++++++++++++++++---
 4 files changed, 142 insertions(+), 17 deletions(-)

New commits:
commit dab11f7fe2a2fa4155e4c4feaa5fc54e57cfbd37
Author: Jani Monoses <jani at ubuntu.com>
Date:   Fri Feb 10 14:50:22 2012 +0200

    ARM bridge: VFP ABI (armhf) support

diff --git a/bridges/source/cpp_uno/gcc3_linux_arm/armhelper.S b/bridges/source/cpp_uno/gcc3_linux_arm/armhelper.S
index d5faf15..27148dc 100644
--- a/bridges/source/cpp_uno/gcc3_linux_arm/armhelper.S
+++ b/bridges/source/cpp_uno/gcc3_linux_arm/armhelper.S
@@ -10,6 +10,17 @@
 #  define UNWIND @
 #endif
 
+@ If the VFP ABI variant (armhf in Debian/Ubuntu) is used, an additional extra 64 bytes
+@ are taken up on the stack (the equivalent of the 8 double precision VFP registers)
+
+#ifdef __ARM_PCS_VFP
+#  define PAD 80
+#  define DISCARDED 84
+#else
+#  define PAD 16
+#  define DISCARDED 20
+#endif
+
 	.file	"armhelper.s"
 	.text
 	.align	4
@@ -19,9 +30,12 @@ privateSnippetExecutor:
 	UNWIND .fnstart            @ start of unwinder entry
 
 	stmfd sp!, {r0-r3}         @ follow other parameters on stack
-	UNWIND .pad  #16           @ throw this data away on exception
 	mov   r0, ip               @ r0 points to functionoffset/vtable
 	mov   r1, sp               @ r1 points to this and params
+#ifdef __ARM_PCS_VFP
+	vpush {d0-d7}              @ floating point parameter on stack
+#endif
+	UNWIND .pad  #PAD          @ throw this data away on exception
 	                           @ (see cppuno.cxx:codeSnippet())
 	stmfd sp!, {r4,lr}         @ save return address 
 	                           @ (r4 pushed to preserve stack alignment)
@@ -30,7 +44,7 @@ privateSnippetExecutor:
 	bl    cpp_vtable_call(PLT)
 
 	add   sp, sp, #4           @ no need to restore r4 (we didn't touch it)
-	ldr   pc, [sp], #20        @ return, discarding function arguments
+	ldr   pc, [sp], #DISCARDED @ return, discarding function arguments
 
 	UNWIND .fnend              @ end of unwinder entry
 
diff --git a/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx
index d347aa0..07bdea1 100644
--- a/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx
+++ b/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx
@@ -69,6 +69,9 @@ namespace
         char * pTopStack = (char *)(pCallStack + 0);
         char * pCppStack = pTopStack;
 
+#ifdef __ARM_PCS_VFP
+        char * pFloatArgs = (char *)(pCppStack - 64);
+#endif
         // return
         typelib_TypeDescription * pReturnTypeDescr = 0;
         if (pReturnTypeRef)
@@ -125,7 +128,9 @@ namespace
                 {
                     case typelib_TypeClass_HYPER:
                     case typelib_TypeClass_UNSIGNED_HYPER:
+#ifndef __ARM_PCS_VFP
                     case typelib_TypeClass_DOUBLE:
+#endif
             if ((pCppStack - pTopStack) % 8) pCppStack+=sizeof(sal_Int32); //align to 8
                         break;
                     default:
@@ -133,13 +138,31 @@ namespace
                 }
 #endif
 
-                pCppArgs[nPos] = pCppStack;
-                pUnoArgs[nPos] = pCppStack;
+// For armhf we get the floating point arguments from a different area of the stack
+// TODO: deal with functions with more than 8 floating point args that need to overflow
+// to the stack. Find such an UNO API to try on.
+#ifdef __ARM_PCS_VFP
+                if (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT)
+                {
+                    pCppArgs[nPos] =  pUnoArgs[nPos] = pFloatArgs;
+                    pFloatArgs += sizeof(float);
+                } else
+                if (pParamTypeDescr->eTypeClass == typelib_TypeClass_DOUBLE)
+                {
+                    if ((pFloatArgs - pTopStack) % 8) pFloatArgs+=sizeof(float); //align to 8
+                    pCppArgs[nPos] = pUnoArgs[nPos] = pFloatArgs;
+                    pFloatArgs += sizeof(double);
+                } else
+#endif
+                    pCppArgs[nPos] = pUnoArgs[nPos] = pCppStack;
+
                 switch (pParamTypeDescr->eTypeClass)
                 {
                     case typelib_TypeClass_HYPER:
                     case typelib_TypeClass_UNSIGNED_HYPER:
+#ifndef __ARM_PCS_VFP
                     case typelib_TypeClass_DOUBLE:
+#endif
                         pCppStack += sizeof(sal_Int32); // extra long
                         break;
                     default:
@@ -179,6 +202,13 @@ namespace
                     TYPELIB_DANGER_RELEASE( pParamTypeDescr );
                 }
             }
+#ifdef __ARM_PCS_VFP
+            // use the stack for output parameters or non floating point values
+                if (rParam.bOut ||
+                        ((pParamTypeDescr->eTypeClass != typelib_TypeClass_DOUBLE)
+                         && (pParamTypeDescr->eTypeClass != typelib_TypeClass_FLOAT))
+                    )
+#endif
             pCppStack += sizeof(sal_Int32); // standard parameter length
         }
 
diff --git a/bridges/source/cpp_uno/gcc3_linux_arm/share.hxx b/bridges/source/cpp_uno/gcc3_linux_arm/share.hxx
index f7a85ba..da36c75 100644
--- a/bridges/source/cpp_uno/gcc3_linux_arm/share.hxx
+++ b/bridges/source/cpp_uno/gcc3_linux_arm/share.hxx
@@ -93,7 +93,7 @@ namespace CPPU_CURRENT_NAMESPACE
 
 namespace arm
 {
-    enum armlimits { MAX_GPR_REGS = 4 };
+    enum armlimits { MAX_GPR_REGS = 4, MAX_FPR_REGS = 8 };
     bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef );
 }
 
diff --git a/bridges/source/cpp_uno/gcc3_linux_arm/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_arm/uno2cpp.cxx
index fc8a9e2..97eff51 100644
--- a/bridges/source/cpp_uno/gcc3_linux_arm/uno2cpp.cxx
+++ b/bridges/source/cpp_uno/gcc3_linux_arm/uno2cpp.cxx
@@ -131,6 +131,20 @@ namespace arm
         return false;
     }
 
+#ifdef __ARM_PCS_VFP
+    bool is_float_only_struct(const typelib_TypeDescription * type)
+    {
+        const typelib_CompoundTypeDescription * p
+            = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
+        for (sal_Int32 i = 0; i < p->nMembers; ++i)
+        {
+            if (p->ppTypeRefs[i]->eTypeClass != typelib_TypeClass_FLOAT &&
+                p->ppTypeRefs[i]->eTypeClass != typelib_TypeClass_DOUBLE)
+                return false;
+        }
+        return true;
+    }
+#endif
     bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef )
     {
         if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
@@ -143,6 +157,13 @@ namespace arm
             //A Composite Type not larger than 4 bytes is returned in r0
             bool bRet = pTypeDescr->nSize > 4 || is_complex_struct(pTypeDescr);
 
+#ifdef __ARM_PCS_VFP
+            // In the VFP ABI, structs with only float/double values that fit in
+            // 16 bytes are returned in registers
+            if( pTypeDescr->nSize <= 16 && is_float_only_struct(pTypeDescr))
+                bRet = false;
+#endif
+
             TYPELIB_DANGER_RELEASE( pTypeDescr );
             return bRet;
         }
@@ -208,7 +229,8 @@ void callVirtualMethod(
     sal_uInt32 *pStack,
     sal_uInt32 nStack,
     sal_uInt32 *pGPR,
-    sal_uInt32 nGPR) __attribute__((noinline));
+    sal_uInt32 nGPR,
+    double *pFPR) __attribute__((noinline));
 
 void callVirtualMethod(
     void * pThis,
@@ -218,7 +240,8 @@ void callVirtualMethod(
     sal_uInt32 *pStack,
     sal_uInt32 nStack,
     sal_uInt32 *pGPR,
-    sal_uInt32 nGPR)
+    sal_uInt32 nGPR,
+    double *pFPR)
 {
     // never called
     if (! pThis)
@@ -240,19 +263,30 @@ void callVirtualMethod(
     pMethod += 4 * nVtableIndex;
     pMethod = *((sal_uInt32 *)pMethod);
 
-    typedef void (*FunctionCall )( sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32);
-    FunctionCall pFunc = (FunctionCall)pMethod;
-
-    (*pFunc)(pGPR[0], pGPR[1], pGPR[2], pGPR[3]);
-
+    //Return registers
     sal_uInt32 r0;
     sal_uInt32 r1;
 
-    // get return value
     __asm__ __volatile__ (
-        "mov %0, r0\n\t"
-        "mov %1, r1\n\t"
-        : "=r" (r0), "=r" (r1) : );
+        //Fill in general purpose register arguments
+        "ldr r4, %[pgpr]\n\t"
+        "ldmia r4, {r0-r3}\n\t"
+
+#ifdef __ARM_PCS_VFP
+        //Fill in VFP register arguments as double precision values
+        "ldr r4, %[pfpr]\n\t"
+        "vldmia r4, {d0-d7}\n\t"
+#endif
+        //Make the call
+        "ldr r5, %[pmethod]\n\t"
+        "blx r5\n\t"
+
+        //Fill in return values
+        "mov %[r0], r0\n\t"
+        "mov %[r1], r1\n\t"
+        : [r0]"=r" (r0), [r1]"=r" (r1)
+        : [pmethod]"m" (pMethod), [pgpr]"m" (pGPR), [pfpr]"m" (pFPR)
+        : "r4", "r5");
 
     MapReturn(r0, r1, pReturnType, (sal_uInt32*)pRegisterReturn);
 }
@@ -290,11 +324,49 @@ void callVirtualMethod(
         INSERT_INT32( ((sal_uInt32*)pSV)+1, nr, pGPR, pDS )
 #endif
 
+#ifdef __ARM_PCS_VFP
+// Since single and double arguments share the same register bank the filling of the
+// registers is not always linear. Single values go to the first available single register,
+// while doubles need to have an 8 byte alignment, so only go into double registers starting
+// at every other single register. For ex a float, double, float sequence will fill registers
+// s0, d1, and s1, actually corresponding to the linear order s0,s1, d1.
+//
+// These use the single/double register array and counters and ignore the pGPR argument
+// nSR and nDR are the number of single and double precision registers that are no longer
+// available
+#define INSERT_FLOAT( pSV, nr, pGPR, pDS ) \
+        if (nSR % 2 == 0) {\
+            nSR = 2*nDR; \
+        }\
+        if ( nSR < arm::MAX_FPR_REGS*2 ) {\
+                pSPR[nSR++] = *reinterpret_cast<float *>( pSV ); \
+                if ((nSR % 2 == 1) && (nSR > 2*nDR)) {\
+                    nDR++; \
+                }\
+        }\
+        else \
+        {\
+                *pDS++ = *reinterpret_cast<float *>( pSV );\
+        }
+#define INSERT_DOUBLE( pSV, nr, pGPR, pDS, pStart ) \
+        if ( nDR < arm::MAX_FPR_REGS ) { \
+                pFPR[nDR++] = *reinterpret_cast<double *>( pSV ); \
+        }\
+        else\
+        {\
+            if ( (pDS - pStart) % 2) \
+                { \
+                    ++pDS; \
+                } \
+                *pDS++ = *reinterpret_cast<double *>( pSV );\
+        }
+#else
 #define INSERT_FLOAT( pSV, nr, pFPR, pDS ) \
         INSERT_INT32( pSV, nr, pGPR, pDS )
 
 #define INSERT_DOUBLE( pSV, nr, pFPR, pDS, pStart ) \
         INSERT_INT64( pSV, nr, pGPR, pDS, pStart )
+#endif
 
 #define INSERT_INT16( pSV, nr, pGPR, pDS ) \
         if ( nr < arm::MAX_GPR_REGS ) \
@@ -325,6 +397,14 @@ static void cpp_call(
     sal_uInt32 pGPR[arm::MAX_GPR_REGS];
     sal_uInt32 nGPR = 0;
 
+    // storage and counters for single and double precision VFP registers
+    double pFPR[arm::MAX_FPR_REGS];
+#ifdef __ARM_PCS_VFP
+    sal_uInt32 nDR = 0;
+    float *pSPR = reinterpret_cast< float *>(&pFPR);
+    sal_uInt32 nSR = 0;
+#endif
+
     // return
     typelib_TypeDescription * pReturnTypeDescr = 0;
     TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
@@ -456,7 +536,8 @@ static void cpp_call(
             pCppReturn, pReturnTypeRef,
             pStackStart,
             (pStack - pStackStart),
-            pGPR, nGPR);
+            pGPR, nGPR,
+            pFPR);
 
         // NO exception occurred...
         *ppUnoExc = 0;


More information about the Libreoffice-commits mailing list