为什么优化后消失了?

gus*_*avo 4 c assembly gcc inline-assembly compiler-optimization

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);
}
Run Code Online (Sandbox Code Playgroud)

为什么gcc会retsuma()on 的末尾插入-O0,但我必须自己添加on -O3

来自gcc -v

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);
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*des 6

我假设在RDI中使用64bit ...数组,在esi中使用len。

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

要回答主要问题,编译器只需内联sumamain。它是隐式的volatile(因为这是一个基本的asm语句),因此并未进行优化。

但是执行落在非空函数(suma)的末尾,后者是未定义的行为,因此现代GCC只是放弃并忽略了ret指令。它假定执行永远不会采用该路径(由于未定义的行为),并且不会为它生成代码。

如果return 0;在的末尾添加a sumamain则将以一条ret指令结尾。

令人惊讶的是,gcc仅在使用-O3 -Wall的Godbolt编译器资源管理器中发出一个警告

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

的asm输出结果main是这样,由于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         
Run Code Online (Sandbox Code Playgroud)

以a return 0;结尾suma,它和主要结尾为xorl %eax, %eaxret,但是main由于内联汇编不使用任何输入约束,因此当然还是完全坏掉了。