Kaydet (Commit) dab11f7f authored tarafından Jani Monoses's avatar Jani Monoses

ARM bridge: VFP ABI (armhf) support

üst 746e9a7d
......@@ -8,6 +8,17 @@
# define UNWIND
#else
# 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"
......@@ -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
......
......@@ -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
}
......
......@@ -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 );
}
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment