Bug 492299 - add support for soft-float for Linux/PPC, r=bsmedberg
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>
Sat, 17 Oct 2009 21:05:36 -0700
changeset 34237 38b06fd30c16c4b2dc5b30a1a4d61dbe97c8e6a8
parent 34236 33c41598d5ced2596cf5ee2b020bfb0d4d3bef74
child 34238 8c32e0eecbad2f154294c67014ac9e09e26617d7
push id115
push userbmcbride@mozilla.com
push dateMon, 19 Oct 2009 23:27:00 +0000
reviewersbsmedberg
bugs492299
milestone1.9.3a1pre
Bug 492299 - add support for soft-float for Linux/PPC, r=bsmedberg current implemention assumes hard float what means dedicated floating point registers are used for floating point numbers. This does not work on soft float toolchains where dedicated floating point registers and opcodes are not used and/or available. On such toolchains the gcc compiler provides a built-in define __NO_FPRS__ to signalize such a behavior.
xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s
xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp
xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s
xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp
--- a/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s
@@ -19,16 +19,17 @@
 // Netscape Communications Corporation.
 // Portions created by the Initial Developer are Copyright (C) 1999
 // the Initial Developer. All Rights Reserved.
 //
 // Contributor(s):
 //   Franz.Sirl-kernel@lauterbach.com (Franz Sirl)
 //   beard@netscape.com (Patrick Beard)
 //   waterson@netscape.com (Chris Waterson)
+//   bigeasy@linutronix.de (Sebastian Andrzej Siewior)
 //
 // Alternatively, the contents of this file may be used under the terms of
 // either the GNU General Public License Version 2 or later (the "GPL"), or
 // the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 // in which case the provisions of the GPL or the LGPL are applicable instead
 // of those above. If you wish to allow use of your version of this file only
 // under the terms of either the GPL or the LGPL, and not to allow others to
 // use your version of this file under the terms of the MPL, indicate your
@@ -81,29 +82,33 @@ NS_InvokeByIndex_P:
 	neg     r0,r0
 	stwux   r9,sp,r0			// reserve stack space and save SP backchain
 
 	addi    r3,sp,8				// r3 <= args
 	mr      r4,r5				// r4 <= paramCount
 	mr      r5,r6				// r5 <= params
 	add     r6,r3,r10			// r6 <= gpregs ( == args + r10 )
 	mr      r30,r6				// store in r30 for use later...
+#ifndef __NO_FPRS__
 	addi    r7,r6,32			// r7 <= fpregs ( == gpregs + 32 )
+#else
+	li	r7, 0
+#endif
 
 	bl      invoke_copy_to_stack@local	// (args, paramCount, params, gpregs, fpregs)
-
+#ifndef __NO_FPRS__
 	lfd     f1,32(r30)			// load FP registers with method parameters
 	lfd     f2,40(r30)   
 	lfd     f3,48(r30)  
 	lfd     f4,56(r30)  
 	lfd     f5,64(r30)  
 	lfd     f6,72(r30)  
 	lfd     f7,80(r30)  
 	lfd     f8,88(r30)
-
+#endif
 	lwz     r3,8(r31)			// r3 <= that
 	lwz     r4,12(r31)			// r4 <= methodIndex
 	lwz     r5,0(r3)			// r5 <= vtable ( == *that )
 #if !((__GNUC__ == 3 && __GNUC_MINOR__ < 2) || __GXX_ABI_VERSION  >= 100) // G++ pre-V3 ABI
 	addi	r4,r4,2				// skip first two vtable entries
 #endif
 	slwi    r4,r4,2				// convert to offset ( *= 4 )
 	lwzx    r0,r5,r4			// r0 <= methodpointer ( == vtable + offset )
--- a/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp
@@ -18,16 +18,17 @@
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Franz.Sirl-kernel@lauterbach.com (Franz Sirl)
  *   beard@netscape.com (Patrick Beard)
  *   waterson@netscape.com (Chris Waterson)
+ *   bigeasy@linutronix.de (Sebastian Andrzej Siewior)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -48,35 +49,39 @@
 // ABI this means that the first 8 integral and floating point
 // parameters are passed in registers.
 
 #include "xptcprivate.h"
 
 // 8 integral parameters are passed in registers
 #define GPR_COUNT     8
 
-// 8 floating point parameters are passed in registers, floats are
-// promoted to doubles when passed in registers
+// With hardfloat support 8 floating point parameters are passed in registers,
+// floats are promoted to doubles when passed in registers
+// In Softfloat mode, everything is handled via gprs
+#ifndef __NO_FPRS__
 #define FPR_COUNT     8
-
+#endif
 extern "C" PRUint32
 invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s)
 {
   return PRUint32(((paramCount * 2) + 3) & ~3);
 }
 
 extern "C" void
 invoke_copy_to_stack(PRUint32* d,
                      PRUint32 paramCount,
                      nsXPTCVariant* s, 
                      PRUint32* gpregs,
                      double* fpregs)
 {
     PRUint32 gpr = 1; // skip one GP reg for 'that'
+#ifndef __NO_FPRS__
     PRUint32 fpr = 0;
+#endif
     PRUint32 tempu32;
     PRUint64 tempu64;
     
     for(uint32 i = 0; i < paramCount; i++, s++) {
         if(s->IsPtrData())
             tempu32 = (PRUint32) s->ptr;
         else {
             switch(s->type) {
@@ -93,27 +98,41 @@ invoke_copy_to_stack(PRUint32* d,
             case nsXPTType::T_BOOL:   tempu32 = s->val.b;             break;
             case nsXPTType::T_CHAR:   tempu32 = s->val.c;             break;
             case nsXPTType::T_WCHAR:  tempu32 = s->val.wc;            break;
             default:                  tempu32 = (PRUint32) s->val.p;  break;
             }
         }
 
         if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) {
+#ifndef __NO_FPRS__
             if (fpr < FPR_COUNT)
                 fpregs[fpr++]    = s->val.d;
+#else
+            if (gpr & 1)
+                gpr++;
+            if ((gpr + 1) < GPR_COUNT) {
+                *((double*) &gpregs[gpr]) = s->val.d;
+                gpr += 2;
+            }
+#endif
             else {
                 if ((PRUint32) d & 4) d++; // doubles are 8-byte aligned on stack
                 *((double*) d) = s->val.d;
                 d += 2;
             }
         }
         else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) {
+#ifndef __NO_FPRS__
             if (fpr < FPR_COUNT)
                 fpregs[fpr++]   = s->val.f; // if passed in registers, floats are promoted to doubles
+#else
+            if (gpr < GPR_COUNT)
+                *((float*) &gpregs[gpr++]) = s->val.f;
+#endif
             else
                 *((float*) d++) = s->val.f;
         }
         else if (!s->IsPtrData() && (s->type == nsXPTType::T_I64
                                      || s->type == nsXPTType::T_U64)) {
             if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6
             if ((gpr + 1) < GPR_COUNT) {
                 *((PRUint64*) &gpregs[gpr]) = tempu64;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s
@@ -19,16 +19,17 @@
 // Netscape Communications Corporation.
 // Portions created by the Initial Developer are Copyright (C) 1999
 // the Initial Developer. All Rights Reserved.
 //
 // Contributor(s):
 //   Franz.Sirl-kernel@lauterbach.com (Franz Sirl)
 //   beard@netscape.com (Patrick Beard)
 //   waterson@netscape.com (Chris Waterson)
+//   bigeasy@linutronix.de (Sebastian Andrzej Siewior)
 //
 // Alternatively, the contents of this file may be used under the terms of
 // either the GNU General Public License Version 2 or later (the "GPL"), or
 // the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 // in which case the provisions of the GPL or the LGPL are applicable instead
 // of those above. If you wish to allow use of your version of this file only
 // under the terms of either the GPL or the LGPL, and not to allow others to
 // use your version of this file under the terms of the MPL, indicate your
@@ -70,36 +71,41 @@ SharedStub:
 
 	stw	r4,12(sp)			// save GP registers
 	stw	r5,16(sp)			// (n.b. that we don't save r3
 	stw	r6,20(sp)			// because PrepareAndDispatch() is savvy)
 	stw	r7,24(sp)
 	stw	r8,28(sp)
 	stw	r9,32(sp)
 	stw	r10,36(sp)
-
+#ifndef __NO_FPRS__
 	stfd	f1,40(sp)			// save FP registers
 	stfd	f2,48(sp)
 	stfd	f3,56(sp)
 	stfd	f4,64(sp)
 	stfd	f5,72(sp)
 	stfd	f6,80(sp)
 	stfd	f7,88(sp)
 	stfd	f8,96(sp)
+#endif
 
 						// r3 has the 'self' pointer already
 	
 	mr      r4,r11				// r4 <= methodIndex selector, passed
 						// via r11 in the nsXPTCStubBase::StubXX() call
 	
 	addi	r5,sp,120			// r5 <= pointer to callers args area,
 						// beyond r3-r10/f1-f8 mapped range
 	
 	addi	r6,sp,8				// r6 <= gprData
+#ifndef __NO_FPRS__
 	addi	r7,sp,40			// r7 <= fprData
+#else
+	li	r7, 0				// r7 should be unused
+#endif
       
 	bl	PrepareAndDispatch@local	// Go!
     
 	lwz	r0,116(sp)			// restore LR
 	mtlr	r0
 	la	sp,112(sp)			// clean up the stack
 	blr
 
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp
@@ -18,16 +18,17 @@
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1999
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Franz.Sirl-kernel@lauterbach.com (Franz Sirl)
  *   beard@netscape.com (Patrick Beard)
  *   waterson@netscape.com (Chris Waterson)
+ *   bigeasy@linutronix.de (Sebastian Andrzej Siewior)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -44,21 +45,24 @@
 #include "xptiprivate.h"
 
 // The Linux/PPC ABI (aka PPC/SYSV ABI) passes the first 8 integral
 // parameters and the first 8 floating point parameters in registers
 // (r3-r10 and f1-f8), no stack space is allocated for these by the
 // caller.  The rest of the parameters are passed in the callers stack
 // area. The stack pointer has to retain 16-byte alignment, longlongs
 // and doubles are aligned on 8-byte boundaries.
-
+#ifndef __NO_FPRS__
 #define PARAM_BUFFER_COUNT     16
 #define GPR_COUNT               8
 #define FPR_COUNT               8
-
+#else
+#define PARAM_BUFFER_COUNT      8
+#define GPR_COUNT               8
+#endif
 // PrepareAndDispatch() is called by SharedStub() and calls the actual method.
 //
 // - 'args[]' contains the arguments passed on stack
 // - 'gprData[]' contains the arguments passed in integer registers
 // - 'fprData[]' contains the arguments passed in floating point registers
 // 
 // The parameters are mapped into an array of type 'nsXPTCMiniVariant'
 // and then the method gets called.
@@ -93,38 +97,54 @@ PrepareAndDispatch(nsXPTCStubBase* self,
         dispatchParams = paramBuffer;
 
     NS_ASSERTION(dispatchParams,"no place for params");
     if (! dispatchParams)
         return NS_ERROR_OUT_OF_MEMORY;
 
     PRUint32* ap = args;
     PRUint32 gpr = 1;    // skip one GPR register
+#ifndef __NO_FPRS__
     PRUint32 fpr = 0;
+#endif
     PRUint32 tempu32;
     PRUint64 tempu64;
 
     for(i = 0; i < paramCount; i++) {
         const nsXPTParamInfo& param = info->GetParam(i);
         const nsXPTType& type = param.GetType();
         nsXPTCMiniVariant* dp = &dispatchParams[i];
 	
         if (!param.IsOut() && type == nsXPTType::T_DOUBLE) {
+#ifndef __NO_FPRS__
             if (fpr < FPR_COUNT)
                 dp->val.d = fprData[fpr++];
+#else
+            if (gpr & 1)
+                gpr++;
+            if (gpr + 1 < GPR_COUNT) {
+                dp->val.d = *(double*) &gprData[gpr];
+                gpr += 2;
+            }
+#endif
             else {
                 if ((PRUint32) ap & 4) ap++; // doubles are 8-byte aligned on stack
                 dp->val.d = *(double*) ap;
                 ap += 2;
             }
             continue;
         }
         else if (!param.IsOut() && type == nsXPTType::T_FLOAT) {
+#ifndef __NO_FPRS__
             if (fpr < FPR_COUNT)
                 dp->val.f = (float) fprData[fpr++]; // in registers floats are passed as doubles
+#else
+            if (gpr  < GPR_COUNT)
+                dp->val.f = *(float*) &gprData[gpr++];
+#endif
             else
                 dp->val.f = *(float*) ap++;
             continue;
         }
         else if (!param.IsOut() && (type == nsXPTType::T_I64
                                     || type == nsXPTType::T_U64)) {
             if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6
             if ((gpr + 1) < GPR_COUNT) {