我知道x87具有更高的内部精度,这可能是人们看到的它与SSE操作之间最大的区别。但我想知道,使用 x87 还有其他好处吗?我有在任何项目中自动输入
-mfpmath=sse
的习惯,我想知道我是否错过了 x87 FPU 提供的其他功能。
对于手写asm,x87有一些SSE指令集中不存在的指令。
我脑子里全都是三角函数,比如 fsin、fcos、fatan、fatan2 和一些指数/对数函数。
使用
gcc -O3 -ffast-math -mfpmath=387
,GCC9 will 实际上仍然内联 sin(x)
作为 fsin
指令,无论 libm 中的实现使用什么。 (https://godbolt.org/z/Euc5gp)。
MSVC 在编译 32 位 x86 时调用
__libm_sse2_sin_precise
。
如果您的代码大部分时间都花在三角函数上,那么如果您使用 x87,您可能会看到轻微的性能增益或损失,具体取决于使用 SSE1/SSE2 的标准数学库实现比慢速微代码更快还是更慢
fsin
无论您使用什么 CPU。
CPU 供应商并没有投入大量精力来优化最新一代 CPU 中 x87 指令的微代码,因为它通常被认为已过时且很少使用。 (查看最近几代 CPU 中Agner Fog 的指令表中复杂 x87 指令的 uop 计数和吞吐量:比旧 CPU 的周期更多)。 CPU 越新,x87 计算 log、exp、pow 或 trig 函数的速度就越有可能比许多 SSE 或 AVX 指令慢。
即使 x87 可用,并非所有数学库都选择使用像
fsin
这样的复杂指令来实现 sin()
等函数,或者特别是 exp/log,其中用于操作基于日志的 FP 位模式的整数技巧非常有用。
一些 DSP 算法使用大量三角函数,但通常可以从 SIMD 数学库的自动矢量化中受益匪浅。 但是,对于您花费大部分时间进行加法、乘法等的数学代码。SSE 通常更快。
还相关:
- fsin
的最坏情况(
fsin
输入非常接近 pi的灾难性取消)非常糟糕。软件可以做得更好,但只能使用缓慢的扩展精度技术。
EOF
float
和
double
之间的转换比使用 SSE 更快。使用 x87,您可以将 float
、double
或 long double
加载到寄存器堆栈或从寄存器堆栈存储,并且可以将其转换为扩展精度或从扩展精度转换,而无需额外成本。对于 SSE,如果类型混合,则需要额外的指令来执行类型转换,因为寄存器包含 float
或 double
值。这些转换指令相当快,但确实需要额外的时间。真正的解决方法是避免过度混合
float
和
double
,当然不要使用 x87。long double
类型一起使用,但其他编译器(例如 MSVC)不支持该类型。
如果您确实需要 80 位浮点数学(例如,处理该格式的旧二进制数据,或模拟 x87 数学协处理器),请确保您使用支持它的合适编译器。