[RISCV] redundant return-only BB not eliminated

Jeff Law jeffrey.law@oss.qualcomm.com
Sat Oct 24 04:47:50 GMT 2026



On 9/7/26 8:42 PM, Robert Guthrie wrote:
>> Sometimes its better to ask for help as you work through these 
>> things.  Ideally with before/after dumps and the patch you're working 
>> with.  GCC is fairly complex and often even very experienced 
>> developers need to throw things under the debugger to really 
>> understand what's happening.
>>
>
> Thanks -- I didn't want to ask anyone to debug my stuff, and
> anyways it took a bit of time but was straightforward. Most of the 
> debugging
> has just been me resolving my misunderstandings about what certain 
> functions
> do or variables are for, which is helpful for me.
Well, we do all get busy, as you've no doubt noticed.  Once you hit mid 
Sept most of us hunker down to get ready for Cauldron, then spend time 
digging out of all the missed work when we get back.


So just getting familiar with your problem again.  Sometimes time away 
is good ;-)

To recap, we have two returns, that isn't inherently bad -- having 
multiple returns is preferable to having unconditional jumps to a 
return, so we tend to try and replace jumps to a return with the return 
itself.

At the start of basic block reordering the two returns are not yet 
consecutive and both are reachable both via a fallthru path as well as 
via a conditional jump target.   After the call to cfg_layout_finalize 
we have

> (code_label 36 70 32 6 5 (nil) [1 uses])
>
> (note 32 36 31 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
>
> (insn 31 32 88 6 (use (reg/i:DI 10 a0)) "j.c":4:7 -1
>     (nil))
>
> (note 88 31 89 6 NOTE_INSN_EPILOGUE_BEG)
>
> (jump_insn 89 88 90 6 (simple_return) "j.c":4:7 458 {simple_return}
>     (nil)
> -> simple_return)
>
> (barrier 90 89 94)
>
> (code_label 94 90 80 7 13 (nil) [1 uses])
>
> (note 80 94 91 7 [bb 7] NOTE_INSN_BASIC_BLOCK)
>
> (insn 91 80 81 7 (use (reg/i:DI 10 a0)) -1
>     (nil))
>
> (jump_insn 81 91 82 7 (simple_return) 458 {simple_return}
>     (nil)
> -> simple_return)
>

That's the first point at which you could even consider optimizing. And 
sadly I don't see another cleanup_cfg call after that point. Adding 
another pass just to fix this minor optimization isn't likely to be 
acceptable.  But if you're looking to hack on it and learn I would focus 
on the point after the call to cfg_layout_finalize.

At that point we still have a CFG and if you're careful you can adjust 
it without mucking up the layout.

You want to iterate over the predecessors of the exit block.  That's how 
you find quickly find the blocks that potentially have return 
instructions.   You ought to be able to call bb_is_just_return on all of 
them to build the set of blocks which are just return statements.

Give that set, you want to find any that are not reachable via fallthru 
edges.  That property may be lost in by this point in the optimization 
pipeline.  So you might need to look at each one and see if its 
preceeded by a BARRIER.  So you do something like prev_nonnote_insn 
(BB_HEAD (bb)) and see if you get a BARRIER back. If you do, then you've 
got an optimizable case.

Then you have to go do that blocks predecessors and modify the jump at 
the end of the block to each one of the other identified only-return blocks.

The concern you have about transforming a jump to a return to just a 
return is real, but it's not going to apply in this case.  In this case 
I would expect the only references to be via conditional branches and 
that transformation does not apply to conditional branches.

Normally if you change the last reference to a label (which you're going 
to need to do here), the label becomes unreachable and it'll get removed 
as well as any unreachable code.  But you may have to do your 
transformation so late in the pipeline that you can't rely on that .  
But I'd set this question aside for now.  It's a solveable problem, but 
I'd first focus on just identifying the return blocks, then identifying 
those which are only reachable via jumps, then transforming the jump 
which reaches those blocks to instead target a different return-only block.

This may be somewhat different than what I suggested before.  I didn't 
realize there wasn't a cleanup call after the point where the 
consecutive returns are exposed.

jeff






More information about the Gcc mailing list