expand: drop stack adjustments after barrier [PR118006]

A gimple block with __builtin_unreachable () can't have code after it,
and gimple optimizers ensure there isn't any, even without
optimization.  But if the block requires stack adjustments,
e.g. because of a call that passes arguments on the stack, expand will
emit that after the barrier, and then rtl checkers rightfully
complain.  Arrange to discard adjustments after a barrier.

Strub expanders seem to be necessary to bring about the exact
conditions that require stack adjustments after the block that ends
with a __builtin_unreachable call.


for  gcc/ChangeLog

	PR middle-end/118006
	* cfgexpand.cc (expand_gimple_basic_block): Do not emit
	pending stack adjustments after a barrier.

for  gcc/testsuite/ChangeLog

	PR middle-end/118006
	* gcc.target/i386/strub-pr118006.c: New.
This commit is contained in:
Alexandre Oliva 2024-12-20 18:02:08 -03:00 committed by Alexandre Oliva
parent 6069f02a48
commit 1b1a33f768
2 changed files with 28 additions and 1 deletions

View File

@ -6216,7 +6216,17 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
emit_insn_after_noloc (gen_move_insn (dummy, dummy), last, NULL);
}
do_pending_stack_adjust ();
/* A __builtin_unreachable () will insert a barrier that should end
the basic block. In gimple, any code after it will have already
deleted, even without optimization. If we emit additional code
here, as we would to adjust the stack after a call, it should be
eventually deleted, but it confuses internal checkers (PR118006)
and optimizers before it does, because we don't expect to find
barriers inside basic blocks. */
if (!BARRIER_P (get_last_insn ()))
do_pending_stack_adjust ();
else
discard_pending_stack_adjust ();
/* Find the block tail. The last insn in the block is the insn
before a barrier and/or table jump insn. */

View File

@ -0,0 +1,17 @@
/* { dg-require-effective-target strub } */
/* { dg-do compile } */
/* { dg-options "-fstrub=all -O2 -m32 -mno-accumulate-outgoing-args" } */
__attribute__((noipa))
long _raw_syscall(void *, long, long) {
__builtin_abort();
}
static int privileged_traced_syscall() {
return _raw_syscall(0, 0, 0);
}
void privileged_traced_raise() {
privileged_traced_syscall();
__builtin_unreachable ();
}