【问题标题】:Why does GCC for Risc-V generate nop instructions after call为什么 GCC for Risc-V 在调用后会生成 nop 指令
【发布时间】:2020-01-01 20:04:26
【问题描述】:

默认情况下,用于 Risc-V 的 GCC 在 call 指令之后生成 nop 指令:

$ cat test.c
void g();
void f() {
        g();
}
$ riscv64-unknown-elf-gcc -S test.c -o -    
[...]
f:
        addi    sp,sp,-16
        sd      ra,8(sp)
        sd      s0,0(sp)
        addi    s0,sp,16
        call    g
        nop #### <-----------here
        ld      ra,8(sp)
        ld      s0,0(sp)
        addi    sp,sp,16
        jr      ra
        .size   f, .-f
        .ident  "GCC: (GNU) 8.3.0"

我希望在针对具有branch delay slot 的架构时,但我的理解是 Risc-V 不是这样的架构。实际上,nop 在使用-O1 或更高版本编译时会消失。

这只是 GCC 中的一个“错误”,它发出 nop 作为具有延迟槽的架构的遗留物,还是这个 nop 指令的实际原因?

【问题讨论】:

    标签: gcc riscv


    【解决方案1】:

    GCC 可能会在任何架构上执行此操作。我认为nop 指令与void 结果有关,它是非空函数设置返回值的地方。尝试编译:

    int g();
    int f() {
            g();
            return 1;
    }
    

    对于 void 函数,无需执行任何操作来生成结果,因此是 nop

    【讨论】:

      【解决方案2】:

      不是一个完整的答案,但至少尝试深入研究 nop 出现的原因。我坚信这是具有延迟槽的架构的错误/遗留问题(因为它是在第一个 RTL 通道中添加的 - 扩展)。

      在调查中,GCC 有 2 种类型的 pass,Tree 和 RTL。要查看它们的实际效果,请准备 2 个文件夹,因为会有很多文件,nooptopt,然后使用 -fdump-tree-all-raw -fdump-rtl-all 查看中间结果。 Tree pass 的最后阶段给出(noopt case):

      $ cat noopt/test.c.232t.optimized
      
      ;; Function f (f, funcdef_no=0, decl_uid=1549, cgraph_uid=0, symbol_order=0)
      
      f ()
      {
        <bb 2> :
        gimple_call <g, NULL>
        gimple_return <NULL NULL>
      
      }
      

      opt case (-O1) 的差异可以忽略不计:

      $ diff -u noopt/test.c.232t.optimized opt/test.c.232t.optimized 
      --- noopt/test.c.232t.optimized 2019-09-03 14:48:02.874071927 +0200
      +++ opt/test.c.232t.optimized   2019-09-03 14:48:29.550278667 +0200
      @@ -3,7 +3,7 @@
      
       f ()
       {
      -  <bb 2> :
      +  <bb 2> [local count: 1073741825]:
         gimple_call <g, NULL>
         gimple_return <NULL NULL>
      

      RTL 传递(扩展)的第一阶段是不同的:

      $ cat noopt/test.c.234r.expand
      
      ;; Function f (f, funcdef_no=0, decl_uid=1549, cgraph_uid=0, symbol_order=0)
      
      
      ;; Generating RTL for gimple basic block 2
      
      
      try_optimize_cfg iteration 1
      
      Merging block 3 into block 2...
      Merged blocks 2 and 3.
      Merged 2 and 3 without moving.
      Merging block 4 into block 2...
      Merged blocks 2 and 4.
      Merged 2 and 4 without moving.
      
      
      try_optimize_cfg iteration 2
      
      
      
      ;;
      ;; Full RTL generated for this function:
      ;;
      (note 1 0 3 NOTE_INSN_DELETED)
      (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
      (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
      (call_insn 5 2 8 2 (parallel [
                  (call (mem:SI (symbol_ref:DI ("g") [flags 0x41] <function_decl 0x7fbc2827a400 g>) [0 g S4 A32])
                      (const_int 0 [0]))
                  (clobber (reg:SI 1 ra))
              ]) "../test.c":3 -1
           (nil)
          (nil))
      (insn 8 5 0 2 (const_int 0 [0]) "../test.c":4 -1
           (nil))
      

      -O1 的区别只是删除了const_int 0 [0],这最终会导致nop

      $ diff -u noopt/test.c.234r.expand opt/test.c.234r.expand 
      --- noopt/test.c.234r.expand    2019-09-03 14:48:02.874071927 +0200
      +++ opt/test.c.234r.expand  2019-09-03 14:48:29.550278667 +0200
      @@ -25,12 +25,10 @@
       (note 1 0 3 NOTE_INSN_DELETED)
       (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
       (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
      -(call_insn 5 2 8 2 (parallel [
      -            (call (mem:SI (symbol_ref:DI ("g") [flags 0x41] <function_decl 0x7fbc2827a400 g>) [0 g S4 A32])
      +(call_insn 5 2 0 2 (parallel [
      +            (call (mem:SI (symbol_ref:DI ("g") [flags 0x41] <function_decl 0x7f0bdec1f400 g>) [0 g S4 A32])
                       (const_int 0 [0]))
                   (clobber (reg:SI 1 ra))
               ]) "../test.c":3 -1
            (nil)
           (nil))
      -(insn 8 5 0 2 (const_int 0 [0]) "../test.c":4 -1
      -     (nil))
      

      【讨论】:

        猜你喜欢
        • 2018-11-22
        • 1970-01-01
        • 2022-12-06
        • 2011-08-19
        • 2023-03-22
        • 2014-12-10
        • 2023-04-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多