public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH][v3] rtl-optimization/105231 - distribute_notes and REG_EH_REGION
@ 2022-04-20 13:52 Richard Biener
  2022-04-20 15:43 ` Segher Boessenkool
  0 siblings, 1 reply; 5+ messages in thread
From: Richard Biener @ 2022-04-20 13:52 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, rth, ebotcazou

The following mitigates a problem in combine distribute_notes which
places an original REG_EH_REGION based on only may_trap_p which is
good to test whether a non-call insn can possibly throw but not if
actually it does or we care.  That's something we decided at RTL
expansion time where we possibly still know the insn evaluates
to a constant.

In fact, the REG_EH_REGION note with lp > 0 can only come from the
original i3 and an assert is added to that effect.  That means we only
need to retain the note on i3 or, if that cannot trap, drop it but we
should never move it to i2.

For REG_EH_REGION corresponding to must-not-throw regions or
nothrow marking try_combine gets new code ensuring we can merge
and distribute notes which means placing must-not-throw notes
on all result insns, and dropping nothrow notes or preserve
them on i3 for calls.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

WDYT?

Thanks,
Richard.

2022-04-19  Richard Biener  <rguenther@suse.de>

	PR rtl-optimization/105231
	* combine.cc (distribute_notes): Assert that a REG_EH_REGION
	with landing pad > 0 is from i3 and only keep it there or drop
	it if the insn can not trap.  Throw away REG_EH_REGION with
	landing pad = 0 or INT_MIN if it does not originate from a
	call i3.  Distribute must-not-throw REG_EH_REGION to all
	resulting instructions.
	(try_combine): Ensure that we can merge REG_EH_REGION notes.

	* gcc.dg/torture/pr105231.c: New testcase.
---
 gcc/combine.cc                          | 106 ++++++++++++++++++++----
 gcc/testsuite/gcc.dg/torture/pr105231.c |  15 ++++
 2 files changed, 104 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr105231.c

diff --git a/gcc/combine.cc b/gcc/combine.cc
index 53dcac92abc..ba234e3af5f 100644
--- a/gcc/combine.cc
+++ b/gcc/combine.cc
@@ -2951,6 +2951,45 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       return 0;
     }
 
+  /* When i3 transfers to an EH handler we cannot combine if any of the
+     sources are within a must-not-throw region.  Else we can throw away
+     any nothrow, pick a random must-not-throw region or preserve the EH
+     transfer on i3.  Since we want to preserve nothrow notes on calls
+     we have to avoid combining from must-not-throw stmts there as well.
+     This has to be kept in sync with distribute_note.  */
+  if (rtx i3_eh = find_reg_note (i3, REG_EH_REGION, NULL_RTX))
+    {
+      int i3_lp_nr = INTVAL (XEXP (i3_eh, 0));
+      if (i3_lp_nr > 0
+	  || ((i3_lp_nr == 0 || i3_lp_nr == INT_MIN) && CALL_P (i3)))
+	{
+	  rtx eh;
+	  int eh_lp;
+	  if (((eh = find_reg_note (i2, REG_EH_REGION, NULL_RTX))
+	       && (eh_lp = INTVAL (XEXP (eh, 0))) < 0
+	       && eh_lp != INT_MIN)
+	      || (i2
+		  && (eh = find_reg_note (i2, REG_EH_REGION, NULL_RTX))
+		  && (eh_lp = INTVAL (XEXP (eh, 0))) < 0
+		  && eh_lp != INT_MIN)
+	      || (i1
+		  && (eh = find_reg_note (i1, REG_EH_REGION, NULL_RTX))
+		  && (eh_lp = INTVAL (XEXP (eh, 0))) < 0
+		  && eh_lp != INT_MIN)
+	      || (i0
+		  && (eh = find_reg_note (i0, REG_EH_REGION, NULL_RTX))
+		  && (eh_lp = INTVAL (XEXP (eh, 0))) < 0
+		  && eh_lp != INT_MIN))
+	    {
+	      if (dump_file && (dump_flags & TDF_DETAILS))
+		fprintf (dump_file, "Can't combine insn in must-not-throw "
+			 "EH region into i3 which can throws\n");
+	      undo_all ();
+	      return 0;
+	    }
+	}
+    }
+
   /* Record whether i2 and i3 are trivial moves.  */
   i2_was_move = is_just_move (i2);
   i3_was_move = is_just_move (i3);
@@ -14175,23 +14214,56 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
 	  break;
 
 	case REG_EH_REGION:
-	  /* These notes must remain with the call or trapping instruction.  */
-	  if (CALL_P (i3))
-	    place = i3;
-	  else if (i2 && CALL_P (i2))
-	    place = i2;
-	  else
-	    {
-	      gcc_assert (cfun->can_throw_non_call_exceptions);
-	      if (may_trap_p (i3))
-		place = i3;
-	      else if (i2 && may_trap_p (i2))
-		place = i2;
-	      /* ??? Otherwise assume we've combined things such that we
-		 can now prove that the instructions can't trap.  Drop the
-		 note in this case.  */
-	    }
-	  break;
+	  {
+	    /* This handling needs to be kept in sync with the
+	       prerequesite checking in try_combine.  */
+	    int lp_nr = INTVAL (XEXP (note, 0));
+	    /* A REG_EH_REGION note transfering control can only ever come
+	       from i3 and it has to stay there.  */
+	    if (lp_nr > 0)
+	      {
+		gcc_assert (from_insn == i3);
+		if (CALL_P (i3))
+		  place = i3;
+		else
+		  {
+		    gcc_assert (cfun->can_throw_non_call_exceptions);
+		    /* If i3 can still trap preserve the note, otherwise we've
+		       combined things such that we can now prove that the
+		       instructions can't trap.  Drop the note in this case.  */
+		    if (may_trap_p (i3))
+		      place = i3;
+		  }
+	      }
+	    else if (lp_nr == 0 || lp_nr == INT_MIN)
+	      {
+		/* nothrow notes can be dropped but we preserve
+		   those on calls.  */
+		if (from_insn == i3 && CALL_P (i3))
+		  place = i3;
+	      }
+	    else
+	      {
+		/* Distribute must-not-throw notes to all resulting
+		   insns and just pick the first.  */
+		if (!find_reg_note (i3, REG_EH_REGION, NULL_RTX)
+		    && (CALL_P (i3)
+			|| (cfun->can_throw_non_call_exceptions
+			    && may_trap_p (i3))))
+		  place = i3;
+		if (i2
+		    && !find_reg_note (i2, REG_EH_REGION, NULL_RTX)
+		    && cfun->can_throw_non_call_exceptions
+		    && may_trap_p (i2))
+		  {
+		    if (place)
+		      place2 = i2;
+		    else
+		      place = i2;
+		  }
+	      }
+	    break;
+	  }
 
 	case REG_ARGS_SIZE:
 	  /* ??? How to distribute between i3-i1.  Assume i3 contains the
diff --git a/gcc/testsuite/gcc.dg/torture/pr105231.c b/gcc/testsuite/gcc.dg/torture/pr105231.c
new file mode 100644
index 00000000000..50459219c08
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr105231.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target int32plus } */
+/* { dg-require-effective-target dfp } */
+/* { dg-additional-options "-fsanitize-coverage=trace-pc -fnon-call-exceptions --param=max-cse-insns=1 -frounding-math" } */
+/* { dg-additional-options "-mstack-arg-probe" { target x86_64-*-* i?86-*-* } } */
+
+void baz (int *);
+void bar (double, double, _Decimal64);
+
+void
+foo (void)
+{
+  int s __attribute__((cleanup (baz)));
+  bar (0xfffffffffffffffe, 0xebf3fff2fbebaf7f, 0xffffffffffffff);
+}
-- 
2.34.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-04-21 10:53 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-20 13:52 [PATCH][v3] rtl-optimization/105231 - distribute_notes and REG_EH_REGION Richard Biener
2022-04-20 15:43 ` Segher Boessenkool
2022-04-21  7:55   ` Richard Biener
2022-04-21  9:43     ` Richard Biener
2022-04-21 10:53       ` Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).