aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2017-12-11 22:36:07 +0000
committerAlexandre Oliva <aoliva@gcc.gnu.org>2017-12-11 22:36:07 +0000
commitb92977ee9fe46d0625d6c7a7fc63a9005753b892 (patch)
tree154fb2776aa4536d105f810a07b6ca6d166a3744
parent0a2c51498215e3e881b40bab388242390a8b4678 (diff)
downloadgcc-b92977ee9fe46d0625d6c7a7fc63a9005753b892.zip
gcc-b92977ee9fe46d0625d6c7a7fc63a9005753b892.tar.gz
gcc-b92977ee9fe46d0625d6c7a7fc63a9005753b892.tar.bz2
[PR80693] drop value of parallel SETs dropped by combine
When combine drops a REG_UNUSED SET in a parallel, we have to clear cached values, so that, even if the REGs remain used (e.g. because they were referenced in the used SET_SRC), we will not use properties of the dropped modified value as if they applied to the preserved original one. We fail to adjust REG_N_SETS. for gcc/ChangeLog PR rtl-optimization/80693 PR rtl-optimization/81019 PR rtl-optimization/81020 * combine.c (distribute_notes): Reset any REG_UNUSED REGs that are not mentioned in i3. Place the REG_UNUSED note on i2, possibly modified to REG_DEAD, if it did not originate in i3. for gcc/testsuite/ChangeLog PR rtl-optimization/80693 PR rtl-optimization/81019 PR rtl-optimization/81020 * gcc.dg/pr80693.c: New. * gcc.dg/pr81019.c: New. From-SVN: r255554
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/combine.c40
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.dg/pr80693.c26
-rw-r--r--gcc/testsuite/gcc.dg/pr81019.c27
5 files changed, 110 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index bd41af8..04fbd66 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2017-12-11 Alexandre Oliva <aoliva@redhat.com>
+
+ PR rtl-optimization/80693
+ PR rtl-optimization/81019
+ PR rtl-optimization/81020
+ * combine.c (distribute_notes): Reset any REG_UNUSED REGs that
+ are not mentioned in i3. Place the REG_UNUSED note on i2,
+ possibly modified to REG_DEAD, if it did not originate in i3.
+
2017-12-11 Jakub Jelinek <jakub@redhat.com>
* recog.c (store_data_bypass_p_1): New function.
diff --git a/gcc/combine.c b/gcc/combine.c
index 786a840..7f10c67 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -14219,6 +14219,46 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
PUT_REG_NOTE_KIND (note, REG_DEAD);
place = i3;
}
+
+ /* A SET or CLOBBER of the REG_UNUSED reg has been removed,
+ but we can't tell which at this point. We must reset any
+ expectations we had about the value that was previously
+ stored in the reg. ??? Ideally, we'd adjust REG_N_SETS
+ and, if appropriate, restore its previous value, but we
+ don't have enough information for that at this point. */
+ else
+ {
+ record_value_for_reg (XEXP (note, 0), NULL, NULL_RTX);
+
+ /* Otherwise, if this register is now referenced in i2
+ then the register used to be modified in one of the
+ original insns. If it was i3 (say, in an unused
+ parallel), it's now completely gone, so the note can
+ be discarded. But if it was modified in i2, i1 or i0
+ and we still reference it in i2, then we're
+ referencing the previous value, and since the
+ register was modified and REG_UNUSED, we know that
+ the previous value is now dead. So, if we only
+ reference the register in i2, we change the note to
+ REG_DEAD, to reflect the previous value. However, if
+ we're also setting or clobbering the register as
+ scratch, we know (because the register was not
+ referenced in i3) that it's unused, just as it was
+ unused before, and we place the note in i2. */
+ if (from_insn != i3 && i2 && INSN_P (i2)
+ && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
+ {
+ if (!reg_set_p (XEXP (note, 0), PATTERN (i2)))
+ PUT_REG_NOTE_KIND (note, REG_DEAD);
+ if (! (REG_P (XEXP (note, 0))
+ ? find_regno_note (i2, REG_NOTE_KIND (note),
+ REGNO (XEXP (note, 0)))
+ : find_reg_note (i2, REG_NOTE_KIND (note),
+ XEXP (note, 0))))
+ place = i2;
+ }
+ }
+
break;
case REG_EQUAL:
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3c2f0d2..5cdd493 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2017-12-11 Alexandre Oliva <aoliva@redhat.com>
+
+ PR rtl-optimization/80693
+ PR rtl-optimization/81019
+ PR rtl-optimization/81020
+ * gcc.dg/pr80693.c: New.
+ * gcc.dg/pr81019.c: New.
+
2017-12-11 Segher Boessenkool <segher@kernel.crashing.org>
PR rtl-optimization/83361
diff --git a/gcc/testsuite/gcc.dg/pr80693.c b/gcc/testsuite/gcc.dg/pr80693.c
new file mode 100644
index 0000000..5071771
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr80693.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options "-O -fno-tree-coalesce-vars" } */
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned u32;
+typedef unsigned long long u64;
+
+static u64 __attribute__((noinline, noclone))
+foo(u8 u8_0, u16 u16_0, u32 u32_0, u64 u64_0, u16 u16_1)
+{
+ u16_1 += 0x1051;
+ u16_1 &= 1;
+ u8_0 <<= u32_0 & 7;
+ u16_0 -= !u16_1;
+ u16_1 >>= ((u16)-u8_0 != 0xff);
+ return u8_0 + u16_0 + u64_0 + u16_1;
+}
+
+int
+main (void)
+{
+ u64 x = foo(1, 1, 0xffff, 0, 1);
+ if (x != 0x80)
+ __builtin_abort();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr81019.c b/gcc/testsuite/gcc.dg/pr81019.c
new file mode 100644
index 0000000..cf13bfa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr81019.c
@@ -0,0 +1,27 @@
+/* PR rtl-optimization/81019 */
+/* { dg-do run } */
+/* { dg-options "-O -fno-tree-ccp" } */
+
+unsigned long long __attribute__((noinline, noclone))
+foo (unsigned char a, unsigned short b, unsigned c, unsigned long long d,
+ unsigned char e, unsigned short f, unsigned g, unsigned long long h)
+{
+ g = e;
+ c &= 0 < d;
+ b *= d;
+ g ^= -1;
+ g &= 1;
+ c |= 1;
+ a -= 0 < g;
+ g >>= 1;
+ f = b | (f >> b);
+ return a + c + d + f + g + h;
+}
+
+int
+main (void)
+{
+ if (foo (0, 0, 0, 0, 0, 0, 0, 0) != 0x100)
+ __builtin_abort ();
+ return 0;
+}