changeset 51:9e9d6a90492a r0.9-RC4

- armhf experimental vararg call support
author cslag
date Sun, 20 Dec 2015 20:27:43 +0100
parents 9bd3c5219505
children 7d84baf8cf80
files doc/manual/callconvs/callconv_arm32.tex dyncall/dyncall_callvm_arm32_arm_armhf.c
diffstat 2 files changed, 53 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/doc/manual/callconvs/callconv_arm32.tex	Sun Dec 20 15:38:14 2015 +0100
+++ b/doc/manual/callconvs/callconv_arm32.tex	Sun Dec 20 20:27:43 2015 +0100
@@ -335,10 +335,11 @@
 \item stack parameter order: right-to-left
 \item caller cleans up the stack
 \item first four non-floating-point words are passed using r0-r3
+\item out of those, 64bit parameters use 2 registers, either r0,r1 or r2,r3 (skipped registers are left unused)
 \item first 16 single-precision, or 8 double-precision arguments are passed via s0-s15 or d0-d7, respectively (note that since s and d registers are aliased, already used ones are skipped)
 \item subsequent parameters are pushed onto the stack (in right to left order, such that the stack pointer points to the first of the remaining parameters)
 \item note that as soon one floating point parameter is passed via the stack, subsequent single precision floating point parameters are also pushed onto the stack even if there are still free S* registers
-\item floating point vararg parameters (only doubles, b/c of promotion) are pushed onth the stack, never passed via registers
+\item float and double vararg function parameters (no matter if in ellipsis part of function, or not) are passed like int or long long parameters, vfp registers aren't used
 \item if the callee takes the address of one of the parameters and uses it to address other parameters (e.g. varargs) it has to copy - in its prolog - the first four words (for first 4 integer arguments) to a reserved stack area adjacent to the other parameters on the stack
 \item parameters \textless=\ 32 bits are passed as 32 bit words
 \item structures and unions are passed by value, with the first four words of the parameters in r0-r3 @@@?check doc
--- a/dyncall/dyncall_callvm_arm32_arm_armhf.c	Sun Dec 20 15:38:14 2015 +0100
+++ b/dyncall/dyncall_callvm_arm32_arm_armhf.c	Sun Dec 20 20:27:43 2015 +0100
@@ -30,7 +30,7 @@
 
 static DCCallVM* dc_callvm_new_arm32_armhf(DCCallVM_vt* vt, DCsize size)
 {
-  /* Store at least 16 bytes (4 words) for internal spill area. Assembly code depends on it. */
+  /* Store at least 16 bytes (4 words for first 4 int args) for internal spill area. Assembly code depends on it. */
   DCCallVM_arm32_armhf* p = (DCCallVM_arm32_armhf*)dcAllocMem(sizeof(DCCallVM_arm32_armhf)+size+16);
   dc_callvm_base_init(&p->mInterface, vt);
   dcVecInit(&p->mVecHead, size);
@@ -72,6 +72,7 @@
 static void a_char    (DCCallVM* in_self, DCchar  x) { a_int(in_self, x); }
 static void a_short   (DCCallVM* in_self, DCshort x) { a_int(in_self, x); }
 static void a_long    (DCCallVM* in_self, DClong  x) { a_int(in_self, x); }
+
 static void a_longlong(DCCallVM* in_self, DClonglong x)
 {
   DCCallVM_arm32_armhf* p = (DCCallVM_arm32_armhf*)in_self;
@@ -86,6 +87,7 @@
     dcVecAppend(&p->mVecHead, &x, sizeof(DClonglong));
   }
 }
+
 static void a_pointer(DCCallVM* in_p, DCpointer x) { a_int(in_p, (DCint) x ); }
 
 static void a_float(DCCallVM* in_p, DCfloat x)
@@ -100,7 +102,7 @@
     }
   } else {
     dcVecAppend(&p->mVecHead, &x, sizeof(DCfloat));
-  } 
+  }
 }
 
 static void a_double(DCCallVM* in_p, DCdouble x)
@@ -115,21 +117,28 @@
     * (double*) &p->S[p->d] = x;
     p->d += 2;
     if (!(p->s & 1)) {
-      /* if s is even it always equals d. 
-	 otherwise, s points to an odd float register. 
-       */
+      /* if s is even it always equals d. otherwise, s points to an odd float register. */
       p->s = p->d;
     }
   } else {
     p->s = 16; /* fp registers all full - need to use stack now: stop filling gaps for single precision, also */
     v.d = x;
-
     /* 64 bit values need to be aligned on 8 byte boundaries */
     dcVecSkip(&p->mVecHead, dcVecSize(&p->mVecHead) & 4);
     dcVecAppend(&p->mVecHead, &v.b[0], sizeof(DCdouble));
   }
 }
 
+static void a_float_ellipsis(DCCallVM* in_p, DCfloat x)
+{
+  a_int(in_p, *(DCint*)&x);
+}
+
+static void a_double_ellipsis(DCCallVM* in_p, DCdouble x)
+{
+  a_longlong(in_p, *(DClonglong*)&x);
+}
+
 void call(DCCallVM* in_p, DCpointer target)
 {
   DCCallVM_arm32_armhf* p = (DCCallVM_arm32_armhf*)in_p;
@@ -143,7 +152,7 @@
 , &mode
 , &a_bool
 , &a_char
-, &a_short 
+, &a_short
 , &a_int
 , &a_long
 , &a_longlong
@@ -164,7 +173,35 @@
 , NULL /* callStruct */
 };
 
-DCCallVM* dcNewCallVM(DCsize size) 
+DCCallVM_vt vt_armhf_ellipsis =
+{
+  &deinit
+, &reset
+, &mode
+, &a_bool
+, &a_char
+, &a_short
+, &a_int
+, &a_long
+, &a_longlong
+, &a_float_ellipsis
+, &a_double_ellipsis
+, &a_pointer
+, NULL /* argStruct */
+, (DCvoidvmfunc*)       &call
+, (DCboolvmfunc*)       &call
+, (DCcharvmfunc*)       &call
+, (DCshortvmfunc*)      &call
+, (DCintvmfunc*)        &call
+, (DClongvmfunc*)       &call
+, (DClonglongvmfunc*)   &call
+, (DCfloatvmfunc*)      &call
+, (DCdoublevmfunc*)     &call
+, (DCpointervmfunc*)    &call
+, NULL /* callStruct */
+};
+
+DCCallVM* dcNewCallVM(DCsize size)
 {
 #if defined(DC__ABI_ARM_EABI)
   return dc_callvm_new_arm32_arm(&eabi, size);
@@ -180,18 +217,18 @@
 static void mode(DCCallVM* in_self,DCint mode)
 {
   DCCallVM_arm32_armhf* self = (DCCallVM_arm32_armhf*) in_self;
-  DCCallVM_vt*  vt;
   switch(mode) {
-    case DC_CALL_C_DEFAULT:        
+    case DC_CALL_C_DEFAULT:
+    case DC_CALL_C_ARM_ARMHF:
+      self->mInterface.mVTpointer = &vt_armhf;
+      break;
     case DC_CALL_C_ELLIPSIS:
     case DC_CALL_C_ELLIPSIS_VARARGS:
-    case DC_CALL_C_ARM_ARMHF:        
-      vt = &vt_armhf;
+      self->mInterface.mVTpointer = &vt_armhf_ellipsis;
       break;
-    default: 
+    default:
       in_self->mError = DC_ERROR_UNSUPPORTED_MODE;
       return;
   }
-  self->mInterface.mVTpointer = vt;
 }