为什么clang ++比adc更喜欢adcx

时间:2018-06-03 07:03:45

标签: c++ assembly x86-64 clang++

我使用以下代码实现了多精度添加:

    bool carry{};
    std::array<uint64_t, N> r{};

    for (auto i = 0; i < N; ++i) {
       uint64_t aa = a[i];
       __uint128_t res = static_cast<__uint128_t>(aa) + b[i] + carry;
       carry = res >> 64;
       r[i] = res;
    }

clang ++ 6.0产生了以下程序集:

400a49: 4c 01 c1                add    %r8,%rcx
400a4c: 66 49 0f 38 f6 c1       adcx   %r9,%rax
400a52: 66 49 0f 38 f6 f2       adcx   %r10,%rsi
400a58: 66 48 0f 38 f6 d7       adcx   %rdi,%rdx

任何人都可以解释为什么clang选择使用adcx而不是adc? 据我所知,boto具有相同的执行时间,但adc的编码为3字节,而adcx的编码为6。

更新:我玩了一下,似乎行为很随机。 如果args作为const引用传递,我得到adcx https://godbolt.org/g/noFZNS 如果我通过值,我得到adc:

https://godbolt.org/g/RkBWhV

如果代码不在函数内部,只是在main中内联,它就是一团糟。

1 个答案:

答案 0 :(得分:2)

这看起来像是对我的错过优化。我认为adc是更好的选择。在Skylake上,根据一些快速吞吐量测试(在循环中使用xor eax,eax / times 4 adcx eax,edx),它们具有相同的性能特征。 Agner Fog奇怪地没有在他的指令表(http://agner.org/optimize/)中列出adox / adcx,SKL ADC / ADCX / ADOX对于p0 / p6都是1 uop,延迟为1c。

如果有的话,写下所有标志而不仅仅是CF不太可能导致性能问题。

您应该在https://bugs.llvm.org/buglist.cgi上报告此内容。

当有两个并行的dep链时,clang知道如何实际交错ADOX,在ADCX上花费额外的代码大小是没有意义的。

我可以想象一个罕见的情况,其中保留其他标志是有用的,并且最近的英特尔CPU似乎在部分标记的东西非常有效,甚至不需要合并的uop。但这是非常适合的,而不是这里发生的事情(add所有标志都被扼杀了。