This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[4.0] fix target/19010


Whee.  I am having just all sorts of fun with SSE this week.

For this PR, or rather another PR that sort of wandered off-topic
which I split off into its own, the ABI conformance bits in 
function_arg would request arguments in registers that the selected
hardware couldn't handle, leading to ICEs.

Which is not 100% true.  The hardware registers are available, in
the proper widths, but we're asking for modes for which the hardware
doesn't support any operation instructions.  There are two possible
solutions to this, (1) allow any mode of the proper width in the
registers, or (2) use a different mode for the argument.

Since (1) seems like lying to the compiler, and we know what that 
always leads to in the end, I chose (2).  So that's the change to
function_arg and gen_reg_or_parallel.  If the HARD_REGNO_MODE_OK is
false, we masquerade the argument in another mode.

I also discovered that the comment in the middle of VALID_SSE_REG_MODE
is false, that we don't need to lie and say that SSE2 modes are valid
for SSE1.  This has probably been true since the SSE2 bits were moved
from xmmintrin.h to emmintrin.h.  I had mistakenly thought that this
lie was to blame for the ICE.  I think, however, that returning 
inaccurate results from ix86_vector_mode_supported_p as we were means
that the vectorizer is or would potentially do the wrong thing on an
SSE1 only machine.

Finally, I discovered by inspection of the code generated from the
test case that some of our generic vector changes in 4.0 broke the
ABI for SSE1.  Thus the change to ix86_must_pass_in_stack.



r~


        * config/i386/i386.c (ix86_must_pass_in_stack): Don't return true
        for TImode vectors.
        (gen_reg_or_parallel): New.
        (function_arg): Use it.
        (ix86_hard_regno_mode_ok): Test SSE1 and SSE2 separately,
        MMX and 3DNOW separately.
        (ix86_rtx_costs): Simplify FLOAT_EXTEND case.
        (ix86_vector_mode_supported_p): Test SSE1 and SSE2 separately.
        * config/i386/i386.h (VALID_SSE2_REG_MODE): Move SSE2 cases from ...
        (VALID_SSE_REG_MODE): ... here.

        * gcc.target/i386/i386.exp: New harness.
        * gcc.target/i386/vect-args.c: New.

Index: gcc/config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.753
diff -u -p -r1.753 i386.c
--- gcc/config/i386/i386.c	14 Dec 2004 22:45:23 -0000	1.753
+++ gcc/config/i386/i386.c	15 Dec 2004 17:35:58 -0000
@@ -1943,7 +1943,12 @@ ix86_must_pass_in_stack (enum machine_mo
 {
   if (must_pass_in_stack_var_size_or_pad (mode, type))
     return true;
-  return (!TARGET_64BIT && type && mode == TImode);
+
+  /* For 32-bit, we want TImode aggregates to go on the stack.  But watch out!
+     The layout_type routine is crafty and tries to trick us into passing
+     currently unsupported vector types on the stack by using TImode.  */
+  return (!TARGET_64BIT && mode == TImode
+	  && type && TREE_CODE (type) != VECTOR_TYPE);
 }
 
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
@@ -2640,6 +2645,34 @@ function_arg_advance (CUMULATIVE_ARGS *c
   return;
 }
 
+/* A subroutine of function_arg.  We want to pass a parameter whose nominal
+   type is MODE in REGNO.  We try to minimize ABI variation, so MODE may not
+   actually be valid for REGNO with the current ISA.  In this case, ALT_MODE
+   is used instead.  It must be the same size as MODE, and must be known to
+   be valid for REGNO.  Finally, ORIG_MODE is the original mode of the 
+   parameter, as seen by the type system.  This may be different from MODE
+   when we're mucking with things minimizing ABI variations.
+
+   Returns a REG or a PARALLEL as appropriate.  */
+
+static rtx
+gen_reg_or_parallel (enum machine_mode mode, enum machine_mode alt_mode,
+		     enum machine_mode orig_mode, unsigned int regno)
+{
+  rtx tmp;
+
+  if (HARD_REGNO_MODE_OK (regno, mode))
+    tmp = gen_rtx_REG (mode, regno);
+  else
+    {
+      tmp = gen_rtx_REG (alt_mode, regno);
+      tmp = gen_rtx_EXPR_LIST (VOIDmode, tmp, const0_rtx);
+      tmp = gen_rtx_PARALLEL (orig_mode, gen_rtvec (1, tmp));
+    }
+
+  return tmp;
+}
+
 /* Define where to put the arguments to a function.
    Value is zero to push the argument on the stack,
    or a hard register in which to store the argument.
@@ -2654,12 +2687,11 @@ function_arg_advance (CUMULATIVE_ARGS *c
     (otherwise it is an extra parameter matching an ellipsis).  */
 
 rtx
-function_arg (CUMULATIVE_ARGS *cum,	/* current arg information */
-	      enum machine_mode mode,	/* current arg mode */
-	      tree type,	/* type of the argument or 0 if lib support */
-	      int named)	/* != 0 for normal args, == 0 for ...  args */
+function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode,
+	      tree type, int named)
 {
-  rtx ret   = NULL_RTX;
+  enum machine_mode mode = orig_mode;
+  rtx ret = NULL_RTX;
   int bytes =
     (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
   int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
@@ -2755,7 +2787,8 @@ function_arg (CUMULATIVE_ARGS *cum,	/* c
 			 "changes the ABI");
 	      }
 	    if (cum->sse_nregs)
-	      ret = gen_rtx_REG (mode, cum->sse_regno + FIRST_SSE_REG);
+	      ret = gen_reg_or_parallel (mode, TImode, orig_mode,
+					 cum->sse_regno + FIRST_SSE_REG);
 	  }
 	break;
       case V8QImode:
@@ -2771,7 +2804,8 @@ function_arg (CUMULATIVE_ARGS *cum,	/* c
 			 "changes the ABI");
 	      }
 	    if (cum->mmx_nregs)
-	      ret = gen_rtx_REG (mode, cum->mmx_regno + FIRST_MMX_REG);
+	      ret = gen_reg_or_parallel (mode, DImode, orig_mode,
+					 cum->mmx_regno + FIRST_MMX_REG);
 	  }
 	break;
       }
@@ -13991,10 +14025,20 @@ ix86_hard_regno_mode_ok (int regno, enum
   if (FP_REGNO_P (regno))
     return VALID_FP_MODE_P (mode);
   if (SSE_REGNO_P (regno))
-    return (TARGET_SSE ? VALID_SSE_REG_MODE (mode) : 0);
+    {
+      if (TARGET_SSE2 && VALID_SSE2_REG_MODE (mode))
+	return 1;
+      if (TARGET_SSE && VALID_SSE_REG_MODE (mode))
+	return 1;
+      return 0;
+    }
   if (MMX_REGNO_P (regno))
-    return (TARGET_MMX
-	    ? VALID_MMX_REG_MODE (mode) || VALID_MMX_REG_MODE_3DNOW (mode) : 0);
+    {
+      if (TARGET_3DNOW && VALID_MMX_REG_MODE_3DNOW (mode))
+	return 1;
+      if (TARGET_MMX && VALID_MMX_REG_MODE (mode))
+	return 1;
+    }
   /* We handle both integer and floats in the general purpose registers.
      In future we should be able to handle vector modes as well.  */
   if (!VALID_INT_MODE_P (mode) && !VALID_FP_MODE_P (mode))
@@ -14372,7 +14416,9 @@ ix86_rtx_costs (rtx x, int code, int out
       return false;
 
     case FLOAT_EXTEND:
-      if (!TARGET_SSE_MATH || !VALID_SSE_REG_MODE (mode))
+      if (!TARGET_SSE_MATH
+	  || mode == XFmode
+	  || (mode == DFmode && !TARGET_SSE2))
 	*total = 0;
       return false;
 
@@ -15164,20 +15210,15 @@ ix86_expand_vector_init (rtx target, rtx
 static bool
 ix86_vector_mode_supported_p (enum machine_mode mode)
 {
-  if (TARGET_SSE
-      && VALID_SSE_REG_MODE (mode))
+  if (TARGET_SSE && VALID_SSE_REG_MODE (mode))
     return true;
-
-  else if (TARGET_MMX
-	   && VALID_MMX_REG_MODE (mode))
+  if (TARGET_SSE2 && VALID_SSE2_REG_MODE (mode))
     return true;
-
-  else if (TARGET_3DNOW
-	   && VALID_MMX_REG_MODE_3DNOW (mode))
+  if (TARGET_MMX && VALID_MMX_REG_MODE (mode))
     return true;
-
-  else
-    return false;
+  if (TARGET_3DNOW && VALID_MMX_REG_MODE_3DNOW (mode))
+    return true;
+  return false;
 }
 
 /* Worker function for TARGET_MD_ASM_CLOBBERS.
Index: gcc/config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.h,v
retrieving revision 1.407
diff -u -p -r1.407 i386.h
--- gcc/config/i386/i386.h	14 Dec 2004 22:45:27 -0000	1.407
+++ gcc/config/i386/i386.h	15 Dec 2004 17:35:59 -0000
@@ -1075,14 +1075,12 @@ do {									\
 
 #define VALID_SSE2_REG_MODE(MODE) \
     ((MODE) == V16QImode || (MODE) == V8HImode || (MODE) == V2DFmode    \
-     || (MODE) == V2DImode)
+     || (MODE) == V2DImode || (MODE) == DFmode				\
+     || VALID_MMX_REG_MODE (MODE))
 
 #define VALID_SSE_REG_MODE(MODE)					\
     ((MODE) == TImode || (MODE) == V4SFmode || (MODE) == V4SImode	\
-     || (MODE) == SFmode || (MODE) == TFmode				\
-     /* Always accept SSE2 modes so that xmmintrin.h compiles.  */	\
-     || VALID_SSE2_REG_MODE (MODE)					\
-     || (TARGET_SSE2 && ((MODE) == DFmode || VALID_MMX_REG_MODE (MODE))))
+     || (MODE) == SFmode || (MODE) == TFmode)
 
 #define VALID_MMX_REG_MODE_3DNOW(MODE) \
     ((MODE) == V2SFmode || (MODE) == SFmode)
Index: gcc/testsuite/gcc.target/i386/i386.exp
===================================================================
RCS file: gcc/testsuite/gcc.target/i386/i386.exp
diff -N gcc/testsuite/gcc.target/i386/i386.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.target/i386/i386.exp	15 Dec 2004 17:35:59 -0000
@@ -0,0 +1,54 @@
+# Copyright (C) 1997, 2004 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Exit immediately if this isn't a SPARC target.
+if { ![istarget i?86*-*-*] && ![istarget x86_64-*-*] } then {
+  return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Special case compilation of vect-args.c so we don't have to
+# replicate it 10 times.
+foreach type { "" -mmmx -m3dnow -msse -msse2 } {
+  foreach level { "" -O } {
+    set flags "$type $level"
+    verbose -log "Testing vect-args, $flags" 1
+    dg-test $srcdir/$subdir/vect-args.c $flags ""
+  }
+}
+
+# Everything else.
+set tests [lsort [find $srcdir/$subdir *.\[cS\]]]
+set tests [prune $tests $srcdir/$subdir/vect-args.c]
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
Index: gcc/testsuite/gcc.target/i386/vect-args.c
===================================================================
RCS file: gcc/testsuite/gcc.target/i386/vect-args.c
diff -N gcc/testsuite/gcc.target/i386/vect-args.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.target/i386/vect-args.c	15 Dec 2004 17:35:59 -0000
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-w" } */
+
+/* SSE1 and SSE2 modes.  */
+typedef unsigned char V16QImode __attribute__((vector_size(16)));
+typedef unsigned short V8HImode __attribute__((vector_size(16)));
+typedef unsigned int V4SImode __attribute__((vector_size(16)));
+typedef unsigned long long V2DImode __attribute__((vector_size(16)));
+typedef float V4SFmode __attribute__((vector_size(16)));
+typedef double V2DFmode __attribute__((vector_size(16)));
+
+/* MMX and 3DNOW modes.  */
+typedef unsigned char V8QImode __attribute__((vector_size(8)));
+typedef unsigned short V4HImode __attribute__((vector_size(8)));
+typedef unsigned int V2SImode __attribute__((vector_size(8)));
+typedef float V2SFmode __attribute__((vector_size(8)));
+
+/* Test argument loading and unloading of each.  */
+#define TEST(TYPE)					\
+extern TYPE data_##TYPE;				\
+void r_##TYPE (TYPE x) { data_##TYPE = x; }		\
+void s_##TYPE (void) { r_##TYPE (data_##TYPE); }
+
+TEST(V16QImode)
+TEST(V8HImode)
+TEST(V4SImode)
+TEST(V2DImode)
+TEST(V4SFmode)
+TEST(V2DFmode)
+TEST(V8QImode)
+TEST(V4HImode)
+TEST(V2SImode)
+TEST(V2SFmode)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]