This is the mail archive of the gcc-bugs@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]

[Bug rtl-optimization/18628] [4.0/4.1 regression] miscompilation of switch statement in loop


------- Additional Comments From aoliva at gcc dot gnu dot org  2005-03-10 20:38 -------
Subject: Re: [PR middle-end/18628] do not fold to label load from tablejump to reg

On Mar 10, 2005, Richard Henderson <rth@gcc.gnu.org> wrote:

> On Wed, Mar 09, 2005 at 07:26:37AM -0300, Alexandre Oliva wrote:
>> +		/* If it's not a REG, the REG_EQUAL note is inappropriate.  */
>> +		if (REG_P (SET_DEST (set)))
>> +		  set_unique_reg_note (insn, REG_EQUAL, label);

> I don't think this is a good idea at all.  This is just
> asking for reload to recreate a reference to the deleted label.

Here's a patch with that bit removed, along with the change in
cse_init that it required.  Ok?

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR middle-end/18628
	* cse.c (fold_rtx_mem): Don't fold a load from a jumptable into a
	register.

Index: gcc/cse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cse.c,v
retrieving revision 1.349
diff -u -p -r1.349 cse.c
--- gcc/cse.c 8 Mar 2005 13:56:56 -0000 1.349
+++ gcc/cse.c 10 Mar 2005 20:36:36 -0000
@@ -3515,8 +3515,30 @@ fold_rtx_mem (rtx x, rtx insn)
 	    if (offset >= 0
 		&& (offset / GET_MODE_SIZE (GET_MODE (table))
 		    < XVECLEN (table, 0)))
-	      return XVECEXP (table, 0,
-			      offset / GET_MODE_SIZE (GET_MODE (table)));
+	      {
+		rtx label = XVECEXP
+		  (table, 0, offset / GET_MODE_SIZE (GET_MODE (table)));
+		rtx set;
+
+		/* If we have an insn that loads the label from the
+		   jumptable into a reg, we don't want to set the reg
+		   to the label, because this may cause a reference to
+		   the label to remain after the label is removed in
+		   some very obscure cases (PR middle-end/18628).  */
+		if (!insn)
+		  return label;
+
+		set = single_set (insn);		
+
+		if (! set || SET_SRC (set) != x)
+		  return x;
+
+		/* If it's a jump, it's safe to reference the label.  */
+		if (SET_DEST (set) == pc_rtx)
+		  return label;
+
+		return x;
+	      }
 	  }
 	if (table_insn && JUMP_P (table_insn)
 	    && GET_CODE (PATTERN (table_insn)) == ADDR_DIFF_VEC)
Index: gcc/testsuite/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* gcc.dg/pr18628.c: New.

Index: gcc/testsuite/gcc.dg/pr18628.c
===================================================================
RCS file: gcc/testsuite/gcc.dg/pr18628.c
diff -N gcc/testsuite/gcc.dg/pr18628.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.dg/pr18628.c 10 Mar 2005 20:36:52 -0000
@@ -0,0 +1,31 @@
+/* { dg-do link } */
+/* { dg-options "-O2" } */
+
+/* PR middle-end/18628 exposed a problem in which cse folded a load
+   from a jump table into the label that was the target of the branch.
+   Unfortunately, the indirect jump was moved to a different basic
+   block, and the LABEL_REF copied to the register wasn't enough to
+   keep the cfg from optimizing the otherwise-unused label away.  So
+   we ended up with a dangling reference to the label.  */
+
+int i;
+
+int main()
+{
+  for (;;)
+  {
+    switch (i)
+    {
+      case 0:
+      case 1:
+        return 1;
+
+      case 2:
+      case 3:
+        return 0;
+
+      case 5:
+        --i;
+    }
+  }
+}

-- 
Alexandre Oliva             http://www.ic.unicamp.br/~oliva/
Red Hat Compiler Engineer   aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist  oliva@{lsd.ic.unicamp.br, gnu.org}


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18628


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