2

我试图通过查看生成的汇编代码来了解使用带有双参数的std::fma是否有利,我正在使用标志“-O3”,并且我正在比较这两个例程的程序集:

#include <cmath>
#define FP_FAST_FMAF

float test_1(const double &a, const double &b, const double &c ){
    return a*b + c;
}
float test_2(const double &a, const double &b, const double &c ){
    return std::fma(a,b,c);
}

使用Compiler Explorer工具,这是为两个例程生成的程序集:

test_1(double const&, double const&, double const&):
        movsd     xmm0, QWORD PTR [rdi]                         #5.12
        mulsd     xmm0, QWORD PTR [rsi]                         #5.14
        addsd     xmm0, QWORD PTR [rdx]                         #5.18
        cvtsd2ss  xmm0, xmm0                                    #5.18
        ret                                                     #5.18
test_2(double const&, double const&, double const&):
        push      rsi                                           #7.65
        movsd     xmm0, QWORD PTR [rdi]                         #8.12
        movsd     xmm1, QWORD PTR [rsi]                         #8.12
        movsd     xmm2, QWORD PTR [rdx]                         #8.12
        call      fma                                           #8.12
        cvtsd2ss  xmm0, xmm0                                    #8.12
        pop       rcx                                           #8.12
        ret      

并且使用 icc 或 gcc 可用的最新版本不会更改程序集。关于这两个例程的性能让我感到困惑的是,虽然对于 test_1 只有一个内存操作(movsd),但对于 test_2 有三个,并且考虑到内存操作的延迟在一到两个数量级之间与浮点运算的延迟相比,test_1 的性能应该更高。因此,建议在哪些情况下使用 std::fma?我的假设有什么错误?

4

1 回答 1

1

如果您的问题仅与内存操作的数量有关,请务必注意,mulsd并且addsd在您的示例中也是内存操作。内存操作由寄存器名称周围的方括号表示,而不是程序集助记符本身。

如果您仍然好奇使用 是否有好处std::fma,答案可能是“视情况而定”。

当您通过查看汇编来分析性能时,向编译器提供至少一些有关您的目标体系结构的信息几乎是必不可少的。std::fma如果硬件 FMA 指令在目标架构上可用,则使用硬件 FMA 指令,因此总体上是否std::fma提高性能并不是一个真正可以回答的问题。

如果您在 Compiler Explorer中指定-mfma,编译器有一些信息可以用来生成更高效的代码。如果支持,您还可以指定-march=[your architecture]将自动-mfma为您设置的内容。


此外,还有一大堆关于浮点数处理舍入方式导致的结果略有不同的蠕虫std::fma。在两个浮点运算期间只循环一次,而可能[1]将结果存储在 64 位中,添加到该值,然后将结果存储在 64 位中。(a*b)+cstd::fma(a*b)+ca*bc

如果您想最小化计算中的浮点算术误差,std::fma这可能是一个更好的选择,因为它保证您只会从宝贵的浮点数中剥离宝贵的位一次。


[1]这种额外的舍入是否发生取决于您的编译器、优化设置和体系结构设置: msvc、gcc、icc、clang 的编译器资源管理器示例

于 2020-06-09T01:18:49.950 回答