diff options
author | Alexandre Oliva <aoliva@redhat.com> | 2017-12-11 22:36:07 +0000 |
---|---|---|
committer | Alexandre Oliva <aoliva@gcc.gnu.org> | 2017-12-11 22:36:07 +0000 |
commit | b92977ee9fe46d0625d6c7a7fc63a9005753b892 (patch) | |
tree | 154fb2776aa4536d105f810a07b6ca6d166a3744 /gcc | |
parent | 0a2c51498215e3e881b40bab388242390a8b4678 (diff) | |
download | gcc-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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/combine.c | 40 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr80693.c | 26 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr81019.c | 27 |
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; +} |