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..76af8b0 100644 --- a/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx @@ -69,6 +69,10 @@ namespace char * pTopStack = (char *)(pCallStack + 0); char * pCppStack = pTopStack; +#ifdef __ARM_PCS_VFP + int sc = 0, dc = 0; + char * pFloatArgs = (char *)(pCppStack - 64); +#endif // return typelib_TypeDescription * pReturnTypeDescr = 0; if (pReturnTypeRef) @@ -125,7 +129,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 +139,37 @@ namespace } #endif +// For armhf we get the floating point arguments from a different area of the stack +#ifdef __ARM_PCS_VFP + switch (pParamTypeDescr->eTypeClass) + { + case typelib_TypeClass_FLOAT: + pCppArgs[nPos] = pFloatArgs; + pUnoArgs[nPos] = pFloatArgs; + pFloatArgs += sizeof(float); + break; + case typelib_TypeClass_DOUBLE: + if ((pFloatArgs - pTopStack) % 8) pFloatArgs+=sizeof(float); //align to 8 + pCppArgs[nPos] = pFloatArgs; + pUnoArgs[nPos] = pFloatArgs; + pFloatArgs += sizeof(double); + break; + default: + pCppArgs[nPos] = pCppStack; + pUnoArgs[nPos] = pCppStack; + } +#else pCppArgs[nPos] = pCppStack; pUnoArgs[nPos] = pCppStack; +#endif + 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 +209,9 @@ namespace TYPELIB_DANGER_RELEASE( pParamTypeDescr ); } } +#ifdef __ARM_PCS_VFP + if ((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 9502b87..ebd7128 100644 --- a/bridges/source/cpp_uno/gcc3_linux_arm/uno2cpp.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_arm/uno2cpp.cxx @@ -152,11 +152,6 @@ namespace arm void MapReturn(sal_uInt32 r0, sal_uInt32 r1, typelib_TypeDescriptionReference * pReturnType, sal_uInt32* pRegisterReturn) { -#if !defined(__ARM_EABI__) && !defined(__SOFTFP__) - register float fret asm("f0"); - register double dret asm("f0"); -#endif - switch( pReturnType->eTypeClass ) { case typelib_TypeClass_HYPER: @@ -176,6 +171,7 @@ void MapReturn(sal_uInt32 r0, sal_uInt32 r1, typelib_TypeDescriptionReference * #if !defined(__ARM_PCS_VFP) && (defined(__ARM_EABI__) || defined(__SOFTFP__)) pRegisterReturn[0] = r0; #else + register float fret asm("s0"); *(float*)pRegisterReturn = fret; #endif break; @@ -184,6 +180,7 @@ void MapReturn(sal_uInt32 r0, sal_uInt32 r1, typelib_TypeDescriptionReference * pRegisterReturn[1] = r1; pRegisterReturn[0] = r0; #else + register double dret asm("d0"); *(double*)pRegisterReturn = dret; #endif break; @@ -211,7 +208,9 @@ void callVirtualMethod( sal_uInt32 *pStack, sal_uInt32 nStack, sal_uInt32 *pGPR, - sal_uInt32 nGPR) __attribute__((noinline)); + sal_uInt32 nGPR, + double *pFPR, + sal_uInt32 nFPR) __attribute__((noinline)); void callVirtualMethod( void * pThis, @@ -221,7 +220,9 @@ void callVirtualMethod( sal_uInt32 *pStack, sal_uInt32 nStack, sal_uInt32 *pGPR, - sal_uInt32 nGPR) + sal_uInt32 nGPR, + double *pFPR, + sal_uInt32 nFPR) { // never called if (! pThis) @@ -238,39 +239,53 @@ void callVirtualMethod( // Should not happen, but... if ( nGPR > arm::MAX_GPR_REGS ) nGPR = arm::MAX_GPR_REGS; + if ( nFPR > arm::MAX_FPR_REGS ) + nFPR = arm::MAX_FPR_REGS; sal_uInt32 pMethod = *((sal_uInt32*)pThis); 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; + float s0; + double d0; - // get return value __asm__ __volatile__ ( + //Fill in general purpose register arguments + "ldr r4, %[pgpr]\n\t" + "ldmia r4, {r0-r3}\n\t" + + //Fill in VFP register arguments as double precision values + "ldr r4, %[pfpr]\n\t" + "vldmia r4, {d0-d7}\n\t" + + //Make the call + "ldr r5, %[pmethod]\n\t" + "blx r5\n\t" + + //Fill in return values "mov %0, r0\n\t" "mov %1, r1\n\t" - : "=r" (r0), "=r" (r1) : ); + "fsts s0, %2\n\t" + "fstd d0, %3\n\t" + : "=r" (r0), "=r" (r1), "=m" (s0), "=m" (d0) + : [pmethod]"m" (pMethod), [pgpr]"m" (pGPR), [pfpr]"m" (pFPR) + : "r4", "r5"); MapReturn(r0, r1, pReturnType, (sal_uInt32*)pRegisterReturn); } } -#define INSERT_INT32( pSV, nr, pGPR, pDS, bOverflow ) \ +#define INSERT_INT32( pSV, nr, pGPR, pDS ) \ if ( nr < arm::MAX_GPR_REGS ) \ pGPR[nr++] = *reinterpret_cast( pSV ); \ else \ - bOverFlow = true; \ - if (bOverFlow) \ *pDS++ = *reinterpret_cast( pSV ); #ifdef __ARM_EABI__ -#define INSERT_INT64( pSV, nr, pGPR, pDS, pStart, bOverflow ) \ +#define INSERT_INT64( pSV, nr, pGPR, pDS, pStart ) \ if ( (nr < arm::MAX_GPR_REGS) && (nr % 2) ) \ { \ ++nr; \ @@ -281,8 +296,6 @@ void callVirtualMethod( pGPR[nr++] = *(reinterpret_cast( pSV ) + 1); \ } \ else \ - bOverFlow = true; \ - if (bOverFlow) \ { \ if ( (pDS - pStart) % 2) \ { \ @@ -292,31 +305,64 @@ void callVirtualMethod( *pDS++ = reinterpret_cast( pSV )[1]; \ } #else -#define INSERT_INT64( pSV, nr, pGPR, pDS, pStart, bOverflow ) \ - INSERT_INT32( pSV, nr, pGPR, pDS, bOverflow) \ - INSERT_INT32( ((sal_uInt32*)pSV)+1, nr, pGPR, pDS, bOverflow) +#define INSERT_INT64( pSV, nr, pGPR, pDS, pStart ) \ + INSERT_INT32( pSV, nr, pGPR, pDS ) \ + INSERT_INT32( ((sal_uInt32*)pSV)+1, nr, pGPR, pDS ) #endif -#define INSERT_FLOAT( pSV, nr, pFPR, pDS, bOverflow ) \ - INSERT_INT32( pSV, nr, pGPR, pDS, bOverflow) - -#define INSERT_DOUBLE( pSV, nr, pFPR, pDS, pStart, bOverflow ) \ - INSERT_INT64( pSV, nr, pGPR, pDS, pStart, bOverflow ) +#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( pSV ); \ + if ((nSR % 2 == 1) && (nSR > 2*nDR)) {\ + nDR++; \ + }\ + }\ + else \ + {\ + *pDS++ = *reinterpret_cast( pSV );\ + } +#define INSERT_DOUBLE( pSV, nr, pGPR, pDS, pStart ) \ + if ( nDR < arm::MAX_FPR_REGS ) { \ + pFPR[nDR++] = *reinterpret_cast( pSV ); \ + }\ + else\ + {\ + if ( (pDS - pStart) % 2) \ + { \ + ++pDS; \ + } \ + *pDS++ = *reinterpret_cast( pSV );\ + } +#else +#define INSERT_FLOAT( pSV, nr, pFPR, pDS ) \ + INSERT_INT32( pSV, nr, pGPR, pDS ) -#define INSERT_INT16( pSV, nr, pGPR, pDS, bOverflow ) \ +#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 ) \ pGPR[nr++] = *reinterpret_cast( pSV ); \ else \ - bOverFlow = true; \ - if (bOverFlow) \ *pDS++ = *reinterpret_cast( pSV ); -#define INSERT_INT8( pSV, nr, pGPR, pDS, bOverflow ) \ +#define INSERT_INT8( pSV, nr, pGPR, pDS ) \ if ( nr < arm::MAX_GPR_REGS ) \ pGPR[nr++] = *reinterpret_cast( pSV ); \ else \ - bOverFlow = true; \ - if (bOverFlow) \ *pDS++ = *reinterpret_cast( pSV ); namespace { @@ -336,6 +382,11 @@ static void cpp_call( sal_uInt32 pGPR[arm::MAX_GPR_REGS]; sal_uInt32 nGPR = 0; + double pFPR[arm::MAX_FPR_REGS]; + float *pSPR = reinterpret_cast< float *>(&pFPR); + sal_uInt32 nSR = 0; + sal_uInt32 nDR = 0; + // return typelib_TypeDescription * pReturnTypeDescr = 0; TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); @@ -343,7 +394,6 @@ static void cpp_call( void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion - bool bOverFlow = false; bool bSimpleReturn = true; if (pReturnTypeDescr) { @@ -359,13 +409,13 @@ static void cpp_call( ? __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn); // direct way - INSERT_INT32( &pCppReturn, nGPR, pGPR, pStack, bOverFlow ); + INSERT_INT32( &pCppReturn, nGPR, pGPR, pStack ); } } // push this void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI()) + aVtableSlot.offset; - INSERT_INT32( &pAdjustedThisPtr, nGPR, pGPR, pStack, bOverFlow ); + INSERT_INT32( &pAdjustedThisPtr, nGPR, pGPR, pStack ); // stack space OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); @@ -397,7 +447,7 @@ static void cpp_call( #if OSL_DEBUG_LEVEL > 2 fprintf(stderr, "hyper is %lx\n", pCppArgs[nPos]); #endif - INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack, pStackStart, bOverFlow ); + INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack, pStackStart ); break; case typelib_TypeClass_LONG: case typelib_TypeClass_UNSIGNED_LONG: @@ -405,22 +455,22 @@ static void cpp_call( #if OSL_DEBUG_LEVEL > 2 fprintf(stderr, "long is %x\n", pCppArgs[nPos]); #endif - INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack, bOverFlow ); + INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack ); break; case typelib_TypeClass_SHORT: case typelib_TypeClass_CHAR: case typelib_TypeClass_UNSIGNED_SHORT: - INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack, bOverFlow ); + INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack ); break; case typelib_TypeClass_BOOLEAN: case typelib_TypeClass_BYTE: - INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack, bOverFlow ); + INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack ); break; case typelib_TypeClass_FLOAT: - INSERT_FLOAT( pCppArgs[nPos], nGPR, pGPR, pStack, bOverFlow ); + INSERT_FLOAT( pCppArgs[nPos], nGPR, pGPR, pStack ); break; case typelib_TypeClass_DOUBLE: - INSERT_DOUBLE( pCppArgs[nPos], nGPR, pGPR, pStack, pStackStart, bOverFlow ); + INSERT_DOUBLE( pCppArgs[nPos], nGPR, pGPR, pStack, pStackStart ); break; default: break; @@ -457,7 +507,7 @@ static void cpp_call( // no longer needed TYPELIB_DANGER_RELEASE( pParamTypeDescr ); } - INSERT_INT32( &(pCppArgs[nPos]), nGPR, pGPR, pStack, bOverFlow ); + INSERT_INT32( &(pCppArgs[nPos]), nGPR, pGPR, pStack ); } } @@ -468,7 +518,8 @@ static void cpp_call( pCppReturn, pReturnTypeRef, pStackStart, (pStack - pStackStart), - pGPR, nGPR); + pGPR, nGPR, + pFPR, nDR); // NO exception occurred... *ppUnoExc = 0;