[PATCH] Fix ira.c indirect_jump_optimize (PR rtl-optimization/70460)

Jakub Jelinek jakub@redhat.com
Wed Mar 30 22:42:00 GMT 2016


Hi!

As mentioned in the PR, we are miscompiling glibc on i686-linux, because
the new indirect_jump_optimize mini-pass thinks that a insn
which has REG_LABEL_OPERAND note necessarily has to set the target register
to that label, while in the glibc case it is actually that label + some
offset, where the offset is read from a table which contains other labels -
this label differences.

The following patch changes it to just look at SET_SRC of single_set and/or
REG_EQUAL note, and only consider those if one of them is a LABEL_REF.
That alone broke lots of tests, which contain non-local gotos, so I had
to add a check that we don't do anything in this mini-pass (like old ira.c
code did) if there is REG_NON_LOCAL_GOTO note.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/5/4.9?
Bernd has preapproved the patch, but that was before the REG_NON_LOCAL_GOTO
changes.

2016-03-30  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/70460
	* ira.c (indirect_jump_optimize): Don't substitute LABEL_REF
	with operand from REG_LABEL_OPERAND, instead substitute
	SET_SRC or REG_EQUAL note content if it is a LABEL_REF.
	Don't do anything for REG_NON_LOCAL_GOTO jumps.

	* gcc.c-torture/execute/pr70460.c: New test.

--- gcc/ira.c.jj	2016-03-21 10:12:32.000000000 +0100
+++ gcc/ira.c	2016-03-30 19:06:42.883892088 +0200
@@ -3870,7 +3870,8 @@ indirect_jump_optimize (void)
   FOR_EACH_BB_REVERSE_FN (bb, cfun)
     {
       rtx_insn *insn = BB_END (bb);
-      if (!JUMP_P (insn))
+      if (!JUMP_P (insn)
+	  || find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
 	continue;
 
       rtx x = pc_set (insn);
@@ -3884,19 +3885,18 @@ indirect_jump_optimize (void)
 	  if (!DF_REF_IS_ARTIFICIAL (def))
 	    {
 	      rtx_insn *def_insn = DF_REF_INSN (def);
-	      rtx note = find_reg_note (def_insn, REG_LABEL_OPERAND, NULL_RTX);
-
-	      if (note)
+	      rtx lab = NULL_RTX;
+	      rtx set = single_set (def_insn);
+	      if (set && GET_CODE (SET_SRC (set)) == LABEL_REF)
+		lab = SET_SRC (set);
+	      else
 		{
-		  /* Substitute a LABEL_REF to the label given by the
-		     note rather than using SET_SRC of DEF_INSN.
-		     DEF_INSN might be loading the label constant from
-		     a constant pool, which isn't what we want in a
-		     direct branch.  */
-		  rtx lab = gen_rtx_LABEL_REF (Pmode, XEXP (note, 0));
-		  if (validate_replace_rtx (SET_SRC (x), lab, insn))
-		    rebuild_p = true;
+		  rtx eqnote = find_reg_note (def_insn, REG_EQUAL, NULL_RTX);
+		  if (eqnote && GET_CODE (XEXP (eqnote, 0)) == LABEL_REF)
+		    lab = XEXP (eqnote, 0);
 		}
+	      if (lab && validate_replace_rtx (SET_SRC (x), lab, insn))
+		rebuild_p = true;
 	    }
 	}
     }
--- gcc/testsuite/gcc.c-torture/execute/pr70460.c.jj	2016-03-30 19:08:39.295335567 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr70460.c	2016-03-30 19:08:18.000000000 +0200
@@ -0,0 +1,29 @@
+/* PR rtl-optimization/70460 */
+
+int c;
+
+__attribute__((noinline, noclone)) void
+foo (int x)
+{
+  static int b[] = { &&lab1 - &&lab0, &&lab2 - &&lab0 };
+  void *a = &&lab0 + b[x];
+  goto *a;
+lab1:
+  c += 2;
+lab2:
+  c++;
+lab0:
+  ;
+}
+
+int
+main ()
+{
+  foo (0);
+  if (c != 3)
+    __builtin_abort ();
+  foo (1);
+  if (c != 4)
+    __builtin_abort ();
+  return 0;
+}


	Jakub



More information about the Gcc-patches mailing list