循环中的价值约束优化建议

时间:2019-01-16 14:00:45

标签: c++ c++11 assembly c++14 inline-assembly

我有一个紧紧的循环,就像钱德勒·卡鲁斯(Chandler Carruth)在CPP CON 2017上提出的那样: https://www.youtube.com/watch?v=2EWejmkKlxs 在此视频中,在25分钟时出现了这样的循环:

for (int& i:v)
    i = i>255?255:i;

其中v是向量。这与我的程序中使用的代码完全相同,经过分析后,证明需要花费大量时间。

在他的演讲中,钱德勒修改了装配体并加快了循环速度。我的问题是,在实践中,在生产代码中,建议采用什么方法来优化此效果?我们应该在C ++代码中使用内联汇编吗?还是像钱德勒所做的那样,将C ++代码编译到汇编中,然后优化汇编器?

假设采用x86架构,将非常感谢您优化上述for循环的示例。

2 个答案:

答案 0 :(得分:2)

  

我的问题是,在实践中,在生产代码中,建议使用哪种方法来对此进行优化?我们应该在C ++代码中使用内联汇编吗?还是像钱德勒所做的那样,将C ++代码编译到汇编中,然后优化汇编器?

对于生产代码,您需要考虑该软件可以在自动构建系统中进行编译和链接。

在这样的系统中,您如何将代码更改应用于汇编代码?您可能会应用一个diff文件,但是如果更改了优化(或其他)设置,切换到其他编译器或...时,该文件可能会中断。

现在剩下两个选择:将整个函数写入汇编文件(.s)或在C ++代码内包含内联汇编代码-后者可能具有将相关代码保持在同一翻译单元中的优点。

还是让编译器一次生成汇编代码 -并提供最高的优化级别。然后,该代码可以用作您进行手工优化的基础(已经预先优化),然后将其结果作为内联汇编粘贴回C ++源文件或放置到单独的汇编源文件中。

答案 1 :(得分:2)

Chandler修改了编译器的asm输出,因为这是进行一次性实验以找出更改是否有用的简便方法无需您通常希望将一个asm循环或功能作为项目源代码的一部分。

编译器生成的asm通常是优化循环的一个很好的起点,但是实际上将整个文件保持原样不是将循环的asm实现作为程序的一部分实际维护的好方法,甚至不是可行的方法。参见@Aconcagua的答案。

此外,它无法实现用C ++编写的文件中具有其他任何功能并且可用于链接时优化的目的。


回复:实际夹紧:

请注意,Chandler只是在尝试对非矢量化的代码源进行更改,并禁用了展开+自动矢量化。希望在现实生活中,您可以针对SSE4.1或AVX2,并让编译器使用pminsdpminud自动向量化,以将有符号或无符号int钳位到上限。 (也可以使用其他元素大小。或者不使用SSE4.1,仅使用SSE2,也许可以2x PACKSSDW => packuswb(无符号饱和度),然后用零解包,最多返回4个dword元素向量。 (如果不能仅使用uint8_t[]的输出!)

顺便说一句,{TW},in the comments of the video, Chandler said证明他犯了一个错误,而他所看到的效果并不是真的由于可预测的分支与cmov所致。可能是代码对齐问题,因为从mov %ebx, (%rdi)更改为movl $255, (%rdi)会有所作为!

(不知道AMD CPU是否像P6-系列那样具有寄存器读取停顿功能,应该毫不费力地隐藏将存储耦合到负载的cmov的dep链与通过分支预测+推测打破它分支。)


很少实际上会想要使用手写循环。通常,只需修改C ++源代码,您就可以手持和/或诱使编译器使asm更符合您的需要。然后,将来的编译器可以自由调整-march=some_future_cpu的内容。