aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernd Schmidt <bschmidt@redhat.com>2017-03-17 15:10:13 +0000
committerJeff Law <law@redhat.com>2017-03-17 15:10:13 +0000
commit0bfc1db772734a5daac2de3f8cbf80683d3fc77d (patch)
treeb6b93ff7ec850cd309e3de2969d25c1e8c288c69
parenta9e742df25f56b439e99b889f510637c28ea599d (diff)
PR rtl-optimization/79910
* combine.c (record_used_regs): New static function. (try_combine): Handle situations where there is an additional instruction between I2 and I3 which needs to have a LOG_LINK updated. PR rtl-optimization/79910 * gcc.dg/torture/pr79910.c: New test. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@246226 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/combine.c138
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr79910.c29
4 files changed, 180 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 71bebcf9fb3..f6caadb967f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2017-03-17 Bernd Schmidt <bschmidt@redhat.com>
+
+ PR rtl-optimization/79910
+ * combine.c (record_used_regs): New static function.
+ (try_combine): Handle situations where there is an additional
+ instruction between I2 and I3 which needs to have a LOG_LINK
+ updated.
+
2017-03-17 Jeff Law <law@redhat.com>
PR tree-optimization/71437
diff --git a/gcc/combine.c b/gcc/combine.c
index 66215a607bd..ff0df80a801 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -2559,6 +2559,57 @@ can_split_parallel_of_n_reg_sets (rtx_insn *insn, int n)
return true;
}
+/* Set up a set of registers used in an insn. Called through note_uses,
+ arguments as described for that function. */
+
+static void
+record_used_regs (rtx *xptr, void *data)
+{
+ bitmap set = (bitmap)data;
+ int i, j;
+ enum rtx_code code;
+ const char *fmt;
+ rtx x = *xptr;
+
+ /* repeat is used to turn tail-recursion into iteration since GCC
+ can't do it when there's no return value. */
+ repeat:
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+ if (REG_P (x))
+ {
+ unsigned regno = REGNO (x);
+ unsigned end_regno = END_REGNO (x);
+ while (regno < end_regno)
+ bitmap_set_bit (set, regno++);
+ return;
+ }
+
+ /* Recursively scan the operands of this expression. */
+
+ for (i = GET_RTX_LENGTH (code) - 1, fmt = GET_RTX_FORMAT (code); i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ /* If we are about to do the last recursive call
+ needed at this level, change it into iteration.
+ This function is called enough to be worth it. */
+ if (i == 0)
+ {
+ x = XEXP (x, 0);
+ goto repeat;
+ }
+
+ record_used_regs (&XEXP (x, i), data);
+ }
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ record_used_regs (&XVECEXP (x, i, j), data);
+ }
+}
+
/* Try to combine the insns I0, I1 and I2 into I3.
Here I0, I1 and I2 appear earlier than I3.
I0 and I1 can be zero; then we combine just I2 into I3, or I1 and I2 into
@@ -2742,6 +2793,27 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
added_links_insn = 0;
+ /* For combinations that may result in two insns, we have to gather
+ some extra information about registers used, so that we can
+ update all relevant LOG_LINKS later. */
+ auto_bitmap i2_regset, i3_regset, links_regset;
+ if (i1)
+ {
+ note_uses (&PATTERN (i2), record_used_regs, (bitmap)i2_regset);
+ note_uses (&PATTERN (i3), record_used_regs, (bitmap)i3_regset);
+ insn_link *ll;
+ FOR_EACH_LOG_LINK (ll, i3)
+ bitmap_set_bit (links_regset, ll->regno);
+ FOR_EACH_LOG_LINK (ll, i2)
+ bitmap_set_bit (links_regset, ll->regno);
+ if (i1)
+ FOR_EACH_LOG_LINK (ll, i1)
+ bitmap_set_bit (links_regset, ll->regno);
+ if (i0)
+ FOR_EACH_LOG_LINK (ll, i0)
+ bitmap_set_bit (links_regset, ll->regno);
+ }
+
/* First check for one important special case that the code below will
not handle. Namely, the case where I1 is zero, I2 is a PARALLEL
and I3 is a SET whose SET_SRC is a SET_DEST in I2. In that case,
@@ -4051,6 +4123,33 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
return 0;
}
+ auto_bitmap new_regs_in_i2;
+ if (newi2pat)
+ {
+ /* We need to discover situations where we introduce a use of a
+ register into I2, where none of the existing LOG_LINKS contain
+ a reference to it. This can happen if previously I3 referenced
+ the reg, and there is an additional use between I2 and I3. We
+ must remove the LOG_LINKS entry from that additional use and
+ distribute it along with our own ones. */
+ note_uses (&newi2pat, record_used_regs, (bitmap)new_regs_in_i2);
+ bitmap_and_compl_into (new_regs_in_i2, i2_regset);
+ bitmap_and_compl_into (new_regs_in_i2, links_regset);
+
+ /* Here, we first look for situations where a hard register use
+ moved, and just give up. This should happen approximately
+ never, and it's not worth it to deal with possibilities like
+ multi-word registers. Later, when fixing up LOG_LINKS, we
+ deal with the case where a pseudo use moved. */
+ if (!bitmap_empty_p (new_regs_in_i2)
+ && prev_nonnote_insn (i3) != i2
+ && bitmap_first_set_bit (new_regs_in_i2) < FIRST_PSEUDO_REGISTER)
+ {
+ undo_all ();
+ return 0;
+ }
+ }
+
if (MAY_HAVE_DEBUG_INSNS)
{
struct undo *undo;
@@ -4493,6 +4592,45 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
NULL_RTX, NULL_RTX, NULL_RTX);
}
+ if (newi2pat)
+ {
+ bitmap_iterator iter;
+ unsigned int i;
+
+ /* See comments above where we calculate the bitmap. */
+ EXECUTE_IF_SET_IN_BITMAP ((bitmap)new_regs_in_i2,
+ LAST_VIRTUAL_REGISTER, i, iter)
+ {
+ rtx reg = regno_reg_rtx[i];
+ rtx_insn *other;
+ for (other = NEXT_INSN (i2); other != i3; other = NEXT_INSN (other))
+ if (NONDEBUG_INSN_P (other)
+ && (reg_overlap_mentioned_p (reg, PATTERN (other))
+ || (CALL_P (other) && find_reg_fusage (other, USE, reg))))
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "found extra use of reg %d at insn %d\n", i,
+ INSN_UID (other));
+ insn_link **plink;
+ for (plink = &LOG_LINKS (other);
+ *plink;
+ plink = &(*plink)->next)
+ {
+ insn_link *link = *plink;
+ if (link->regno == i)
+ {
+ *plink = link->next;
+ link->next = i3links;
+ i3links = link;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
distribute_links (i3links);
distribute_links (i2links);
distribute_links (i1links);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ab4a49d5ffa..4162ca23eed 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2017-03-17 Bernd Schmidt <bschmidt@redhat.com>
+
+ PR rtl-optimization/79910
+ * gcc.dg/torture/pr79910.c: New test.
+
2017-03-17 Jeff Law <law@redhat.com>
PR tree-optimization/71437
diff --git a/gcc/testsuite/gcc.dg/torture/pr79910.c b/gcc/testsuite/gcc.dg/torture/pr79910.c
new file mode 100644
index 00000000000..5fe80aee144
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr79910.c
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+/* { dg-additional-options "-fweb" } */
+
+typedef unsigned char u8;
+typedef unsigned int u32;
+typedef unsigned long long u64;
+int a;
+
+static __attribute__ ((noinline, noclone)) u64
+foo (u8 p1, u32 p2)
+{
+ u64 b = a <= 0;
+ p2 = 4;
+ b >>= a == 0;
+ p1 %= 0xfffffffff;
+ p2 >>= b & 31;
+ p1 += b;
+ p2 <<= 31;
+ return p1 + p2 + b;
+}
+
+int
+main (void)
+{
+ u64 x = foo (0, 1);
+ if (x != 0)
+ __builtin_abort ();
+ return 0;
+}