Commit 2e825e219fa06d308b9a9863d70320606d67490d

YunQiang Su 2022-05-16T09:47:11

MIPS: fix some N32 test failure (#701) Some go closure and pointer testcase fails. These failures is not introduced by the complex support code.

diff --git a/src/mips/ffi.c b/src/mips/ffi.c
index 77bf3db..e704325 100644
--- a/src/mips/ffi.c
+++ b/src/mips/ffi.c
@@ -84,6 +84,8 @@ static void ffi_prep_args(char *stack,
   memset(stack, 0, bytes);
 
 #ifdef FFI_MIPS_N32
+  int soft_float = (ecif->cif->abi == FFI_N32_SOFT_FLOAT
+		    || ecif->cif->abi == FFI_N64_SOFT_FLOAT);
   /* If more than 8 double words are used, the remainder go
      on the stack. We reorder stuff on the stack here to 
      support this easily. */
@@ -149,7 +151,7 @@ static void ffi_prep_args(char *stack,
           if (type == FFI_TYPE_POINTER)
             type = (ecif->cif->abi == FFI_N64
 		    || ecif->cif->abi == FFI_N64_SOFT_FLOAT)
-	      ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+	      ? FFI_TYPE_SINT64 : FFI_TYPE_UINT32;
 
 	if (i < 8 && (ecif->cif->abi == FFI_N32_SOFT_FLOAT
 		      || ecif->cif->abi == FFI_N64_SOFT_FLOAT))
@@ -204,9 +206,10 @@ static void ffi_prep_args(char *stack,
 		/* expand from 4+4 to 8+8 if pass with fpr reg */
 		/* argp will wind back to stack when we process all of reg args */
 		/* all var_args passed with gpr, should be expand */
-	        if((*p_arg)->elements[0]->type == FFI_TYPE_FLOAT
-				&& argp>=argp_f
-				&& i < ecif->cif->mips_nfixedargs)
+	        if(!soft_float
+		    && (*p_arg)->elements[0]->type == FFI_TYPE_FLOAT
+		    && argp>=argp_f
+		    && i < ecif->cif->mips_nfixedargs)
 		  {
 		    *(float *) argp = *(float *)(* p_argv);
 		    argp += z;
@@ -644,7 +647,7 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
 
       case FFI_TYPE_POINTER:
 	if (cif->abi == FFI_N32_SOFT_FLOAT || cif->abi == FFI_N32)
-	  cif->flags += FFI_TYPE_SINT32 << (FFI_FLAG_BITS * 8);
+	  cif->flags += FFI_TYPE_UINT32 << (FFI_FLAG_BITS * 8);
 	else
 	  cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
 	break;
@@ -668,8 +671,9 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
 	   two doubles.  */
 	if (soft_float)
 	  {
-	    cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
-	    cif->flags += FFI_TYPE_SMALLSTRUCT2 << (4 + (FFI_FLAG_BITS * 8));
+	    /* if ret is long double, the ret is given by v0 and a0, no idea why
+	     * Let's us VOID | VOID | LONGDOUBLE for it*/
+	    cif->flags += FFI_TYPE_LONGDOUBLE << (FFI_FLAG_BITS * 8);
  	  }
 	else
 	  {
@@ -694,6 +698,10 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
 		case FFI_TYPE_INT:
 		  type = FFI_TYPE_SMALLSTRUCT2;
 		  break;
+		case FFI_TYPE_LONGDOUBLE:
+		  type = FFI_TYPE_LONGDOUBLE;
+		  break;
+		case FFI_TYPE_FLOAT:
 		default:
 		  type = FFI_TYPE_SMALLSTRUCT;
 		}
@@ -1194,10 +1202,10 @@ ffi_closure_mips_inner_N32 (ffi_cif *cif,
           /* The size of a pointer depends on the ABI */
           if (type == FFI_TYPE_POINTER)
             type = (cif->abi == FFI_N64 || cif->abi == FFI_N64_SOFT_FLOAT)
-	      ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+	      ? FFI_TYPE_SINT64 : FFI_TYPE_UINT32;
 
 	  if (soft_float && type ==  FFI_TYPE_FLOAT)
-	    type = FFI_TYPE_UINT32;
+	    type = FFI_TYPE_SINT32;
 
           switch (type)
             {
diff --git a/src/mips/ffitarget.h b/src/mips/ffitarget.h
index 61d04f9..294c3ba 100644
--- a/src/mips/ffitarget.h
+++ b/src/mips/ffitarget.h
@@ -112,10 +112,11 @@
 #define FFI_TYPE_STRUCT_SMALL  93
 #define FFI_TYPE_STRUCT_SMALL2 109
 
-#define FFI_TYPE_COMPLEX_II    95
-#define FFI_TYPE_COMPLEX_FF    47
-#define FFI_TYPE_COMPLEX_DD    63
-#define FFI_TYPE_COMPLEX_LDLD  79
+#define FFI_TYPE_COMPLEX_SMALL    95
+#define FFI_TYPE_COMPLEX_SMALL2   111
+#define FFI_TYPE_COMPLEX_FF       47
+#define FFI_TYPE_COMPLEX_DD       63
+#define FFI_TYPE_COMPLEX_LDLD     79
 
 /* and for n32 soft float, add 16 * 2^4 */
 #define FFI_TYPE_STRUCT_D_SOFT      317
diff --git a/src/mips/n32.S b/src/mips/n32.S
index f9bfa5a..e1938d1 100644
--- a/src/mips/n32.S
+++ b/src/mips/n32.S
@@ -236,14 +236,21 @@ callit:
 	# Shift the return type flag over
 	SRL	t6, 8*FFI_FLAG_BITS
 
-	beq	t6, FFI_TYPE_SINT32, retint	
-	bne     t6, FFI_TYPE_INT, retfloat
+	beq	t6, FFI_TYPE_SINT32, retint
+	bne     t6, FFI_TYPE_INT, retuint32
 retint:
 	jal	t9
 	REG_L	t4, 4*FFI_SIZEOF_ARG($fp)
 	REG_S	v0, 0(t4)
 	b	epilogue
 
+retuint32:
+	bne     t6, FFI_TYPE_UINT32, retfloat
+	jal	t9
+	REG_L	t4, 4*FFI_SIZEOF_ARG($fp)
+	sw	v0, 0(t4)
+	b	epilogue
+
 retfloat:
 #ifndef __mips_soft_float
 	bne     t6, FFI_TYPE_FLOAT, retdouble
@@ -259,7 +266,7 @@ retdouble:
 	s.d	$f0, 0(t4)
 	b	epilogue
 
-retstruct_d:	
+retstruct_d:
 	bne	t6, FFI_TYPE_STRUCT_D, retstruct_f
 	jal	t9
 	REG_L	t4, 4*FFI_SIZEOF_ARG($fp)
@@ -346,7 +353,7 @@ retstruct_d_d_soft:
 	jal	t9
 	REG_L	t4, 4*FFI_SIZEOF_ARG($fp)
 	sd	v0, 0(t4)
-	sd	v1, 8(t4)
+	sd	a0, 8(t4) # not typo, it is a0, I have no idea, gcc does do it
 	b	epilogue
 	
 retstruct_f_f_soft:	
@@ -370,7 +377,7 @@ retstruct_f_d_soft:
 	jal	t9
 	REG_L	t4, 4*FFI_SIZEOF_ARG($fp)
 	sw	v0, 0(t4)
-	sd	v1, 8(t4)
+	sd	a0, 8(t4) # not typo, it is a0, I have no idea, gcc does do it
 	b	epilogue
 	
 retstruct_small:	
@@ -381,21 +388,37 @@ retstruct_small:
 	b	epilogue
 	
 retstruct_small2:	
-	bne	t6, FFI_TYPE_STRUCT_SMALL2, retcomplex_i_i
+	bne	t6, FFI_TYPE_STRUCT_SMALL2, retlongdouble_soft
 	jal	t9
 	REG_L	t4, 4*FFI_SIZEOF_ARG($fp)
 	REG_S	v0, 0(t4)
 	REG_S	v1, 8(t4)
 	b	epilogue
 	
-retcomplex_i_i:
-	bne	t6, FFI_TYPE_COMPLEX_II, retstruct
+retlongdouble_soft:
+	bne	t6, FFI_TYPE_LONGDOUBLE, retcomplex_small
 	jal	t9
 	REG_L	t4, 4*FFI_SIZEOF_ARG($fp)
 	REG_S	v0, 0(t4)
+	REG_S	a0, 8(t4) # not typo, it is a0, I have no idea, gcc does do it
 	b	epilogue
 
-retstruct:	
+retcomplex_small:
+	bne	t6, FFI_TYPE_COMPLEX_SMALL, retcomplex_small2
+	jal	t9
+	REG_L	t4, 4*FFI_SIZEOF_ARG($fp)
+	REG_S	v0, 0(t4)
+	b	epilogue
+
+retcomplex_small2:
+	bne	t6, FFI_TYPE_COMPLEX_SMALL2, retstruct
+	jal	t9
+	REG_L	t4, 4*FFI_SIZEOF_ARG($fp)
+	REG_S	v0, 0(t4)
+	REG_S	v1, 8(t4)
+	b	epilogue
+
+retstruct:
 noretval:	
 	jal	t9
 	
@@ -489,8 +512,13 @@ ffi_go_closure_N32:
 
 	# Call ffi_closure_mips_inner_N32 to do the real work.
 	LA	t9, ffi_closure_mips_inner_N32
+#if _MIPS_SIM==_ABIN32
+	lw	a0, 4($15)   # cif
+	lw	a1, 8($15) # fun
+#else
 	REG_L	a0, 8($15)   # cif
 	REG_L	a1, 16($15) # fun
+#endif
 	move	a2, t7                     # userdata=closure
 	ADDU	a3, $sp, V0_OFF2           # rvalue
 	ADDU	a4, $sp, A0_OFF2           # ar
@@ -558,10 +586,15 @@ $do_closure:
 	jalr	t9
 
 	# Return flags are in v0
-	bne     v0, FFI_TYPE_SINT32, cls_retint
+	bne     v0, FFI_TYPE_SINT32, cls_retuint32
 	lw	v0, V0_OFF2($sp)
 	b	cls_epilogue
 
+cls_retuint32:
+	bne     v0, FFI_TYPE_UINT32, cls_retint
+	lwu	v0, V0_OFF2($sp)
+	b	cls_epilogue
+
 cls_retint:
 	bne     v0, FFI_TYPE_INT, cls_retfloat
 	REG_L	v0, V0_OFF2($sp)
@@ -595,25 +628,12 @@ cls_retstruct_d_d:
 	b	cls_epilogue
 
 cls_retcomplex_d_d:
-	bne	v0, FFI_TYPE_COMPLEX_DD, cls_retcomplex_ld_ld
+	bne	v0, FFI_TYPE_COMPLEX_DD, cls_retcomplex_f_f
 	l.d	$f0, V0_OFF2($sp)
 	l.d	$f2, V1_OFF2($sp)
 	b	cls_epilogue
 	
-cls_retcomplex_ld_ld:
-	bne	v0, FFI_TYPE_COMPLEX_LDLD, cls_retstruct_f_f
-	REG_L	t8, A0_OFF2($sp)
-	REG_L	t9, 16($sp)
-	REG_S	t9, 0(t8)
-	REG_L	t9, 24($sp)
-	REG_S	t9, 8(t8)
-	REG_L	t9, 32($sp)
-	REG_S	t9, 16(t8)
-	REG_L	t9, 40($sp)
-	REG_S	t9, 24(t8)
-	b	cls_epilogue
-
-cls_retstruct_f_f:	
+cls_retstruct_f_f:
 	bne	v0, FFI_TYPE_STRUCT_FF, cls_retcomplex_f_f
 	l.s	$f0, V0_OFF2($sp)
 	l.s	$f2, V1_OFF2($sp)
@@ -632,12 +652,31 @@ cls_retstruct_d_f:
 	b	cls_epilogue
 	
 cls_retstruct_f_d:	
-	bne	v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2
+	bne	v0, FFI_TYPE_STRUCT_FD, cls_retcomplex_ld_ld
 	l.s	$f0, V0_OFF2($sp)
 	l.d	$f2, V1_OFF2($sp)
 	b	cls_epilogue
+#else
+cls_longdouble_soft:
+	bne	v0, FFI_TYPE_LONGDOUBLE, cls_retcomplex_ld_ld
+	REG_L	v0, V0_OFF2($sp)
+	REG_L	a0, V1_OFF2($sp) # not typo, it is a0, I have no idea, gcc does do it
+	b	cls_epilogue
 #endif
-	
+
+cls_retcomplex_ld_ld:
+	bne	v0, FFI_TYPE_COMPLEX_LDLD, cls_retstruct_small2
+	REG_L	t8, A0_OFF2($sp)
+	REG_L	t9, 16($sp)
+	REG_S	t9, 0(t8)
+	REG_L	t9, 24($sp)
+	REG_S	t9, 8(t8)
+	REG_L	t9, 32($sp)
+	REG_S	t9, 16(t8)
+	REG_L	t9, 40($sp)
+	REG_S	t9, 24(t8)
+	b	cls_epilogue
+
 cls_retstruct_small2:	
 	REG_L	v0, V0_OFF2($sp)
 	REG_L	v1, V1_OFF2($sp)