gpt4 book ai didi

c - 未执行循环裂变/不变优化,为什么?

转载 作者:行者123 更新时间:2023-12-03 19:11:23 26 4
gpt4 key购买 nike

我正在尝试了解有关汇编的更多信息以及编译器可以做和不能做的优化。

我有一段测试代码,对此我有一些疑问。

在此处查看实际操作:https://godbolt.org/z/pRztTT ,或检查下面的代码和程序集。

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
for (int j = 0; j < 100; j++) {
if (argc == 2 && argv[1][0] == '5') {
printf("yes\n");
}
else {
printf("no\n");
}
}

return 0;
}

GCC 10.1 使用 -O3 生成的程序集:
.LC0:
.string "no"
.LC1:
.string "yes"
main:
push rbp
mov rbp, rsi
push rbx
mov ebx, 100
sub rsp, 8
cmp edi, 2
je .L2
jmp .L3
.L5:
mov edi, OFFSET FLAT:.LC0
call puts
sub ebx, 1
je .L4
.L2:
mov rax, QWORD PTR [rbp+8]
cmp BYTE PTR [rax], 53
jne .L5
mov edi, OFFSET FLAT:.LC1
call puts
sub ebx, 1
jne .L2
.L4:
add rsp, 8
xor eax, eax
pop rbx
pop rbp
ret
.L3:
mov edi, OFFSET FLAT:.LC0
call puts
sub ebx, 1
je .L4
mov edi, OFFSET FLAT:.LC0
call puts
sub ebx, 1
jne .L3
jmp .L4

似乎 GCC 产生了两个版本的循环:一个带有 argv[1][0] == '5'条件但没有 argc == 2有条件的,无条件的。

我的问题:
  • 是什么阻止了 GCC 拆分完整的条件?类似于 this问题,但是代码没有机会在这里获得指向 argv 的指针。
  • 在没有任何条件的循环中(汇编中的L3),为什么循环体重复?是否在仍然适合某种缓存的同时减少跳转次数?
  • 最佳答案

    GCC 不知道 printf不会修改 argv 指向的内存,因此它无法将该检查提升到循环之外。
    argc是一个局部变量(不能被任何指针全局变量指向),所以它知道调用一个不透明的函数不能修改它。证明局部变量是真正私有(private)的是 Escape Analysis 的一部分。 .

    OP 通过复制 argv[1][0] 对此进行了测试。首先进入本地 char 变量:让 GCC 将完整条件提升出循环。

    在实践中 argv[1]不会指向 printf 的内存可以修改。但我们只知道因为printf是一个 C 标准库函数,我们假设 main仅由具有实际命令行参数的 CRT 启动代码调用。不是通过该程序中传递自己的参数的其他函数。在 C 中(与 C++ 不同),main是可重入的,可以在程序内调用。

    此外,在 GNU C 中,printf可以注册自定义格式字符串处理函数。虽然在这种情况下,编译器内置 printf查看格式字符串并将其优化为 puts称呼。

    所以printf已经部分特殊了,但我认为 GCC 不会费心寻找基于它的优化而不修改任何其他全局可访问的内存。使用自定义 stdio 输出缓冲区,这甚至可能不是真的。 printf是缓慢的;节省一些溢出/重新加载通常没什么大不了的。

    Would (theoretically) compiling puts() together with this main() allow the compiler to see puts() isn't touching argv and optimize the loop fully?



    是的,例如如果你自己写了 writesyscall 周围使用内联 asm 语句的函数指令(使用仅内存输入操作数使其安全,同时避免 "memory" 破坏)然后它可以内联并假设 argv[1][0]没有被 asm 语句更改并基于它进行检查。即使您正在输出 argv[1] .

    或者可以在没有内联的情况下进行过程间优化。

    回复:展开:这很奇怪, -funroll-loops GCC 在 -O3 默认情况下不启用, 仅适用于 -O3 -fprofile-use .或者如果手动启用。

    关于c - 未执行循环裂变/不变优化,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61957095/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com