GCC 编译器中的条件移动 (cmov)

标签 c gcc assembly compiler-optimization

我在某处看到 GCC 编译器在将我的代码转换为 ASM 时有时可能不喜欢使用条件 mov。

在哪些情况下它可能会选择执行条件 mov 以外的操作?

最佳答案

当分支的两边都很短时,编译器通常倾向于将 if-conversion 转换为 cmov,尤其是对于三元组,因此您总是分配一个 C 变量。例如if(x) y=bar; 有时不会优化到 CMOV 但 y = x ? bar : y; 确实更频繁地使用 CMOV。特别是当 y 是一个否则不会被触及的数组条目时:引入它的非原子 RMW 可能会创建源中不存在的数据竞争。 (编译器无法发明对可能共享对象的写入。)

if 转换合法但显然无利可图的一个明显例子是当 if/else 的两边都有大量工作时。例如一些乘法和除法,整个循环和/或表查找。即使 gcc 可以证明两边都运行并在最后选择一个结果是安全的,它也会看到做更多的工作不值得避免一个分支。

If 转换为数据依赖(无分支 cmov)甚至仅在有限的情况下才有可能。例如Why is gcc allowed to speculatively load from a struct?显示了可以/不能完成的情况。其他情况包括进行 C 抽象机没有的内存访问,编译器无法证明它不会出错。或者可能有副作用的非内联函数调用。

另请参阅这些关于 gcc 使用 CMOV 的问题。

另见 Disabling predication in gcc/g++ - 显然 gcc -fno-if-conversion -fno-if-conversion2 将禁用 cmov。

有关 cmov 损害性能的情况,请参阅 gcc optimization flag -O3 makes code slower than -O2 - GCC -O3 需要配置文件引导优化以使其正确并为 if 使用分支,结果证明是高度可预测的。 GCC -O2 一开始就没有进行 if 转换,即使没有 PGO 分析数据。

另一个例子:Is there a good reason why GCC would generate jump to jump just over one cheap instruction?

GCC seemingly misses simple optimization显示了三元在两半都有副作用的情况:三元不像 CMOV:甚至只有一侧被评估为副作用。

AVX-512 and Branching显示了一个 Fortran 示例,其中 GCC 需要源代码更改的帮助才能使用无分支 SIMD。 (相当于标量 CMOV)。这是不发明写入的情况:对于源不会写入的元素,它不能将读取/分支转换为读取/可能修改/写入。 自动矢量化通常需要If-conversion。

关于GCC 编译器中的条件移动 (cmov),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60019582/

相关文章:

c - 在枚举中定义 "Unknown"或 "NULL"值

c++ - 加载共享库时出错 : libgomp. so.1 : , GCC 版本错误?

linux - x86 程序集 - printf 在没有 "\n"的情况下不打印

android.mk sdl 构建错误

C - 为什么我的函数返回 NULL?

c - 将 char 数组转换为十六进制字符串并将其打印在一行中的方法

c - 运行任何英特尔 AVX 函数后,数学函数需要更多周期

c++ - g++ 没有 gcc 也能工作吗?

assembly - 将 EAX 复制到 RAX 更高位?

linux - 在程序集递归中求解帕斯卡三角 (nCk)