On Wed, Jan 11, 2012 at 10:28:55AM +0100, Eric Botcazou wrote: > > IMHO reordering the notes in the chain would be even more work than this. > > Can't we just move down the lines > > 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; > } > > in emit_call_1 with a big comment explaining why the ECF_NORETURN note should > come first?
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. Anyway, here is an (untested) variant of the patch that puts the REG_NORETURN note in first in distribute_notes: 2012-01-11 Jakub Jelinek <ja...@redhat.com> PR bootstrap/51796 * combine.c (distribute_notes): If i3 is a noreturn call, allow old_size to be equal to args_size and make sure the noreturn call gets REG_ARGS_SIZE note. * expr.c (fixup_args_size_notes): Put REG_ARGS_SIZE notes on noreturn calls even when the delta is 0. --- gcc/combine.c.jj 2011-12-09 15:21:20.000000000 +0100 +++ gcc/combine.c 2012-01-11 09:37:40.199961939 +0100 @@ -13281,8 +13281,28 @@ distribute_notes (rtx notes, rtx from_in if (!noop_move_p (i3)) { int old_size, args_size = INTVAL (XEXP (note, 0)); + /* fixup_args_size_notes looks at REG_NORETURN note, + so ensure the note is placed there first. */ + if (CALL_P (i3)) + { + rtx *np; + for (np = &next_note; *np; np = &XEXP (*np, 1)) + if (REG_NOTE_KIND (*np) == REG_NORETURN) + { + rtx n = *np; + *np = XEXP (n, 1); + XEXP (n, 1) = REG_NOTES (i3); + REG_NOTES (i3) = n; + break; + } + } 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, allow that here. */ + gcc_assert (old_size != args_size + || (CALL_P (i3) + && !ACCUMULATE_OUTGOING_ARGS + && find_reg_note (i3, REG_NORETURN, NULL_RTX))); } break; --- gcc/expr.c.jj 2012-01-02 17:36:53.000000000 +0100 +++ gcc/expr.c 2012-01-11 09:30:08.549680295 +0100 @@ -3642,9 +3642,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 @@ -3789,7 +3791,12 @@ fixup_args_size_notes (rtx prev, rtx las this_delta = find_args_size_adjust (insn); if (this_delta == 0) - continue; + { + if (!CALL_P (insn) + || ACCUMULATE_OUTGOING_ARGS + || find_reg_note (insn, REG_NORETURN, NULL_RTX) == NULL_RTX) + continue; + } gcc_assert (!saw_unknown); if (this_delta == HOST_WIDE_INT_MIN) --- gcc/testsuite/gcc.dg/pr51796.c.jj 2012-01-10 16:43:00.494803970 +0100 +++ gcc/testsuite/gcc.dg/pr51796.c 2012-01-10 16:43:00.494803970 +0100 @@ -0,0 +1,15 @@ +/* PR bootstrap/51796 */ +/* { dg-do compile } */ +/* { dg-options "-Os -fno-omit-frame-pointer -fno-tree-dominator-opts -fno-tree-fre -fno-tree-pre" } */ + +typedef void (*entry_func) (void) __attribute__ ((noreturn)); +extern entry_func entry_addr; +static void bsd_boot_entry (void) +{ + stop (); +} +void bsd_boot (void) +{ + entry_addr = (entry_func) bsd_boot_entry; + (*entry_addr) (); +} Jakub