如何告诉编译器展开这个循环[重复]

Posted

技术标签:

【中文标题】如何告诉编译器展开这个循环[重复]【英文标题】:How to tell the compiler to unroll this loop [duplicate] 【发布时间】:2013-04-07 23:47:34 【问题描述】:

我在 ARM 处理器上运行以下循环。

// pin here is pointer to some part of an array
for (i = 0; i < v->numelements; i++)

    pe   = pptr[i];
    peParent = pe->parent;

    SPHERE  *ps = (SPHERE *)(pe->data);

    pin[0] = FLOAT2FIX(ps->rad2);
    pin[1] = *peParent->procs->pe_intersect == &SphpeIntersect;
    fixifyVector( &pin[2], ps->center ); // Is an inline function

    pin = pin + 5;

通过循环的缓慢性能,我可以判断编译器无法展开这个循环,因为当我手动展开时,它变得非常快。我认为编译器被pin 指针弄糊涂了。我们可以在这里使用restrict关键字来帮助编译器,还是restrict只保留给函数参数?一般来说,我们如何告诉编译器展开它而不用担心pin 指针。

【问题讨论】:

您是否测量了调试或发布版本的执行时间? 使用 -O3 优化发布构建。 您是否尝试将 v-&gt;numelements 分配给本地并在 for 循环中使用它?可能是编译器无法展开循环,因为它必须假设 v-&gt;numelements 的值将在 fixifyVector 中更改。 gcc 还有 -funroll-loops 优化标志,查看 docs 它必须与 -O3 分开启用 我在该代码中看不到任何可以通过展开循环得到显着帮助的内容。您将不得不查看为这两种情况生成的目标代码,以了解发生了什么。 【参考方案1】:

要告诉 gcc 展开所有循环,您可以使用优化标志 -funroll-loops

仅展开您可以使用的特定循环:

__attribute__((optimize("unroll-loops")))

查看answer了解更多详情。

编辑

如果编译器在进入时无法确定循环的迭代次数,则需要使用-funroll-all-loops。注意从documentation:"Unroll all loops, even if their number of iterations is uncertain when the loop is entered. This usually makes programs run more slowly."

【讨论】:

【参考方案2】:

如果将pptr 的大小扩大一倍,则可以使用pld 指令。

  __asm__ __volatile__("pld\t[%0]" :: "r" (pptr[i+1]));

或者,您可能需要预加载 next peParentSPHERE *ps。 ARM 上的循环开销非常小。展开循环不太可能带来显着的好处。没有循环变量常量。当您展开循环时,编译器的调度程序更有可能在使用高级数据之前获取这些数据。

您还没有展示所有代码来查看数据依赖关系。 预加载可能还有其他变量会受益。给出一个完整的例子可能会帮助每个人回答你的问题。

【讨论】:

这个答案更可能出现在流水线较大的 Cortex 类型 CPU 上。没有提到具体的 ARM CPU。

以上是关于如何告诉编译器展开这个循环[重复]的主要内容,如果未能解决你的问题,请参考以下文章

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

在 MSVC C++ 中强制循环展开

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

如何告诉编译器可以安全地并行化循环?

如何要求 GCC 完全展开这个循环(即剥离这个循环)?

迭代 const 容器时编译器会展开“for”循环吗?