Hi!

As shown on the testcase below, if REE modifies some sign/zero extension
insn, which is on the candidate vector, as a def_insn of some other
extension, before combine_reaching_defs is called on that insn, we might
ignore the changes done to that insn and just assume it is only an
extension to the recorded mode.  It might be an extension to a wider mode
though.

Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux,
ok for trunk/4.7?

2012-04-30  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/53160
        * ree.c (combine_reaching_defs): Handle the case where cand->insn
        has been modified by ree pass already.

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

--- gcc/ree.c.jj        2012-01-31 11:04:34.000000000 +0100
+++ gcc/ree.c   2012-04-30 11:24:02.682520157 +0200
@@ -667,6 +667,24 @@ combine_reaching_defs (ext_cand *cand, c
   if (!outcome)
     return false;
 
+  /* If cand->insn has been already modified, update cand->mode to a wider
+     mode if possible, or punt.  */
+  if (state->modified[INSN_UID (cand->insn)].kind != EXT_MODIFIED_NONE)
+    {
+      enum machine_mode mode;
+      rtx set;
+
+      if (state->modified[INSN_UID (cand->insn)].kind
+         != (cand->code == ZERO_EXTEND
+             ? EXT_MODIFIED_ZEXT : EXT_MODIFIED_SEXT)
+         || state->modified[INSN_UID (cand->insn)].mode != cand->mode
+         || (set = single_set (cand->insn)) == NULL_RTX)
+       return false;
+      mode = GET_MODE (SET_DEST (set));
+      gcc_assert (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (cand->mode));
+      cand->mode = mode;
+    }
+
   merge_successful = true;
 
   /* Go through the defs vector and try to merge all the definitions
--- gcc/testsuite/gcc.c-torture/execute/pr53160.c.jj    2012-04-30 
11:34:33.807798084 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr53160.c       2012-04-30 
11:34:18.000000000 +0200
@@ -0,0 +1,35 @@
+/* PR rtl-optimization/53160 */
+
+extern void abort (void);
+
+int a, c = 1, d, e, g;
+volatile int b;
+volatile char f;
+long h;
+short i;
+
+void
+foo (void)
+{
+  for (e = 0; e; ++e)
+    ;
+}
+
+int
+main ()
+{
+  if (g)
+    (void) b;
+  foo ();
+  for (d = 0; d >= 0; d--)
+    {
+      short j = f;
+      int k = 0;
+      i = j ? j : j << k;
+    }
+  h = c == 0 ? 0 : i;
+  a = h;
+  if (a != 0)
+    abort ();
+  return 0;
+}

        Jakub

Reply via email to