是否有任何控制循环展开的预处理器指令?

Posted

技术标签:

【中文标题】是否有任何控制循环展开的预处理器指令?【英文标题】:Are there any preprocessor directives that control loop unrolling? 【发布时间】:2012-10-11 00:27:14 【问题描述】:

此外,假设循环中的所有操作完全独立于其他迭代,编译器如何确定展开循环的范围。

【问题讨论】:

如果存在这样的控件,它将是特定于编译器的。请说出您使用的是哪个编译器。 如果存在这样的预处理器指令,它就不是特定于编译器的,因为预处理器在编译器启动之前完成! (吹毛求疵的角落:C++ 实现只需要表现得“好像”预处理器在下一个翻译阶段开始之前完成。) @Windowsprogrammer:编译器作为一个整体,包括预处理器。这是一个重载的词,就像几乎所有的词一样。 【参考方案1】:

对于 MSVC,只有一个向量独立提示:http://msdn.microsoft.com/en-us/library/hh923901.aspx

#pragma loop( ivdep )

对于许多其他编译器,例如 Intel/ibm,有一些用于优化循环的 pragma 提示:

#pragma unroll
#pragma loop count N
#pragma ivdep

MSVC++ 的人有一个关于展开启发式的线程:http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/d0b225c2-f5b0-4bb9-ac6a-4d4f61f7cb17/

VC 试图平衡执行速度和代码大小。您可以使用标志 /O1 或 /O2 来更改平衡,但即使在优化速度时 VC 也会尝试节省代码大小。

基本上,展开会增加代码大小,因此可能会在 Os 和 O1 模式下受到限制 (modes table)

PS: Pragma 看起来像预处理器指令,但它不是。它是编译器的指令,它被预处理器忽略(保留)。

【讨论】:

谢谢。只是为了与gcc 参考交叉链接,***.com/questions/4071690/…【参考方案2】:

以英特尔编译器为例:

#pragma loop count N 帮助编译器使用最佳策略来向量化循环。它节省了时间所以,我们可以说它有助于推动循环展开。 例子:

#pragma loop_count min(n),max(n),avg(n)

#pragma unroll (n) 仅在与 -O3 标志一起使用时有效,您可以使用以下策略根据目标处理器展开循环。

除了循环展开生成的代码增加之外,这可能是值得的,因为编译器将为标量操作和向量操作生成循环版本。

在展开影响性能的情况下,例如:具有 20 次迭代且向量长度为​​ 16 的循环,会导致 1 个循环同时执行 16 个操作,而余数循环会顺序执行 4 个操作。 为了避免编译器产生的余数循环,我们可以在循环之前使用:

#pragma vector novecremainder //or -mP2OPT_hpo_vec_peel = F to disable peel and remainder loops (compiler internal option)

#pragma nounroll //where unrolling is not worth at all 

只是为了澄清#pragma ivdep

它提供了修改编译器启发式有关依赖项的具体提示,并且只有在我们知道假定的依赖项可以安全忽略时才必须使用。 最重要的是,它会覆盖潜在的依赖关系,但编译器仍会执行依赖关系分析,尝试#pragma simd 进行向量化,不管任何分析。

希望这会有所帮助。

【讨论】:

以上是关于是否有任何控制循环展开的预处理器指令?的主要内容,如果未能解决你的问题,请参考以下文章

使用循环展开计算正数、负数和零数的最有效方法

优化编译器如何决定何时展开循环以及展开循环的程度?

为啥 clang 无法展开循环(即 gcc 展开)?

C/C++ 中的自展开宏循环

如何在 C++ 中展开嵌套的 for 循环?

循环展开有利的条件以及收益率下降的点?