]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR rtl-optimization/60131 (RTL check fail in rhs_regno)
authorJeff Law <law@redhat.com>
Fri, 14 Feb 2014 20:26:31 +0000 (13:26 -0700)
committerJeff Law <law@gcc.gnu.org>
Fri, 14 Feb 2014 20:26:31 +0000 (13:26 -0700)
PR rtl-optimization/60131
* ree.c (get_extended_src_reg): New function.
(combine_reaching_defs): Use it rather than assuming location
of REG.
(find_and_remove_re): Verify first operand of extension is
a REG before adding the insns to the copy list.

PR rtl-optimization/60131
* g++.dg/torture/pr60131.C: New test.

From-SVN: r207792

gcc/ChangeLog
gcc/ree.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/torture/pr60131.C [new file with mode: 0644]

index dd988ce565d6bc5ae7e177ee6ba1e0fcea5d325b..59d1671f5ee6642b7002c4a59ffc6c75be192971 100644 (file)
@@ -1,3 +1,12 @@
+2014-02-14  Jeff Law  <law@redhat.com>
+
+       PR rtl-optimization/60131
+       * ree.c (get_extended_src_reg): New function.
+       (combine_reaching_defs): Use it rather than assuming location
+       of REG.
+       (find_and_remove_re): Verify first operand of extension is
+       a REG before adding the insns to the copy list.
+
 2014-02-14  Roland McGrath  <mcgrathr@google.com>
 
        * configure.ac (HAVE_AS_IX86_UD2): New test for 'ud2' mnemonic.
index 421eb6cb89b0c202e84974414e8a3aa20b238a45..fcde9a0f3993d5a16281ed9a058cd3a040bd3db5 100644 (file)
--- a/gcc/ree.c
+++ b/gcc/ree.c
@@ -670,6 +670,18 @@ merge_def_and_ext (ext_cand *cand, rtx def_insn, ext_state *state)
   return false;
 }
 
+/* Given SRC, which should be one or more extensions of a REG, strip
+   away the extensions and return the REG.  */
+
+static inline rtx
+get_extended_src_reg (rtx src)
+{
+  while (GET_CODE (src) == SIGN_EXTEND || GET_CODE (src) == ZERO_EXTEND)
+    src = XEXP (src, 0);
+  gcc_assert (REG_P (src));
+  return src;
+}
+
 /* This function goes through all reaching defs of the source
    of the candidate for elimination (CAND) and tries to combine
    the extension with the definition instruction.  The changes
@@ -698,17 +710,23 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
 
   /* If the destination operand of the extension is a different
      register than the source operand, then additional restrictions
-     are needed.  */
-  if ((REGNO (SET_DEST (PATTERN (cand->insn)))
-       != REGNO (XEXP (SET_SRC (PATTERN (cand->insn)), 0))))
+     are needed.  Note we have to handle cases where we have nested
+     extensions in the source operand.  */
+  if (REGNO (SET_DEST (PATTERN (cand->insn)))
+      != REGNO (get_extended_src_reg (SET_SRC (PATTERN (cand->insn)))))
     {
       /* In theory we could handle more than one reaching def, it
         just makes the code to update the insn stream more complex.  */
       if (state->defs_list.length () != 1)
        return false;
 
-      /* We require the candidate not already be modified.  This may
-        be overly conservative.  */
+      /* We require the candidate not already be modified.  It may,
+        for example have been changed from a (sign_extend (reg))
+        into (zero_extend (sign_extend (reg)).
+
+        Handling that case shouldn't be terribly difficult, but the code
+        here and the code to emit copies would need auditing.  Until
+        we see a need, this is the safe thing to do.  */
       if (state->modified[INSN_UID (cand->insn)].kind != EXT_MODIFIED_NONE)
        return false;
 
@@ -999,8 +1017,13 @@ find_and_remove_re (void)
           if (dump_file)
             fprintf (dump_file, "Eliminated the extension.\n");
           num_realized++;
-         if (REGNO (SET_DEST (PATTERN (curr_cand->insn)))
-             != REGNO (XEXP (SET_SRC (PATTERN (curr_cand->insn)), 0)))
+         /* If the RHS of the current candidate is not (extend (reg)), then
+            we do not allow the optimization of extensions where
+            the source and destination registers do not match.  Thus
+            checking REG_P here is correct.  */
+         if (REG_P (XEXP (SET_SRC (PATTERN (curr_cand->insn)), 0))
+             && (REGNO (SET_DEST (PATTERN (curr_cand->insn)))
+                 != REGNO (XEXP (SET_SRC (PATTERN (curr_cand->insn)), 0))))
            {
               reinsn_copy_list.safe_push (curr_cand->insn);
               reinsn_copy_list.safe_push (state.defs_list[0]);
index a8e72e2d2edad830f8b20fd7a11679d85ebe14b5..0415b74e08e74d4cd7254ee099cacabbe922a1b2 100644 (file)
@@ -1,3 +1,8 @@
+2014-02-14  Jeff Law  <law@redhat.com>
+
+       PR rtl-optimization/60131
+       * g++.dg/torture/pr60131.C: New test.
+
 2014-02-14  Ian Bolton  <ian.bolton@arm.com>
 
        * gcc.target/arm/pr59858.c: Skip if -mfloat-abi=hard specified
diff --git a/gcc/testsuite/g++.dg/torture/pr60131.C b/gcc/testsuite/g++.dg/torture/pr60131.C
new file mode 100644 (file)
index 0000000..23dde31
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-do compile }
+struct A { short a; };
+int **b;
+unsigned long c;
+
+bool foo ();
+unsigned bar (unsigned i);
+extern void baz () __attribute__((noreturn));
+
+int *
+test (unsigned x, struct A *y)
+{
+  unsigned v;
+  if (foo () || y[x].a == -1)
+    {
+      c = bar (x);
+      return 0;
+    }
+  v = y[x].a;
+  if (v >= 23)
+    baz ();
+  return b[v];
+}