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]

Re: match constraints with different modes in big endian => reload ICE


On Feb 22, 2003, Alexandre Oliva <aoliva at redhat dot com> wrote:

> 	* reload.h (reload_adjust_reg_for_mode): Declare.

Oops, I noticed by chance that I'd missed this change in the patch
file I posted.  Here's the complete patch.  Ok to install?

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva at redhat dot com>

	* reload.c (reload_adjust_reg_for_mode): New function.
	(subst_reloads): Call it.
	(operands_match_p): Adjust registers using HARD_REGNO_NREGS.
	* reload.h (reload_adjust_reg_for_mode): Declare.
	* reload1.c (emit_input_reload_insns, emit_output_reload_insns):
	Call it.

Index: gcc/reload.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.c,v
retrieving revision 1.209
diff -u -p -r1.209 reload.c
--- gcc/reload.c 4 Feb 2003 22:47:23 -0000 1.209
+++ gcc/reload.c 22 Feb 2003 08:02:45 -0000
@@ -2137,10 +2137,10 @@ operands_match_p (x, y)
 	 (reg:SI 1) will be considered the same register.  */
       if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
 	  && i < FIRST_PSEUDO_REGISTER)
-	i += (GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD) - 1;
+	i += HARD_REGNO_NREGS (i, GET_MODE (x)) - 1;
       if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (y)) > UNITS_PER_WORD
 	  && j < FIRST_PSEUDO_REGISTER)
-	j += (GET_MODE_SIZE (GET_MODE (y)) / UNITS_PER_WORD) - 1;
+	j += HARD_REGNO_NREGS (j, GET_MODE (y)) - 1;
 
       return i == j;
     }
@@ -5954,7 +5954,7 @@ subst_reloads (insn)
 	     do the wrong thing if RELOADREG is multi-word.  RELOADREG
 	     will always be a REG here.  */
 	  if (GET_MODE (reloadreg) != r->mode && r->mode != VOIDmode)
-	    reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg));
+	    reloadreg = reload_adjust_reg_for_mode (reloadreg, r->mode);
 
 	  /* If we are putting this into a SUBREG and RELOADREG is a
 	     SUBREG, we would be making nested SUBREGs, so we have to fix
@@ -6932,6 +6932,26 @@ regno_clobbered_p (regno, insn, mode, se
     }
 
   return 0;
+}
+
+/* Find the low part, with mode MODE, of a hard regno RELOADREG.  */
+rtx
+reload_adjust_reg_for_mode (reloadreg, mode)
+     rtx reloadreg;
+     enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (reloadreg) == mode)
+    return reloadreg;
+
+  regno = REGNO (reloadreg);
+
+  if (WORDS_BIG_ENDIAN)
+    regno += HARD_REGNO_NREGS (regno, GET_MODE (reloadreg))
+      - HARD_REGNO_NREGS (regno, mode);
+
+  return gen_rtx_REG (mode, regno);
 }
 
 static const char *const reload_when_needed_name[] =
Index: gcc/reload.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.h,v
retrieving revision 1.42
diff -u -p -r1.42 reload.h
--- gcc/reload.h 17 Jan 2003 03:28:09 -0000 1.42
+++ gcc/reload.h 2 Mar 2003 11:45:03 -0000
@@ -1,6 +1,6 @@
 /* Communication between reload.c and reload1.c.
    Copyright (C) 1987, 1991, 1992, 1993, 1994, 1995, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -385,3 +385,7 @@ extern void cleanup_subreg_operands PARA
 /* Debugging support.  */
 extern void debug_reload_to_stream PARAMS ((FILE *));
 extern void debug_reload PARAMS ((void));
+
+/* Compute the actual register we should reload to, in case we're
+   reloading to/from a register that is wider than a word.  */
+extern rtx reload_adjust_reg_for_mode PARAMS ((rtx, enum machine_mode));
Index: gcc/reload1.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload1.c,v
retrieving revision 1.379
diff -u -p -r1.379 reload1.c
--- gcc/reload1.c 14 Feb 2003 22:23:48 -0000 1.379
+++ gcc/reload1.c 22 Feb 2003 08:02:52 -0000
@@ -6321,7 +6321,7 @@ emit_input_reload_insns (chain, rl, old,
      must always be a REG here.  */
 
   if (GET_MODE (reloadreg) != mode)
-    reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+    reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
   while (GET_CODE (oldequiv) == SUBREG && GET_MODE (oldequiv) != mode)
     oldequiv = SUBREG_REG (oldequiv);
   if (GET_MODE (oldequiv) != VOIDmode
@@ -6570,8 +6570,8 @@ emit_input_reload_insns (chain, rl, old,
 			oldequiv = old, real_oldequiv = real_old;
 		      else
 			second_reload_reg
-			  = gen_rtx_REG (new_mode,
-					 REGNO (second_reload_reg));
+			  = reload_adjust_reg_for_mode (second_reload_reg,
+							new_mode);
 		    }
 		}
 	    }
@@ -6693,7 +6693,7 @@ emit_output_reload_insns (chain, rl, j)
     }
 
   if (GET_MODE (reloadreg) != mode)
-    reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+    reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
 
 #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
 
@@ -6734,7 +6734,7 @@ emit_output_reload_insns (chain, rl, j)
 		= rld[secondary_reload].secondary_out_icode;
 
 	      if (GET_MODE (reloadreg) != mode)
-		reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+		reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
 
 	      if (tertiary_icode != CODE_FOR_nothing)
 		{
Index: gcc/testsuite/ChangeLog
from  Alexandre Oliva  <aoliva at redhat dot com>

	* gcc.c-torture/execute/20030222-1.c: New test.

Index: gcc/testsuite/gcc.c-torture/execute/20030222-1.c
===================================================================
RCS file: gcc/testsuite/gcc.c-torture/execute/20030222-1.c
diff -N gcc/testsuite/gcc.c-torture/execute/20030222-1.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.c-torture/execute/20030222-1.c 22 Feb 2003 08:03:00 -0000
@@ -0,0 +1,27 @@
+/* Verify that we get the low part of the long long as an int.  We
+   used to get it wrong on big-endian machines, if register allocation
+   succeeded at all.  We use volatile to make sure the long long is
+   actually truncated to int, in case a single register is wide enough
+   for a long long.  */
+
+#include <limits.h>
+
+void
+ll_to_int (long long x, volatile int *p)
+{
+  int i;
+  asm ("" : "=r" (i) : "0" (x));
+  *p = i;
+}
+
+int val = INT_MIN + 1;
+
+int main() {
+  volatile int i;
+
+  ll_to_int ((long long)val, &i);
+  if (i != val)
+    abort ();
+  
+  exit (0);
+}
-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                 aoliva at {redhat dot com, gcc.gnu.org}
CS PhD student at IC-Unicamp        oliva at {lsd dot ic dot unicamp dot br, gnu.org}
Free Software Evangelist                Professional serial bug killer

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