On Thu, 8 Oct 2026, Richard Biener wrote:
> Hmm, I think this issue might be more wide-spread and using arbitrary
> RTL APIs during RTL expansion is now dangerous. That said,
> mips16_gp_pseudo_reg should probably not do this, since try-expansion
> and throw away is expected to leave no trail.
>
> How do we get there?

Hi Richard,

this is my first submission to GCC, so please excuse me if I get
something wrong. After reading through the code myself and discussing
it with Claude, my understanding is that we get there from a call
during expansion:

expand_call -> mips_expand_call -> mips_load_call_address
-> mips_got_load -> mips_pic_base_register -> mips16_gp_pseudo_reg

mips16_gp_pseudo_reg does push_topmost_sequence, walks get_insns() to
the first real insn and emits the $gp load after it. In the testcase
that is the basic block note of bb 2, which is already expanded but
not BB_RTL yet.

I agree with your hint that this is better fixed in mips.cc. The load
could be put on the entry edge instead:

start_sequence ();
... emit the $gp load and the clobbers ...
insert_insn_on_edge (end_sequence (),
single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));

pass_expand commits edge insertions after all blocks are expanded, so
nothing is emitted into the insn stream during expansion.

Should I send a v2 like that instead of the emit-rtl.cc change?

Julius

On Thu, Oct 08, 2026 08:42 AM, Richard Biener <[email protected]> wrote:
>
> On Wed, 7 Oct 2026, Julius Bairaktaris wrote:
>
> > Since r16-1398, expanded blocks stay non-BB_RTL until the end of
> > expansion, but BLOCK_FOR_INSN of their insns is already set.
> > mips16_gp_pseudo_reg emits the $gp load after the basic block note of
> > such a block, and add_insn_after then crashes on BB_END.  Only touch
> > BB_END and BB_HEAD of BB_RTL blocks; pass_expand::execute sets them
> > for the others from head_end_for_bb.
>
> Hmm, I think this issue might be more wide-spread and using arbitrary
> RTL APIs during RTL expansion is now dangerous.  That said,
> mips16_gp_pseudo_reg should probably not do this, since try-expansion
> and throw away is expected to leave no trail.
>
> How do we get there?
>
> > Assisted-by: Claude:claude-opus-5-5
> >
> >       PR target/125582
> >
> > gcc/ChangeLog:
> >
> >       * emit-rtl.cc (add_insn_after): Only update BB_END for BB_RTL
> >       blocks.
> >       (add_insn_before): Only check BB_HEAD for BB_RTL blocks.
> >
> > gcc/testsuite/ChangeLog:
> >
> >       * gcc.target/mips/pr125582.c: New test.
> >
> > Signed-off-by: Julius Bairaktaris <[email protected]>
> > ---
> > Bootstrapped and regtested on x86_64-pc-linux-gnu with no new failures.
> > gcc.target/mips/mips.exp on a mipsel-linux-musl cross compiler shows no
> > changes except the new test, which ICEs at -O1 and above without the
> > patch.
> >
> >  gcc/emit-rtl.cc                          |  9 ++++++---
> >  gcc/testsuite/gcc.target/mips/pr125582.c | 25 ++++++++++++++++++++++++
> >  2 files changed, 31 insertions(+), 3 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.target/mips/pr125582.c
> >
> > diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
> > index d064b2a1064..06294604573 100644
> > --- a/gcc/emit-rtl.cc
> > +++ b/gcc/emit-rtl.cc
> > @@ -4373,8 +4373,10 @@ add_insn_after (rtx_insn *insn, rtx_insn *after, 
> > basic_block bb)
> >        if (INSN_P (insn))
> >       df_insn_rescan (insn);
> >        /* Should not happen as first in the BB is always
> > -      either NOTE or LABEL.  */
> > -      if (BB_END (bb) == after
> > +      either NOTE or LABEL.  Blocks expanded but not yet BB_RTL
> > +      have no BB_END.  */
> > +      if ((bb->flags & BB_RTL)
> > +       && BB_END (bb) == after
> >         /* Avoid clobbering of structure when creating new BB.  */
> >         && !BARRIER_P (insn)
> >         && !NOTE_INSN_BASIC_BLOCK_P (insn))
> > @@ -4408,7 +4410,8 @@ add_insn_before (rtx_insn *insn, rtx_insn *before, 
> > basic_block bb)
> >       df_insn_rescan (insn);
> >        /* Should not happen as first in the BB is always either NOTE or
> >        LABEL.  */
> > -      gcc_assert (BB_HEAD (bb) != insn
> > +      gcc_assert (!(bb->flags & BB_RTL)
> > +               || BB_HEAD (bb) != insn
> >                 /* Avoid clobbering of structure when creating new BB.  */
> >                 || BARRIER_P (insn)
> >                 || NOTE_INSN_BASIC_BLOCK_P (insn));
> > diff --git a/gcc/testsuite/gcc.target/mips/pr125582.c 
> > b/gcc/testsuite/gcc.target/mips/pr125582.c
> > new file mode 100644
> > index 00000000000..524ef4bdf4d
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/mips/pr125582.c
> > @@ -0,0 +1,25 @@
> > +/* PR target/125582 */
> > +/* { dg-do compile } */
> > +/* { dg-options "-mabicalls -fpic -mips16" } */
> > +
> > +int foo (void *, unsigned, unsigned);
> > +
> > +static int
> > +bar (int *p)
> > +{
> > +  int ret;
> > +
> > +  do
> > +    ret = foo (p, sizeof (*p), 1);
> > +  while (ret == -1);
> > +
> > +  return ret;
> > +}
> > +
> > +int
> > +baz (void)
> > +{
> > +  int x = 1;
> > +
> > +  return bar (&x);
> > +}
> >
>
> --
> Richard Biener <[email protected]>
> SUSE Software Solutions Germany GmbH,
> Frankenstrasse 146, 90461 Nuernberg, Germany;
> GF: Stefan Gaiser, Jochen Jaser, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to