This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
RISC-V sibcall optimization with save-restore
- From: Paulo Matos <pmatos@linki.tools>
- To: "gcc at gcc dot gnu dot org" <gcc at gcc dot gnu dot org>
- Date: Wed, 20 Mar 2019 13:25:22 +0100
- Subject: RISC-V sibcall optimization with save-restore
Hi,
I am working on trying to get RISC-V 32 emitting sibcalls even in the
present of `-msave-restore`, for a client concerned with generated code
size.
Take a look at what current gcc generates for:
int __attribute__ ((noinline))
bar ()
{
return 3;
}
int __attribute__ ((noinline))
foo ()
{
return bar ();
}
int
main ()
{
return foo ();
}
$ install-riscv/bin/riscv32-unknown-elf-gcc -msave-restore -Os -o- -S test.c
.file "test.c"
.option nopic
.attribute arch, "rv32i2p0_m2p0_c2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 2
.globl bar
.type bar, @function
bar:
li a0,3
ret
.size bar, .-bar
.align 2
.globl foo
.type foo, @function
foo:
call t0,__riscv_save_0
call bar
tail __riscv_restore_0
.size foo, .-foo
.section .text.startup,"ax",@progbits
.align 2
.globl main
.type main, @function
main:
call t0,__riscv_save_0
call foo
tail __riscv_restore_0
.size main, .-main
.ident "GCC: (GNU) 9.0.1 20190315 (experimental)"
This could clearly be:
bar:
li a0,3
ret
.size bar, .-bar
.align 2
.globl foo
.type foo, @function
foo:
tail bar
.size foo, .-foo
.section .text.startup,"ax",@progbits
.align 2
.globl main
.type main, @function
main:
tail foo
.size main, .-main
which is what I obtain if I remove the lines 4615-4616 from riscv.c:
4610 static bool
4611 riscv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
4612 tree exp ATTRIBUTE_UNUSED)
4613 {
4614 /* Don't use sibcalls when use save-restore routine. */
4615 if (TARGET_SAVE_RESTORE)
4616 return false;
This causes, of course, test save-restore-1.c to break because in the
case of the test, we need to save/restore s0 and therefore require the
prologue and epilogue to do its job properly.
AFAICT in cases where s0-s11 do not need to be saved, we could
potentially sibcalls in the presence of save-restore.
The problem I am facing while attempting to implement this is that the
decision to do a sibcall is done at expand time, and I only get register
liveness information much later which means I can't decide to sibcall or
not depending on which registers need to be saved.
I attempted then to always enable sibcall (by removing lines 4615-4616
above) and fixup the epilogue in `riscv_expand_epilogue' to enable a
libcall generation even if sibcall was requested.
The start of `riscv_expand_epilogue' would look like:
void
riscv_expand_epilogue (int style)
{
struct riscv_frame_info *frame = &cfun->machine->frame;
unsigned mask = frame->mask;
HOST_WIDE_INT step1 = frame->total_size;
HOST_WIDE_INT step2 = 0;
bool use_restore_libcall = riscv_use_save_libcall (frame);
rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
rtx insn;
if (use_restore_libcall)
style = NORMAL_RETURN;
...
So, use_restore_libcall does not depend on style but only if we should
use save_libcall and then if use_restore_libcall then we move the style
to NORMAL_RETURN.
I thought I was on the right path until I noticed that the CFG is messed
up because of assumptions related to emission of sibcall instead of a
libcall until the epilogue is expanded. During the pro_and_epilogue pass
I get an emergency dump and a segfault:
gcc/gcc/testsuite/gcc.target/riscv/save-restore-1.c:11:1: error: in
basic block 2:
gcc/gcc/testsuite/gcc.target/riscv/save-restore-1.c:11:1: error: flow
control insn inside a basic block
(jump_insn 24 23 6 2 (parallel [
(return)
(use (reg:SI 1 ra))
(const_int 0 [0])
]) "gcc/gcc/testsuite/gcc.target/riscv/save-restore-1.c":11:1 -1
(nil))
during RTL pass: pro_and_epilogue
dump file: save-restore-1.c.285r.pro_and_epilogue
gcc/gcc/testsuite/gcc.target/riscv/save-restore-1.c:11:1: internal
compiler error: in rtl_verify_bb_insns, at cfgrtl.c:2705
0xf86661 _fatal_insn(char const*, rtx_def const*, char const*, int, char
const*)
gcc/gcc/rtl-error.c:108
0x9f0e7a rtl_verify_bb_insns
gcc/gcc/cfgrtl.c:2705
0x9f117e rtl_verify_flow_info_1
gcc/gcc/cfgrtl.c:2791
0x9f19b2 rtl_verify_flow_info
gcc/gcc/cfgrtl.c:3034
0x9d6e7c verify_flow_info()
gcc/gcc/cfghooks.c:263
0xed72e2 execute_function_todo
gcc/gcc/passes.c:1989
0xed626f do_per_function
gcc/gcc/passes.c:1638
0xed7467 execute_todo
gcc/gcc/passes.c:2031
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
Is there a way around this issue and allow the libcall to be emitted,
even if the sibcall was enabled? Or emit a sibcall even if it had been
disabled? Since the problem stems that at sibcall_ok_for_function_p I
don't have enough information to know what to do, is there a way to
decide this later on?
Thanks,
--
Paulo Matos