为什么clang会为64位双精度的绝对值发出32位浮点ps指令



为什么clang将fabs(double)变成vandps而不是vandpd(就像GCC一样)?


编译器资源管理器中的示例:

#include <math.h>
double float_abs(double x) {
return fabs(x);
}

clang 12.0.1-std=gnu++11 -Wall -O3 -march=znver3

.LCPI0_0:
.quad   0x7fffffffffffffff              # double NaN
.quad   0x7fffffffffffffff              # double NaN
float_abs(double):                          # @float_abs(double)
vandps  xmm0, xmm0, xmmword ptr [rip + .LCPI0_0]
ret

gcc 11.2-std=gnu++11 -Wall -O3 -march=znver3

float_abs(double):
vandpd  xmm0, xmm0, XMMWORD PTR .LC0[rip]
ret
.LC0:
.long   -1
.long   2147483647
.long   0
.long   0

(具有讽刺意味的是,GCC使用vandpd,但用32位.long块定义常数(有趣的是,上半部分为零),而clang使用vandps,但将常数定义为.quad的两半。

TL:DR:可能是因为优化器/代码生成器更容易始终执行此操作,而不是仅使用遗留SSE指令来节省代码大小。没有性能下降,而且它们在体系结构上是等效的(即没有正确性差异。)


可能总是叮当作响";规范化";与ps版本在架构上等效的指令,因为这些指令的机器代码编码比传统SSE版本更短。

现有的x86 CPU在pspd指令之间转发时没有任何旁路延迟延迟1,因此在[v]mulpd[v]fmadd...pd指令之间使用[v]andps总是安全的。

As像orpd这样的SSE2指令有什么意义?指出,像movupdandpd这样的指令完全是无用的空间浪费,它们只存在于解码器一致性中:SSE1操作码前面的66前缀总是执行它的pd版本。为未来的其他扩展节省一些编码空间可能会更明智,但英特尔没有这样做。

或者,动机可能是确实具有独立SIMD双域和SIMD浮点域的CPU的未来可能性,因为SSE2在纸上设计时,英特尔的FP SIMD还处于早期阶段。如今,我们可以说这不太可能,因为FMA单元需要很多晶体管,而且显然可以构建为在每个64位元素一个53位尾数与每个2x 32位元素两个23位尾数之间共享尾数乘法器硬件。

如果您也有单独的执行单元用于浮点运算与双重运算,而不是共享晶体管,那么拥有单独的转发域可能只有在这样的情况下才有用,除非您有不同类型但实际内部相同的不同输入和输出端口?IDK足够多的CPU设计细节。


对于AVX VEX编码的版本,ps没有优势,但也没有劣势,因此LLVM的优化器/代码生成器可能更简单,只需始终这样做,而不必关心如何尊重源内部函数。(Clang/LLVM通常不会尝试这样做,例如,它可以自由地将shuffle内部函数优化为不同的shuffle。这通常是好的,但有时它会在不知道内部函数作者所做的技巧时,对精心制作的内部函数进行去优化。)

例如LLVM可能根据";FP域128位逐位AND";,并且知道其指令是CCD_ 20/CCD_。clang甚至没有理由知道vandpd的存在,因为在任何情况下使用它都没有帮助


脚注1:推土机隐藏的元数据和数学指令之间的转发
AMD推土机系列对mulps->mulpd,用于实际关心FP值的符号/指数/尾数分量(而不是布尔或混洗)的实际FP数学指令。

将两个IEEE二进制32 FP值的级联视为二进制64基本上没有意义,因此这不是一个需要解决的问题。它主要是让我们深入了解CPU内部是如何设计的。

在Agner Fog的微芯片指南的推土机系列部分中,他解释说,在FMA单元上运行的两条数学指令之间转发的旁路延迟比另一条指令阻碍时低1个周期。例如addps / orps / addps具有比addps / addps / orps更差的延迟。

但对于像addps / addpd / orps这样疯狂的东西,你会得到额外的延迟。但对于addps / orps / addpd则不然。(orpsorpd在这里没有区别。shufps也相当。)

可能的解释是,BD保留了向量元素的额外内容,以便在这种特殊的转发情况下重用,以避免在转发FMA->FMA。如果格式错误,那么乐观的方法必须恢复并执行架构要求的操作,但同样,只有当您实际将浮点FMA/add/mul的结果视为双精度时,才会发生这种情况,反之亦然。

addps可以无延迟地转发到类似unpcklpd的混洗,因此这不是3个独立旁路网络的证据,也不是使用(或存在)andpd/orpd的任何理由。

最新更新