Hello, I have been exploring RISCV, compiling simple programs and looking at
the output.
The below basic recursive factorial function generates two `ret` insns when
only one is necessary:
the BB labeled with .L12 can be eliminated (by just re-targeting to .L1).
I tried to see if I could understand what was going on myself.
I have no experience working on GCC or any other big compiler, so I took this
as an opportunity to dig around more than anything else.
Thus, please forgive if my analysis is way off.
I determined:
* When the loop was unrolled, the early exit for the special case n == 2 added
the extra `ret` insn as a fallthru
* The `bbro` pass subsequently moved both `ret`s to the end of the linear
sequence,
which is the point at which the second one becomes truly redundant.
Next, I tried to determine why it wasn't subsequently eliminated.
* I looked at `cleanup_cfg`. I thought maybe it was supposed to be eliminated
with CROSSJUMP,
but after looking more, I think my understanding of what CROSSJUMP is was
just incorrect.
And anyways, for some reason two basic blocks with only `ret` and `use` do
not count as having
any matching insns in the suffix (I tried to change this, and
`try_optimize_cfg` began infinite looping
though I didn't determine why: this condition early in
`flow_find_cross_jump` is what I was looking at.)
if (!simplejump_p (i2) && !returnjump_p (i2) && last1 && dir_p)
ninsns++;
* In `try_optimize_cfg` there are various pattern-matches to simplify stuff
like this.
I added my own: "if we have a BB that is only a ret+use with a single pred
that is not a fallthru,
and there is another BB that is only a ret+use, retarget the predecessor to the
other BB and delete this one",
which does seem to eliminate this particular case correctly, though I find
it hard to believe that
is the right way to solve this problem (the pattern is quite overly
specific).
I am wondering: which part of the compiler should in principle eliminate the
duplicate? Am I even looking in the right place?
And if I am, is there some specific part of the CFG simplification that ought
to handle this?
Src:
int fact(int n) {
if (n == 0 || n == 1) return 1;
return n * fact(n-1);
}
Asm, Target riscv32-unknown-elf, march=rv32imac, only flag is -O3, off of
master (9c40d803 specifically)
fact:
mv a5,a0
li a0,1
mv a2,a0
bleu a5,a0,.L1
sub a4,a5,a0
and t0,a4,a0
mv a3,a0
beq t0,zero,.L2
mv a0,a5
addi a5,a5,-1
beq a5,a2,.L12
.L2:
mul a0,a0,a5
addi t1,a5,-1
addi a5,a5,-2
mul a0,a0,t1
bne a5,a3,.L2
.L1:
ret
.L12:
ret
Thanks
Robert