diff --git a/gcc/combine.cc b/gcc/combine.cc index 53dcac92abc..9a34ef847aa 100644 --- a/gcc/combine.cc +++ b/gcc/combine.cc @@ -2569,6 +2569,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, rtx new_other_notes; int i; scalar_int_mode dest_mode, temp_mode; + bool has_non_call_exception = false; /* Immediately return if any of I0,I1,I2 are the same insn (I3 can never be). */ @@ -2951,6 +2952,32 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, return 0; } + /* With non-call exceptions we can end up trying to combine multiple + insns with possible EH side effects. Make sure we can combine + that to a single insn which means there must be at most one insn + in the combination with an EH side effect. */ + if (cfun->can_throw_non_call_exceptions) + { + if (find_reg_note (i3, REG_EH_REGION, NULL_RTX) + || find_reg_note (i2, REG_EH_REGION, NULL_RTX) + || (i1 && find_reg_note (i1, REG_EH_REGION, NULL_RTX)) + || (i0 && find_reg_note (i0, REG_EH_REGION, NULL_RTX))) + { + has_non_call_exception = true; + if (insn_could_throw_p (i3) + + insn_could_throw_p (i2) + + (i1 ? insn_could_throw_p (i1) : 0) + + (i0 ? insn_could_throw_p (i0) : 0) > 1) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Can't combine multiple insns with EH " + "side-effects\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); @@ -3685,7 +3712,13 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, || !modified_between_p (*split, i2, i3)) /* We can't overwrite I2DEST if its value is still used by NEWPAT. */ - && ! reg_referenced_p (i2dest, newpat)) + && ! reg_referenced_p (i2dest, newpat) + /* We should not split a possibly trapping part when we + care about non-call EH and have REG_EH_REGION notes + to distribute. */ + && ! (cfun->can_throw_non_call_exceptions + && has_non_call_exception + && may_trap_p (*split))) { rtx newdest = i2dest; enum rtx_code split_code = GET_CODE (*split); @@ -14175,23 +14208,35 @@ 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; + { + /* The landing pad handling needs to be kept in sync with the + prerequisite checking in try_combine. */ + int lp_nr = INTVAL (XEXP (note, 0)); + /* A REG_EH_REGION note transfering control can only ever come + from i3. */ + if (lp_nr > 0) + gcc_assert (from_insn == i3); + /* We are making sure there is a single effective REG_EH_REGION + note and it's valid to put it on i3. */ + if (!insn_could_throw_p (from_insn)) + /* Throw away stra notes on insns that can never throw. */ + ; + else + { + 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; + } + } + 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..00121fd8d1e --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr105231.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target lp64 } */ +/* { 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); +}