This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Fix ICE in distribute_notes (PR bootstrap/51796)
> I'd find that very fragile. E.g. distribute_notes itself reverses the
> order of all notes, and for no REG_NOTES I think we rely on any ordering.
AFAIK distribute_notes is the only routine that redistributes the RTL notes for
a fixed insn, so I'm a little skeptical about the purported fragility here.
My point is that the complexity should be in fixup_args_size_notes instead of
distribute_notes. Tentative patch attached.
PR bootstrap/51796
* calls.c (emit_call_1): Make sure REG_NORETURN note comes first.
* combine.c (distribute_notes): If i3 is a noreturn call, allow
old_size to be equal to args_size if !ACCUMULATE_OUTGOING_ARGS.
* expr.c (fixup_args_size_notes): Put REG_ARGS_SIZE notes on
noreturn calls even when the delta is 0.
* rtlanal.c (find_and_remove_reg_note): New function.
* rtl.h (find_and_remove_reg_note): Declare it.
--
Eric Botcazou
Index: calls.c
===================================================================
--- calls.c (revision 183092)
+++ calls.c (working copy)
@@ -413,15 +413,6 @@ emit_call_1 (rtx funexp, tree fntree ATT
/* Create a nothrow REG_EH_REGION note, if needed. */
make_reg_eh_region_note (call_insn, ecf_flags, 0);
- if (ecf_flags & ECF_NORETURN)
- add_reg_note (call_insn, REG_NORETURN, const0_rtx);
-
- if (ecf_flags & ECF_RETURNS_TWICE)
- {
- add_reg_note (call_insn, REG_SETJMP, const0_rtx);
- cfun->calls_setjmp = 1;
- }
-
SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0);
/* Restore this now, so that we do defer pops for this call's args
@@ -451,6 +442,17 @@ emit_call_1 (rtx funexp, tree fntree ATT
else if (!ACCUMULATE_OUTGOING_ARGS && (ecf_flags & ECF_NORETURN) != 0)
add_reg_note (call_insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
+ if (ecf_flags & ECF_RETURNS_TWICE)
+ {
+ add_reg_note (call_insn, REG_SETJMP, const0_rtx);
+ cfun->calls_setjmp = 1;
+ }
+
+ /* The REG_NORETURN note must come before the REG_ARGS_SIZE note for the
+ fixup_args_size_notes machinery to work correctly. */
+ if (ecf_flags & ECF_NORETURN)
+ add_reg_note (call_insn, REG_NORETURN, const0_rtx);
+
if (!ACCUMULATE_OUTGOING_ARGS)
{
/* If returning from the subroutine does not automatically pop the args,
Index: combine.c
===================================================================
--- combine.c (revision 182780)
+++ combine.c (working copy)
@@ -13282,7 +13282,13 @@ distribute_notes (rtx notes, rtx from_in
{
int old_size, args_size = INTVAL (XEXP (note, 0));
old_size = fixup_args_size_notes (PREV_INSN (i3), i3, args_size);
- gcc_assert (old_size != args_size);
+ /* emit_call_1 adds for !ACCUMULATE_OUTGOING_ARGS REG_ARGS_SIZE
+ note to all noreturn calls, but fixup_args_size_notes cannot
+ recompute the amount on its own, so the size is unchanged. */
+ gcc_assert (old_size != args_size
+ || (CALL_P (i3)
+ && !ACCUMULATE_OUTGOING_ARGS
+ && find_reg_note (i3, REG_NORETURN, NULL_RTX)));
}
break;
Index: expr.c
===================================================================
--- expr.c (revision 182780)
+++ expr.c (working copy)
@@ -3645,9 +3645,11 @@ mem_autoinc_base (rtx mem)
(1) One or more auto-inc style memory references (aka pushes),
(2) One or more addition/subtraction with the SP as destination,
(3) A single move insn with the SP as destination,
- (4) A call_pop insn.
+ (4) A call_pop insn,
+ (5) Noreturn call insns if !ACCUMULATE_OUTGOING_ARGS.
- Insns in the sequence that do not modify the SP are ignored.
+ Insns in the sequence that do not modify the SP are ignored,
+ except for noreturn calls.
The return value is the amount of adjustment that can be trivially
verified, via immediate operand or auto-inc. If the adjustment
@@ -3786,23 +3788,42 @@ fixup_args_size_notes (rtx prev, rtx las
for (insn = last; insn != prev; insn = PREV_INSN (insn))
{
HOST_WIDE_INT this_delta;
+ rtx note = NULL_RTX;
if (!NONDEBUG_INSN_P (insn))
continue;
this_delta = find_args_size_adjust (insn);
if (this_delta == 0)
- continue;
+ {
+ /* In the noreturn call case, we need to maintain the invariant
+ that the REG_NORETURN comes first. So remove it here... */
+ if (!CALL_P (insn)
+ || ACCUMULATE_OUTGOING_ARGS
+ || (note = find_and_remove_reg_note
+ (insn, REG_NORETURN, NULL_RTX)) == NULL_RTX)
+ continue;
+ }
gcc_assert (!saw_unknown);
if (this_delta == HOST_WIDE_INT_MIN)
saw_unknown = true;
add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (args_size));
+
+ if (this_delta == 0)
+ {
+ /* ...and add it back here. */
+ XEXP (note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = note;
+ }
+ else
+ {
#ifdef STACK_GROWS_DOWNWARD
- this_delta = -this_delta;
+ this_delta = -this_delta;
#endif
- args_size -= this_delta;
+ args_size -= this_delta;
+ }
}
return saw_unknown ? INT_MIN : args_size;
Index: rtlanal.c
===================================================================
--- rtlanal.c (revision 182780)
+++ rtlanal.c (working copy)
@@ -1752,6 +1752,17 @@ find_reg_note (const_rtx insn, enum reg_
return 0;
}
+/* Likewise, but additionally remove the note. */
+
+rtx
+find_and_remove_reg_note (rtx insn, enum reg_note kind, const_rtx datum)
+{
+ rtx note = find_reg_note (insn, kind, datum);
+ if (note)
+ remove_note (insn, note);
+ return note;
+}
+
/* Return the reg-note of kind KIND in insn INSN which applies to register
number REGNO, if any. Return 0 if there is no such reg-note. Note that
the REGNO of this NOTE need not be REGNO if REGNO is a hard register;
Index: rtl.h
===================================================================
--- rtl.h (revision 182780)
+++ rtl.h (working copy)
@@ -1951,6 +1951,7 @@ extern void note_uses (rtx *, void (*) (
extern int dead_or_set_p (const_rtx, const_rtx);
extern int dead_or_set_regno_p (const_rtx, unsigned int);
extern rtx find_reg_note (const_rtx, enum reg_note, const_rtx);
+extern rtx find_and_remove_reg_note (rtx, enum reg_note, const_rtx);
extern rtx find_regno_note (const_rtx, enum reg_note, unsigned int);
extern rtx find_reg_equal_equiv_note (const_rtx);
extern rtx find_constant_src (const_rtx);