This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PR80693] drop value of parallel SETs dropped by combine
- From: Alexandre Oliva <aoliva at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 18 May 2017 07:25:57 -0300
- Subject: [PR80693] drop value of parallel SETs dropped by combine
- Authentication-results: sourceware.org; auth=none
- Authentication-results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com
- Authentication-results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=aoliva at redhat dot com
- Dkim-filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 4A08E81227
- Dmarc-filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 4A08E81227
When an insn used by combine has multiple SETs, only the non-REG_UNUSED
set is used: others will end up dropped on the floor. We have to take
note of the dropped REG_UNUSED SETs, clearing their 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 latest value
as if they applied to the earlier one.
Regstrapped on x86_64-linux-gnu. Ok to install?
for gcc/ChangeLog
PR rtl-optimization/80693
* combine.c (distribute_notes): Add IDEST parameter. Reset any
REG_UNUSED REGs that are not IDEST, if IDEST is given. Adjust
all callers.
for gcc/testsuite/ChangeLog
PR rtl-optimization/80693
* gcc.dg/pr80693.c: New.
---
gcc/combine.c | 80 ++++++++++++++++++++++++++--------------
gcc/testsuite/gcc.dg/pr80693.c | 26 +++++++++++++
2 files changed, 78 insertions(+), 28 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/pr80693.c
diff --git a/gcc/combine.c b/gcc/combine.c
index 39ef3c6..6954f92 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -483,7 +483,7 @@ static void reg_dead_at_p_1 (rtx, const_rtx, void *);
static int reg_dead_at_p (rtx, rtx_insn *);
static void move_deaths (rtx, rtx, int, rtx_insn *, rtx *);
static int reg_bitfield_target_p (rtx, rtx);
-static void distribute_notes (rtx, rtx_insn *, rtx_insn *, rtx_insn *, rtx, rtx, rtx);
+static void distribute_notes (rtx, rtx_insn *, rtx, rtx_insn *, rtx_insn *, rtx, rtx, rtx);
static void distribute_links (struct insn_link *);
static void mark_used_regs_combine (rtx);
static void record_promoted_value (rtx_insn *, rtx);
@@ -4170,7 +4170,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
remove_note (undobuf.other_insn, note);
}
- distribute_notes (new_other_notes, undobuf.other_insn,
+ distribute_notes (new_other_notes, undobuf.other_insn, NULL_RTX,
undobuf.other_insn, NULL, NULL_RTX, NULL_RTX,
NULL_RTX);
}
@@ -4424,19 +4424,19 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
/* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3. */
if (i3notes)
- distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL,
+ distribute_notes (i3notes, i3, NULL_RTX, i3, newi2pat ? i2 : NULL,
elim_i2, elim_i1, elim_i0);
if (i2notes)
- distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL,
+ distribute_notes (i2notes, i2, i2dest, i3, newi2pat ? i2 : NULL,
elim_i2, elim_i1, elim_i0);
if (i1notes)
- distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL,
+ distribute_notes (i1notes, i1, i1dest, i3, newi2pat ? i2 : NULL,
elim_i2, local_elim_i1, local_elim_i0);
if (i0notes)
- distribute_notes (i0notes, i0, i3, newi2pat ? i2 : NULL,
+ distribute_notes (i0notes, i0, i0dest, i3, newi2pat ? i2 : NULL,
elim_i2, elim_i1, local_elim_i0);
if (midnotes)
- distribute_notes (midnotes, NULL, i3, newi2pat ? i2 : NULL,
+ distribute_notes (midnotes, NULL, NULL_RTX, i3, newi2pat ? i2 : NULL,
elim_i2, elim_i1, elim_i0);
/* Distribute any notes added to I2 or I3 by recog_for_combine. We
@@ -4444,12 +4444,12 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
so we always pass it as i3. */
if (newi2pat && new_i2_notes)
- distribute_notes (new_i2_notes, i2, i2, NULL, NULL_RTX, NULL_RTX,
- NULL_RTX);
+ distribute_notes (new_i2_notes, i2, NULL_RTX, i2, NULL,
+ NULL_RTX, NULL_RTX, NULL_RTX);
if (new_i3_notes)
- distribute_notes (new_i3_notes, i3, i3, NULL, NULL_RTX, NULL_RTX,
- NULL_RTX);
+ distribute_notes (new_i3_notes, i3, NULL_RTX, i3, NULL,
+ NULL_RTX, NULL_RTX, NULL_RTX);
/* If I3DEST was used in I3SRC, it really died in I3. We may need to
put a REG_DEAD note for it somewhere. If NEWI2PAT exists and sets
@@ -4462,10 +4462,10 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
{
rtx new_note = alloc_reg_note (REG_DEAD, i3dest_killed, NULL_RTX);
if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
- distribute_notes (new_note, NULL, i2, NULL, elim_i2,
+ distribute_notes (new_note, NULL, NULL_RTX, i2, NULL, elim_i2,
elim_i1, elim_i0);
else
- distribute_notes (new_note, NULL, i3, newi2pat ? i2 : NULL,
+ distribute_notes (new_note, NULL, NULL_RTX, i3, newi2pat ? i2 : NULL,
elim_i2, elim_i1, elim_i0);
}
@@ -4473,10 +4473,10 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
{
rtx new_note = alloc_reg_note (REG_DEAD, i2dest, NULL_RTX);
if (newi2pat && reg_set_p (i2dest, newi2pat))
- distribute_notes (new_note, NULL, i2, NULL, NULL_RTX,
+ distribute_notes (new_note, NULL, NULL_RTX, i2, NULL, NULL_RTX,
NULL_RTX, NULL_RTX);
else
- distribute_notes (new_note, NULL, i3, newi2pat ? i2 : NULL,
+ distribute_notes (new_note, NULL, NULL_RTX, i3, newi2pat ? i2 : NULL,
NULL_RTX, NULL_RTX, NULL_RTX);
}
@@ -4484,10 +4484,10 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
{
rtx new_note = alloc_reg_note (REG_DEAD, i1dest, NULL_RTX);
if (newi2pat && reg_set_p (i1dest, newi2pat))
- distribute_notes (new_note, NULL, i2, NULL, NULL_RTX,
+ distribute_notes (new_note, NULL, NULL_RTX, i2, NULL, NULL_RTX,
NULL_RTX, NULL_RTX);
else
- distribute_notes (new_note, NULL, i3, newi2pat ? i2 : NULL,
+ distribute_notes (new_note, NULL, NULL_RTX, i3, newi2pat ? i2 : NULL,
NULL_RTX, NULL_RTX, NULL_RTX);
}
@@ -4495,10 +4495,10 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
{
rtx new_note = alloc_reg_note (REG_DEAD, i0dest, NULL_RTX);
if (newi2pat && reg_set_p (i0dest, newi2pat))
- distribute_notes (new_note, NULL, i2, NULL, NULL_RTX,
+ distribute_notes (new_note, NULL, NULL_RTX, i2, NULL, NULL_RTX,
NULL_RTX, NULL_RTX);
else
- distribute_notes (new_note, NULL, i3, newi2pat ? i2 : NULL,
+ distribute_notes (new_note, NULL, NULL_RTX, i3, newi2pat ? i2 : NULL,
NULL_RTX, NULL_RTX, NULL_RTX);
}
@@ -13938,9 +13938,11 @@ reg_bitfield_target_p (rtx x, rtx body)
return 0;
}
-/* Given a chain of REG_NOTES originally from FROM_INSN, try to place them
- as appropriate. I3 and I2 are the insns resulting from the combination
- insns including FROM (I2 may be zero).
+/* Given a chain of REG_NOTES originally from FROM_INSN, try to place
+ them as appropriate. IDEST is the dest in FROM_INSN used for
+ substitution (other dests in it are just dropped on the floor). I3
+ and I2 are the insns resulting from the combination insns including
+ FROM (I2 may be zero).
ELIM_I2 and ELIM_I1 are either zero or registers that we know will
not need REG_DEAD notes because they are being substituted for. This
@@ -13950,7 +13952,8 @@ reg_bitfield_target_p (rtx x, rtx body)
on the type of note. */
static void
-distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
+distribute_notes (rtx notes, rtx_insn *from_insn, rtx idest,
+ rtx_insn *i3, rtx_insn *i2,
rtx elim_i2, rtx elim_i1, rtx elim_i0)
{
rtx note, next_note;
@@ -14087,6 +14090,26 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
PUT_REG_NOTE_KIND (note, REG_DEAD);
place = i3;
}
+
+ /* If there were any parallel sets in FROM_INSN other than
+ the one setting IDEST, it must be REG_UNUSED, otherwise
+ we could not have used FROM_INSN in combine. Since this
+ combine attempt succeeded, we know this unused SET was
+ dropped on the floor, because the insn was either deleted
+ or created from a new pattern that does not use its
+ SET_DEST. We must forget whatever we knew about the
+ value that was stored by that SET, since the prior value
+ may still be present in IDEST's src expression or
+ elsewhere, and we do not want to use properties of the
+ dropped value as if they applied to the prior one when
+ simplifying e.g. subsequent combine attempts. */
+ if (idest && XEXP (note, 0) != idest)
+ {
+ gcc_assert (REG_P (XEXP (note, 0)));
+ record_value_for_reg (XEXP (note, 0), NULL, NULL_RTX);
+ INC_REG_N_SETS (REGNO (XEXP (note, 0)), -1);
+ }
+
break;
case REG_EQUAL:
@@ -14295,7 +14318,8 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
PATTERN (tem_insn) = pc_rtx;
REG_NOTES (tem_insn) = NULL;
- distribute_notes (old_notes, tem_insn, tem_insn, NULL,
+ distribute_notes (old_notes, tem_insn, NULL_RTX,
+ tem_insn, NULL,
NULL_RTX, NULL_RTX, NULL_RTX);
distribute_links (LOG_LINKS (tem_insn));
@@ -14316,7 +14340,7 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
REG_NOTES (cc0_setter) = NULL;
distribute_notes (old_notes, cc0_setter,
- cc0_setter, NULL,
+ NULL_RTX, cc0_setter, NULL,
NULL_RTX, NULL_RTX, NULL_RTX);
distribute_links (LOG_LINKS (cc0_setter));
@@ -14437,9 +14461,9 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
rtx new_note = alloc_reg_note (REG_DEAD, piece,
NULL_RTX);
- distribute_notes (new_note, place, place,
- NULL, NULL_RTX, NULL_RTX,
- NULL_RTX);
+ distribute_notes (new_note, place, NULL_RTX,
+ place, NULL, NULL_RTX,
+ NULL_RTX, NULL_RTX);
}
else if (! refers_to_regno_p (i, PATTERN (place))
&& ! find_regno_fusage (place, USE, i))
diff --git a/gcc/testsuite/gcc.dg/pr80693.c b/gcc/testsuite/gcc.dg/pr80693.c
new file mode 100644
index 0000000..aecddd0
--- /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 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;
+}
--
Alexandre Oliva, freedom fighter http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/ FSF Latin America board member
Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer