This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PR80693] drop value of parallel SETs dropped by combine


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]