PATCH: PR target/39082: union with long double doesn't follow x86-64 psABI

H.J. Lu hjl.tools@gmail.com
Wed Feb 4 18:28:00 GMT 2009


On Wed, Feb 4, 2009 at 7:22 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Feb 04, 2009 at 04:02:56PM +0100, Richard Guenther wrote:
>> On Wed, Feb 4, 2009 at 3:47 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> > On Wed, Feb 04, 2009 at 06:45:13AM -0800, H.J. Lu wrote:
>> >> On Tue, Feb 03, 2009 at 06:31:21PM -0800, H.J. Lu wrote:
>> >> > Hi,
>> >> >
>> >> > This patch fixes the psABI violation by passing an aggregate in
>> >> > memory if X87UP class isn't preceded by X87 class. I also added some
>> >> > abi testcases based on
>> >> >
>> >> > https://www.x86-64.org/svn/trunk/abitest
>> >> >
>> >> > OK for trunk if it passes tests on Linux/x86-64?
>> >> >
>> >>
>> >> It passed all tests.  OK for trunk and active branches?
>> >
>> > I'm not convinced such an ABI change can be made on release branches.
>>
>> I am not convinced such ABI changes should be done without adding
>> a diagnostic for the cases that changed.  And I agree that release branches
>> should not be touched.
>>
>
> This problem happens deep in the backend. Adding a proper diagnostic
> may not be easy without FE help. I will see what I can do.
>

Here is the updated patch with warning for ABI change. OK for trunk?

Thanks.


-- 
H.J.
-------------- next part --------------
gcc/

2009-02-04  H.J. Lu  <hongjiu.lu@intel.com>

	PR target/39082
	* config/i386/i386.c (classify_argument): Pass an aggregate in
	memory if X87UP class isn't preceded by X87 class.  Warn about
	the ABI change.

	* config/i386/i386.h (machine_function): Add warned_union.

gcc/testsuite/

2009-02-04  H.J. Lu  <hongjiu.lu@intel.com>

	PR target/39082
	* gcc.target/i386/pr39082-1.c: New.

	* gcc.target/x86_64/abi/args.h (XMM_T): Add _m64 and _m128 if
	CHECK_M64_M128 is defined.
	(check_f_arguments): Add "do".
	(check_vector_arguments): New.
	(check_m64_arguments): Likewise.
	(check_m128_arguments): Likewise.

	* gcc.target/x86_64/abi/defines.h: Include <xmmintrin.h>.
	(CHECK_M64_M128): Define.

	* gcc.target/x86_64/abi/test_m64m128_returning.c: New.  Based
	on abitest.
	* gcc.target/x86_64/abi/test_passing_m64m128.c: Likewise.

	* gcc.target/x86_64/abi/test_passing_structs.c: Define __m128
	tests only if CHECK_M64_M128 is defined.

	* gcc.target/x86_64/abi/test_passing_structs.c (m128_struct): New.
	(m128_2_struct): Likewise.
	(check_struct_passing5): Likewise.
	(check_struct_passing6): Likewise.
	(main): Test struct with __m128 if CHECK_M64_M128 is defined.

	* gcc.target/x86_64/abi/test_passing_unions.c (un4): New.
	(un5): Likewise.
	(check_union_passing4): Likewise.
	(main): Test union with __m128 if CHECK_M64_M128 is defined.

Index: gcc/testsuite/gcc.target/i386/pr39082-1.c
===================================================================
--- gcc/testsuite/gcc.target/i386/pr39082-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/i386/pr39082-1.c	(revision 5167)
@@ -0,0 +1,35 @@
+/* PR target/39082 */
+/* { dg-do compile } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O2" } */
+
+union un
+{
+  long double x;
+  int i;
+};
+
+extern int bar1 (union un);
+extern union un bar2 (int);
+
+int
+foo1 (union un u) /* { dg-warning "The ABI of passing union with long double has changed" } */
+{
+  bar1 (u);
+  return u.i;
+}
+
+int
+foo2 (void)
+{
+  union un u;
+  u.i = 1;
+  return foo1 (u) + bar1 (u); /* { dg-warning "The ABI of passing union with long double has changed" } */
+}
+
+int
+foo3 (int x)
+{
+  union un u = bar2 (x); /* { dg-warning "The ABI of passing union with long double has changed" } */
+  return u.i;
+}
Index: gcc/testsuite/gcc.target/x86_64/abi/test_passing_unions.c
===================================================================
--- gcc/testsuite/gcc.target/x86_64/abi/test_passing_unions.c	(revision 5120)
+++ gcc/testsuite/gcc.target/x86_64/abi/test_passing_unions.c	(revision 5167)
@@ -1,4 +1,4 @@
-/* This tests passing of structs. Only integers are tested.  */
+/* This tests passing of structs.  */
 
 #include "defines.h"
 #include "args.h"
@@ -60,6 +60,54 @@ check_union_passing3(union un3 u ATTRIBU
 #define check_union_passing2 WRAP_CALL(check_union_passing2)
 #define check_union_passing3 WRAP_CALL(check_union_passing3)
 
+#ifdef CHECK_M64_M128
+union un4
+{
+  __m128 x;
+  float f;
+};
+
+union un5
+{
+  __m128 x;
+  long i;
+};
+
+void
+check_union_passing4(union un4 u ATTRIBUTE_UNUSED)
+{
+  check_m128_arguments;
+}
+
+void
+check_union_passing5(union un5 u ATTRIBUTE_UNUSED)
+{
+  check_int_arguments;
+  check_vector_arguments(m128, 8);
+}
+
+#define check_union_passing4 WRAP_CALL(check_union_passing4)
+#define check_union_passing5 WRAP_CALL(check_union_passing5)
+#endif
+
+union un6
+{
+  long double ld;
+  int i;
+};
+
+
+void
+check_union_passing6(union un6 u ATTRIBUTE_UNUSED)
+{
+  /* Check the passing on the stack by comparing the address of the
+     stack elements to the expected place on the stack.  */
+  assert ((unsigned long)&u.ld == rsp+8);
+  assert ((unsigned long)&u.i == rsp+8);
+}
+
+#define check_union_passing6 WRAP_CALL(check_union_passing6)
+
 int
 main (void)
 {
@@ -70,6 +118,11 @@ main (void)
   struct int_struct is;
   struct long_struct ls;
 #endif /* CHECK_LARGER_UNION_PASSING */
+#ifdef CHECK_M64_M128
+  union un4 u4 = { { 48.394, 39.3, -397.9, 3484.9 } };
+  union un5 u5 = { { 48.394, 39.3, -397.9, 3484.9 } };
+#endif
+  union un6 u6;
 
   /* Check a union with char, int.  */
   clear_struct_registers;
@@ -140,5 +193,24 @@ main (void)
   check_union_passing3(u3);
 #endif /* CHECK_LARGER_UNION_PASSING */
 
+#ifdef CHECK_M64_M128
+  clear_struct_registers;
+  fregs.xmm0._m128[0] = u4.x;
+  num_fregs = 1;
+  clear_float_hardware_registers;
+  check_union_passing4(u4);
+
+  clear_struct_registers;
+  fregs.xmm0._m128[0] = u5.x;
+  num_fregs = 1;
+  num_iregs = 1;
+  iregs.I0 = u5.i;
+  clear_float_hardware_registers;
+  check_union_passing5(u5);
+#endif
+
+  u6.i = 2;
+  check_union_passing6(u6);
+
   return 0;
 }
Index: gcc/testsuite/gcc.target/x86_64/abi/args.h
===================================================================
--- gcc/testsuite/gcc.target/x86_64/abi/args.h	(revision 5120)
+++ gcc/testsuite/gcc.target/x86_64/abi/args.h	(revision 5167)
@@ -25,6 +25,10 @@ typedef union {
   long _long[2];
   int _int[4];
   unsigned long _ulong[2];
+#ifdef CHECK_M64_M128
+  __m64 _m64[2];
+  __m128 _m128[1];
+#endif
 } XMM_T;
 
 typedef union {
@@ -111,7 +115,7 @@ extern unsigned int num_iregs, num_fregs
   clear_int_hardware_registers
 
 /* TODO: Do the checking.  */
-#define check_f_arguments(T) { \
+#define check_f_arguments(T) do { \
   assert (num_fregs <= 0 || fregs.xmm0._ ## T [0] == xmm_regs[0]._ ## T [0]); \
   assert (num_fregs <= 1 || fregs.xmm1._ ## T [0] == xmm_regs[1]._ ## T [0]); \
   assert (num_fregs <= 2 || fregs.xmm2._ ## T [0] == xmm_regs[2]._ ## T [0]); \
@@ -125,6 +129,44 @@ extern unsigned int num_iregs, num_fregs
 #define check_float_arguments check_f_arguments(float)
 #define check_double_arguments check_f_arguments(double)
 
+#define check_vector_arguments(T,O) do { \
+  assert (num_fregs <= 0 \
+	  || memcmp (((char *) &fregs.xmm0) + (O), \
+		     &xmm_regs[0], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 1 \
+	  || memcmp (((char *) &fregs.xmm1) + (O), \
+		     &xmm_regs[1], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 2 \
+	  || memcmp (((char *) &fregs.xmm2) + (O), \
+		     &xmm_regs[2], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 3 \
+	  || memcmp (((char *) &fregs.xmm3) + (O), \
+		     &xmm_regs[3], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 4 \
+	  || memcmp (((char *) &fregs.xmm4) + (O), \
+		     &xmm_regs[4], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 5 \
+	  || memcmp (((char *) &fregs.xmm5) + (O), \
+		     &xmm_regs[5], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 6 \
+	  || memcmp (((char *) &fregs.xmm6) + (O), \
+		     &xmm_regs[6], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 7 \
+	  || memcmp (((char *) &fregs.xmm7) + (O), \
+		     &xmm_regs[7], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  } while (0)
+
+#define check_m64_arguments check_vector_arguments(m64, 0)
+#define check_m128_arguments check_vector_arguments(m128, 0)
+
 /* ldoubles are not passed in registers */
 #define check_ldouble_arguments
 
Index: gcc/testsuite/gcc.target/x86_64/abi/test_passing_m64m128.c
===================================================================
--- gcc/testsuite/gcc.target/x86_64/abi/test_passing_m64m128.c	(revision 0)
+++ gcc/testsuite/gcc.target/x86_64/abi/test_passing_m64m128.c	(revision 5167)
@@ -0,0 +1,249 @@
+#include <stdio.h>
+#include "defines.h"
+#include "macros.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+unsigned int num_iregs, num_fregs;
+
+/* This struct holds values for argument checking.  */
+struct 
+{
+  XMM_T i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23;
+} values;
+
+char *pass;
+int failed = 0;
+
+#undef assert
+#define assert(c) do { \
+  if (!(c)) {failed++; printf ("failed %s\n", pass); } \
+} while (0)
+
+#define compare(X1,X2,T) do { \
+  assert (memcmp (&X1, &X2, sizeof (T)) == 0); \
+} while (0)
+
+void
+fun_check_passing_m64_8_values (__m64 i0 ATTRIBUTE_UNUSED, __m64 i1 ATTRIBUTE_UNUSED, __m64 i2 ATTRIBUTE_UNUSED, __m64 i3 ATTRIBUTE_UNUSED, __m64 i4 ATTRIBUTE_UNUSED, __m64 i5 ATTRIBUTE_UNUSED, __m64 i6 ATTRIBUTE_UNUSED, __m64 i7 ATTRIBUTE_UNUSED)
+{
+  /* Check argument values.  */
+  compare (values.i0, i0, __m64);
+  compare (values.i1, i1, __m64);
+  compare (values.i2, i2, __m64);
+  compare (values.i3, i3, __m64);
+  compare (values.i4, i4, __m64);
+  compare (values.i5, i5, __m64);
+  compare (values.i6, i6, __m64);
+  compare (values.i7, i7, __m64);
+}
+
+void
+fun_check_passing_m64_8_regs (__m64 i0 ATTRIBUTE_UNUSED, __m64 i1 ATTRIBUTE_UNUSED, __m64 i2 ATTRIBUTE_UNUSED, __m64 i3 ATTRIBUTE_UNUSED, __m64 i4 ATTRIBUTE_UNUSED, __m64 i5 ATTRIBUTE_UNUSED, __m64 i6 ATTRIBUTE_UNUSED, __m64 i7 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m64_arguments;
+}
+
+void
+fun_check_passing_m64_20_values (__m64 i0 ATTRIBUTE_UNUSED, __m64 i1 ATTRIBUTE_UNUSED, __m64 i2 ATTRIBUTE_UNUSED, __m64 i3 ATTRIBUTE_UNUSED, __m64 i4 ATTRIBUTE_UNUSED, __m64 i5 ATTRIBUTE_UNUSED, __m64 i6 ATTRIBUTE_UNUSED, __m64 i7 ATTRIBUTE_UNUSED, __m64 i8 ATTRIBUTE_UNUSED, __m64 i9 ATTRIBUTE_UNUSED, __m64 i10 ATTRIBUTE_UNUSED, __m64 i11 ATTRIBUTE_UNUSED, __m64 i12 ATTRIBUTE_UNUSED, __m64 i13 ATTRIBUTE_UNUSED, __m64 i14 ATTRIBUTE_UNUSED, __m64 i15 ATTRIBUTE_UNUSED, __m64 i16 ATTRIBUTE_UNUSED, __m64 i17 ATTRIBUTE_UNUSED, __m64 i18 ATTRIBUTE_UNUSED, __m64 i19 ATTRIBUTE_UNUSED)
+{
+  /* Check argument values.  */
+  compare (values.i0 , i0, __m64);
+  compare (values.i1 , i1, __m64);
+  compare (values.i2 , i2, __m64);
+  compare (values.i3 , i3, __m64);
+  compare (values.i4 , i4, __m64);
+  compare (values.i5 , i5, __m64);
+  compare (values.i6 , i6, __m64);
+  compare (values.i7 , i7, __m64);
+  compare (values.i8 , i8, __m64);
+  compare (values.i9 , i9, __m64);
+  compare (values.i10 , i10, __m64);
+  compare (values.i11 , i11, __m64);
+  compare (values.i12 , i12, __m64);
+  compare (values.i13 , i13, __m64);
+  compare (values.i14 , i14, __m64);
+  compare (values.i15 , i15, __m64);
+  compare (values.i16 , i16, __m64);
+  compare (values.i17 , i17, __m64);
+  compare (values.i18 , i18, __m64);
+  compare (values.i19 , i19, __m64);
+}
+
+void
+fun_check_passing_m64_20_regs (__m64 i0 ATTRIBUTE_UNUSED, __m64 i1 ATTRIBUTE_UNUSED, __m64 i2 ATTRIBUTE_UNUSED, __m64 i3 ATTRIBUTE_UNUSED, __m64 i4 ATTRIBUTE_UNUSED, __m64 i5 ATTRIBUTE_UNUSED, __m64 i6 ATTRIBUTE_UNUSED, __m64 i7 ATTRIBUTE_UNUSED, __m64 i8 ATTRIBUTE_UNUSED, __m64 i9 ATTRIBUTE_UNUSED, __m64 i10 ATTRIBUTE_UNUSED, __m64 i11 ATTRIBUTE_UNUSED, __m64 i12 ATTRIBUTE_UNUSED, __m64 i13 ATTRIBUTE_UNUSED, __m64 i14 ATTRIBUTE_UNUSED, __m64 i15 ATTRIBUTE_UNUSED, __m64 i16 ATTRIBUTE_UNUSED, __m64 i17 ATTRIBUTE_UNUSED, __m64 i18 ATTRIBUTE_UNUSED, __m64 i19 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m64_arguments;
+}
+
+void
+fun_check_passing_m128_8_values (__m128 i0 ATTRIBUTE_UNUSED, __m128 i1 ATTRIBUTE_UNUSED, __m128 i2 ATTRIBUTE_UNUSED, __m128 i3 ATTRIBUTE_UNUSED, __m128 i4 ATTRIBUTE_UNUSED, __m128 i5 ATTRIBUTE_UNUSED, __m128 i6 ATTRIBUTE_UNUSED, __m128 i7 ATTRIBUTE_UNUSED)
+{
+  /* Check argument values.  */
+  compare (values.i0, i0, __m128);
+  compare (values.i1, i1, __m128);
+  compare (values.i2, i2, __m128);
+  compare (values.i3, i3, __m128);
+  compare (values.i4, i4, __m128);
+  compare (values.i5, i5, __m128);
+  compare (values.i6, i6, __m128);
+  compare (values.i7, i7, __m128);
+}
+
+void
+fun_check_passing_m128_8_regs (__m128 i0 ATTRIBUTE_UNUSED, __m128 i1 ATTRIBUTE_UNUSED, __m128 i2 ATTRIBUTE_UNUSED, __m128 i3 ATTRIBUTE_UNUSED, __m128 i4 ATTRIBUTE_UNUSED, __m128 i5 ATTRIBUTE_UNUSED, __m128 i6 ATTRIBUTE_UNUSED, __m128 i7 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m128_arguments;
+}
+
+void
+fun_check_passing_m128_20_values (__m128 i0 ATTRIBUTE_UNUSED, __m128 i1 ATTRIBUTE_UNUSED, __m128 i2 ATTRIBUTE_UNUSED, __m128 i3 ATTRIBUTE_UNUSED, __m128 i4 ATTRIBUTE_UNUSED, __m128 i5 ATTRIBUTE_UNUSED, __m128 i6 ATTRIBUTE_UNUSED, __m128 i7 ATTRIBUTE_UNUSED, __m128 i8 ATTRIBUTE_UNUSED, __m128 i9 ATTRIBUTE_UNUSED, __m128 i10 ATTRIBUTE_UNUSED, __m128 i11 ATTRIBUTE_UNUSED, __m128 i12 ATTRIBUTE_UNUSED, __m128 i13 ATTRIBUTE_UNUSED, __m128 i14 ATTRIBUTE_UNUSED, __m128 i15 ATTRIBUTE_UNUSED, __m128 i16 ATTRIBUTE_UNUSED, __m128 i17 ATTRIBUTE_UNUSED, __m128 i18 ATTRIBUTE_UNUSED, __m128 i19 ATTRIBUTE_UNUSED)
+{
+  /* Check argument values.  */
+  compare (values.i0 , i0, __m128);
+  compare (values.i1 , i1, __m128);
+  compare (values.i2 , i2, __m128);
+  compare (values.i3 , i3, __m128);
+  compare (values.i4 , i4, __m128);
+  compare (values.i5 , i5, __m128);
+  compare (values.i6 , i6, __m128);
+  compare (values.i7 , i7, __m128);
+  compare (values.i8 , i8, __m128);
+  compare (values.i9 , i9, __m128);
+  compare (values.i10 , i10, __m128);
+  compare (values.i11 , i11, __m128);
+  compare (values.i12 , i12, __m128);
+  compare (values.i13 , i13, __m128);
+  compare (values.i14 , i14, __m128);
+  compare (values.i15 , i15, __m128);
+  compare (values.i16 , i16, __m128);
+  compare (values.i17 , i17, __m128);
+  compare (values.i18 , i18, __m128);
+  compare (values.i19 , i19, __m128);
+}
+
+void
+fun_check_passing_m128_20_regs (__m128 i0 ATTRIBUTE_UNUSED, __m128 i1 ATTRIBUTE_UNUSED, __m128 i2 ATTRIBUTE_UNUSED, __m128 i3 ATTRIBUTE_UNUSED, __m128 i4 ATTRIBUTE_UNUSED, __m128 i5 ATTRIBUTE_UNUSED, __m128 i6 ATTRIBUTE_UNUSED, __m128 i7 ATTRIBUTE_UNUSED, __m128 i8 ATTRIBUTE_UNUSED, __m128 i9 ATTRIBUTE_UNUSED, __m128 i10 ATTRIBUTE_UNUSED, __m128 i11 ATTRIBUTE_UNUSED, __m128 i12 ATTRIBUTE_UNUSED, __m128 i13 ATTRIBUTE_UNUSED, __m128 i14 ATTRIBUTE_UNUSED, __m128 i15 ATTRIBUTE_UNUSED, __m128 i16 ATTRIBUTE_UNUSED, __m128 i17 ATTRIBUTE_UNUSED, __m128 i18 ATTRIBUTE_UNUSED, __m128 i19 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m128_arguments;
+}
+
+
+#define def_check_int_passing8(_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _func1, _func2, TYPE) \
+  values.i0.TYPE[0] = _i0; \
+  values.i1.TYPE[0] = _i1; \
+  values.i2.TYPE[0] = _i2; \
+  values.i3.TYPE[0] = _i3; \
+  values.i4.TYPE[0] = _i4; \
+  values.i5.TYPE[0] = _i5; \
+  values.i6.TYPE[0] = _i6; \
+  values.i7.TYPE[0] = _i7; \
+  WRAP_CALL(_func1) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7); \
+  \
+  clear_float_registers; \
+  fregs.F0.TYPE[0] = _i0; \
+  fregs.F1.TYPE[0] = _i1; \
+  fregs.F2.TYPE[0] = _i2; \
+  fregs.F3.TYPE[0] = _i3; \
+  fregs.F4.TYPE[0] = _i4; \
+  fregs.F5.TYPE[0] = _i5; \
+  fregs.F6.TYPE[0] = _i6; \
+  fregs.F7.TYPE[0] = _i7; \
+  num_fregs = 8; \
+  WRAP_CALL(_func2) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7);
+
+#define def_check_int_passing20(_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9, _i10, _i11, _i12, _i13, _i14, _i15, _i16, _i17, _i18, _i19, _func1, _func2, TYPE) \
+  values.i0.TYPE[0] = _i0; \
+  values.i1.TYPE[0] = _i1; \
+  values.i2.TYPE[0] = _i2; \
+  values.i3.TYPE[0] = _i3; \
+  values.i4.TYPE[0] = _i4; \
+  values.i5.TYPE[0] = _i5; \
+  values.i6.TYPE[0] = _i6; \
+  values.i7.TYPE[0] = _i7; \
+  values.i8.TYPE[0] = _i8; \
+  values.i9.TYPE[0] = _i9; \
+  values.i10.TYPE[0] = _i10; \
+  values.i11.TYPE[0] = _i11; \
+  values.i12.TYPE[0] = _i12; \
+  values.i13.TYPE[0] = _i13; \
+  values.i14.TYPE[0] = _i14; \
+  values.i15.TYPE[0] = _i15; \
+  values.i16.TYPE[0] = _i16; \
+  values.i17.TYPE[0] = _i17; \
+  values.i18.TYPE[0] = _i18; \
+  values.i19.TYPE[0] = _i19; \
+  WRAP_CALL(_func1) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9, _i10, _i11, _i12, _i13, _i14, _i15, _i16, _i17, _i18, _i19); \
+  \
+  clear_float_registers; \
+  fregs.F0.TYPE[0] = _i0; \
+  fregs.F1.TYPE[0] = _i1; \
+  fregs.F2.TYPE[0] = _i2; \
+  fregs.F3.TYPE[0] = _i3; \
+  fregs.F4.TYPE[0] = _i4; \
+  fregs.F5.TYPE[0] = _i5; \
+  fregs.F6.TYPE[0] = _i6; \
+  fregs.F7.TYPE[0] = _i7; \
+  num_fregs = 8; \
+  WRAP_CALL(_func2) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9, _i10, _i11, _i12, _i13, _i14, _i15, _i16, _i17, _i18, _i19);
+
+void
+test_m64_on_stack ()
+{
+  __m64 x[8];
+  int i;
+  for (i = 0; i < 8; i++)
+    x[i] = (__m64){32+i, 0};
+  pass = "m64-8";
+  def_check_int_passing8(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], fun_check_passing_m64_8_values, fun_check_passing_m64_8_regs, _m64);
+}
+
+void
+test_too_many_m64 ()
+{
+  __m64 x[20];
+  int i;
+  for (i = 0; i < 20; i++)
+    x[i] = (__m64){32+i, 0};
+  pass = "m64-20";
+  def_check_int_passing20(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19], fun_check_passing_m64_20_values, fun_check_passing_m64_20_regs, _m64);
+}
+
+void
+test_m128_on_stack ()
+{
+  __m128 x[8];
+  int i;
+  for (i = 0; i < 8; i++)
+    x[i] = (__m128){32+i, 0, 0, 0};
+  pass = "m128-8";
+  def_check_int_passing8(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], fun_check_passing_m128_8_values, fun_check_passing_m128_8_regs, _m128);
+}
+
+void
+test_too_many_m128 ()
+{
+  __m128 x[20];
+  int i;
+  for (i = 0; i < 20; i++)
+    x[i] = (__m128){32+i, 0, 0, 0};
+  pass = "m128-20";
+  def_check_int_passing20(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19], fun_check_passing_m128_20_values, fun_check_passing_m128_20_regs, _m128);
+}
+
+int
+main (void)
+{
+  test_m64_on_stack ();
+  test_too_many_m64 ();
+  test_m128_on_stack ();
+  test_too_many_m128 ();
+  if (failed)
+    abort ();
+  return 0;
+}
Index: gcc/testsuite/gcc.target/x86_64/abi/test_m64m128_returning.c
===================================================================
--- gcc/testsuite/gcc.target/x86_64/abi/test_m64m128_returning.c	(revision 0)
+++ gcc/testsuite/gcc.target/x86_64/abi/test_m64m128_returning.c	(revision 5167)
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include "defines.h"
+#include "macros.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+unsigned int num_iregs, num_fregs;
+
+__m64
+fun_test_returning___m64 (void)
+{
+  volatile_var++;
+  return (__m64){72,0};
+}
+
+__m128
+fun_test_returning___m128 (void)
+{
+  volatile_var++;
+  return (__m128){73,0,0,0};
+}
+
+__m64 test_64;
+__m128 test_128;
+
+int
+main (void)
+{
+  unsigned failed = 0;
+  XMM_T xmmt1, xmmt2;
+
+  /* We jump through hoops to compare the results as gcc 3.3 does throw
+     an ICE when trying to generate a compare for a == b, when a and b
+     are of __m64 or __m128 type :-(  */
+  clear_struct_registers;
+  test_64 = (__m64){72,0};
+  xmmt1._m64[0] = test_64;
+  xmmt2._m64[0] = WRAP_RET (fun_test_returning___m64)();
+  if (xmmt1._long[0] != xmmt2._long[0]
+      || xmmt1._long[0] != xmm_regs[0]._long[0])
+    printf ("fail m64\n"), failed++;
+
+  clear_struct_registers;
+  test_128 = (__m128){73,0};
+  xmmt1._m128[0] = test_128;
+  xmmt2._m128[0] = WRAP_RET (fun_test_returning___m128)();
+  if (xmmt1._long[0] != xmmt2._long[0]
+      || xmmt1._long[0] != xmm_regs[0]._long[0])
+    printf ("fail m128\n"), failed++;
+  if (failed)
+    abort ();
+  return 0;
+}
Index: gcc/testsuite/gcc.target/x86_64/abi/defines.h
===================================================================
--- gcc/testsuite/gcc.target/x86_64/abi/defines.h	(revision 5120)
+++ gcc/testsuite/gcc.target/x86_64/abi/defines.h	(revision 5167)
@@ -1,6 +1,9 @@
 #ifndef DEFINED_DEFINES_H
 #define DEFINED_DEFINES_H
 
+/* Get __m64 and __m128. */
+#include <xmmintrin.h>
+
 typedef unsigned long ulong;
 typedef long double ldouble;
 
@@ -18,7 +21,7 @@ typedef long double ldouble;
 /* #define CHECK_FLOAT128 */
 
 /* Scalar types __m64 and __m128.  */
-/* #define CHECK_M64_M128 */
+#define CHECK_M64_M128
 
 /* Returning of complex type.  */
 #define CHECK_COMPLEX
Index: gcc/testsuite/gcc.target/x86_64/abi/test_passing_structs.c
===================================================================
--- gcc/testsuite/gcc.target/x86_64/abi/test_passing_structs.c	(revision 5120)
+++ gcc/testsuite/gcc.target/x86_64/abi/test_passing_structs.c	(revision 5167)
@@ -1,4 +1,4 @@
-/* This tests passing of structs. Only integers are tested.  */
+/* This tests passing of structs. */
 
 #include "defines.h"
 #include "args.h"
@@ -57,6 +57,33 @@ check_struct_passing4 (struct long3_stru
   assert ((unsigned long)&ls.l3 == rsp+24);
 }
 
+#ifdef CHECK_M64_M128
+struct m128_struct
+{
+  __m128 x;
+};
+
+struct m128_2_struct
+{
+  __m128 x1, x2;
+};
+
+/* Check that the struct is passed as the individual members in fregs.  */
+void
+check_struct_passing5 (struct m128_struct ms ATTRIBUTE_UNUSED)
+{
+  check_m128_arguments;
+}
+
+void
+check_struct_passing6 (struct m128_2_struct ms ATTRIBUTE_UNUSED)
+{
+  /* Check the passing on the stack by comparing the address of the
+     stack elements to the expected place on the stack.  */
+  assert ((unsigned long)&ms.x1 == rsp+8);
+  assert ((unsigned long)&ms.x2 == rsp+24);
+}
+#endif
 
 int
 main (void)
@@ -67,6 +94,13 @@ main (void)
   struct long2_struct l2s = { 50, 51 };
   struct long3_struct l3s = { 52, 53, 54 };
 #endif
+#ifdef CHECK_M64_M128
+  struct m128_struct m128s = { { 48.394, 39.3, -397.9, 3484.9 } };
+  struct m128_2_struct m128_2s = { 
+      { 48.394, 39.3, -397.9, 3484.9 },
+      { -8.394, -93.3, 7.9, 84.94 }
+  };
+#endif
 
   clear_struct_registers;
   iregs.I0 = is.i;
@@ -90,5 +124,14 @@ main (void)
   WRAP_CALL (check_struct_passing4)(l3s);
 #endif
 
+#ifdef CHECK_M64_M128
+  clear_struct_registers;
+  fregs.xmm0._m128[0] = m128s.x;
+  num_fregs = 1;
+  clear_float_hardware_registers;
+  WRAP_CALL (check_struct_passing5)(m128s);
+  WRAP_CALL (check_struct_passing6)(m128_2s);
+#endif
+
   return 0;
 }
Index: gcc/testsuite/ChangeLog.avx
===================================================================
Index: gcc/ChangeLog.avx
===================================================================
Index: gcc/config/i386/i386.h
===================================================================
--- gcc/config/i386/i386.h	(revision 5120)
+++ gcc/config/i386/i386.h	(revision 5167)
@@ -2430,6 +2430,8 @@ struct machine_function GTY(())
   /* This value is used for amd64 targets and specifies the current abi
      to be used. MS_ABI means ms abi. Otherwise SYSV_ABI means sysv abi.  */
   int call_abi;
+  /* 1 if we have warned about union ABI change.  */
+  int warned_union;
 };
 
 #define ix86_stack_locals (cfun->machine->stack_locals)
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 5120)
+++ gcc/config/i386/i386.c	(revision 5167)
@@ -5001,10 +5001,21 @@ classify_argument (enum machine_mode mod
 	      classes[i] = X86_64_SSE_CLASS;
 	    }
 
-	  /*  X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS.  */
+	  /*  If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
+	       everything should be passed in memory.  */
 	  if (classes[i] == X86_64_X87UP_CLASS
-	      && (i == 0 || classes[i - 1] != X86_64_X87_CLASS))
-	    classes[i] = X86_64_SSE_CLASS;
+	      && (classes[i - 1] != X86_64_X87_CLASS))
+	    {
+	      /* The first one should never be X86_64_X87UP_CLASS.  */
+	      gcc_assert (i != 0);
+	      if (!cfun->machine->warned_union)
+		{
+		  cfun->machine->warned_union = 1;
+		  warning (0, "The ABI of passing union with long double"
+			   " has changed");
+		}
+	      return 0;
+	    }
 	}
       return words;
     }


More information about the Gcc-patches mailing list