This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]