【发布时间】:2021-01-12 21:00:29
【问题描述】:
我在编译器资源管理器中摆弄,我发现传递给 std::min 的参数顺序改变了发出的程序集。
Here's the example on Godbolt Compiler Explorer
double std_min_xy(double x, double y) {
return std::min(x, y);
}
double std_min_yx(double x, double y) {
return std::min(y, x);
}
这被编译(例如,在 clang 9.0.0 上使用 -O3),以:
std_min_xy(double, double): # @std_min_xy(double, double)
minsd xmm1, xmm0
movapd xmm0, xmm1
ret
std_min_yx(double, double): # @std_min_yx(double, double)
minsd xmm0, xmm1
ret
如果我将 std::min 更改为老式三元运算符,这种情况仍然存在。它还存在于我尝试过的所有现代编译器(clang、gcc、icc)中。
底层指令是minsd。阅读文档,minsd 的第一个参数也是答案的目的地。显然 xmm0 是我的函数应该放置其返回值的位置,因此如果 xmm0 用作第一个参数,则不需要 movapd。但如果 xmm0 是第二个参数,那么它必须 movapd xmm0, xmm1 才能将值放入 xmm0。 (编者按:是的,x86-64 System V 在 xmm0、xmm1 等中传递 FP args,并在 xmm0 中返回。)
我的问题:为什么编译器不自己切换参数的顺序,这样movapd 就没有必要了?它肯定必须知道 minsd 的参数顺序不会改变答案?是否有一些我不理解的副作用?
【问题讨论】:
-
可能仅仅是因为在极少数情况下保存单个寄存器交换是不值得的
-
@AlanBirtles 我希望编写编译器优化的人不是这样想的。这让我很痛苦。我试图让自己不在乎,因为这在我的上下文中无关紧要,但仍然很痛。
-
@AlanBirtles:Rave 是正确的,这不是编译器开发人员的想法。如果这真的是一个错过的优化(而不是严格的 FP 语义所要求的),gcc 和 clang 开发人员可能会喜欢提交一个错过的优化错误。 (虽然它可能已经是一个已知的错误;通过调用约定要求放置的硬寄存器约束有时会在 gcc 进行寄存器分配时导致浪费
mov或movaps指令,您不会在中间看到内联后更大的函数。) -
@bolov 我的意思是编译器可以切换
minsd操作数的顺序来保存movapd。 (但是,据我所知,它不能那样做。) -
为什么这个问题要加android标签?
标签: android c++ assembly x86 floating-point