为什么优化后消失了?

时间:2018-10-24 10:07:49

标签: c gcc assembly compiler-optimization inline-assembly

int suma(int* array, int len)
{
    asm("    xor %eax, %eax           # resultado = 0   \n"
        "    xor %edx, %edx           # i = 0           \n"
        "1:  add (%rdi,%rdx,4), %eax  # res += array[i] \n"
        "    inc %edx                 # ++i             \n"
        "    cmp %edx,%esi            # i < len?        \n"
        "    jne 1b                   # repetir         \n"
//      "    ret                                        \n"
       );
}

int main()
{
    int v[100];
    return suma(v, 100);
}

为什么gcc在ret的{​​{1}}的末尾插入suma(),但是我必须自己在-O0上添加它?

来自-O3

gcc -v

1 个答案:

答案 0 :(得分:6)

  

我假设64位...,数组在rdi中,len在esi中。

您正在使用 inline asm,而不是在__attribute__((naked,noinline))函数中使用,因此编译器可以在所需的任何上下文中使用inline asm模板块。由于您无法使用任何输入/输出约束,并且您在不告知编译器的情况下就破坏了寄存器,除非禁用优化,否则它将完全中断。

要回答主要问题,编译器只需将suma内联到main中即可。它是隐式的volatile(因为它是基本的asm语句),因此并未进行优化。

但是执行会落在非空函数(suma)的末尾,这是不确定的行为,因此现代的GCC只是放弃并省略了ret指令。它假定执行永远不会走那条路(由于未定义的行为),并且不会为它生成代码。

如果在return 0;的末尾添加suma,则main将以ret指令结尾。

令人惊讶的是,gcc only gives one warning on the Godbolt compiler explorer with -O3 -Wall

<source>: In function 'int suma(int*, int)':
<source>:13:1: warning: no return statement in function returning non-void [-Wreturn-type]
 }
 ^

main的asm输出结果是这样的,由于RDI为argc,因此这当然完全坏了;它从未为int v[100]保留空间,因为它没有在C源代码中使用或做过任何事情。

main:
            xor %eax, %eax           # resultado = 0   
    xor %edx, %edx           # i = 0           
1:  add (%rdi,%rdx,4), %eax  # res += array[i] 
    inc %edx                 # ++i             
    cmp %edx,%esi            # i < len?        
    jne 1b                   # repetir         

return 0;的末尾有一个suma,它和主要结尾是xorl %eax, %eaxret,但当然main仍然被完全破坏,因为内联汇编不使用任何输入约束。