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