c++ - 现代编译器能否展开使用开始和结束迭代器表示的 `for` 循环

标签 c++ stl loop-unrolling

考虑以下代码

 vector<double> v;
 // fill v
 const vector<double>::iterator end =v.end();
 for(vector<double>::iterator i = v.bgin(); i != end; ++i) {
   // do stuff
 }

g++、clang++、icc 等编译器是否能够像这样展开循环。不幸的是,我不知道程序集是否能够从输出中验证循环是否展开。 (而且我只能访问 g++。)

在我看来,这似乎需要代表编译器比平时更聪明,首先推断迭代器是随机访问迭代器,然后计算出循环执行的次数。启用优化后,编译器可以执行此操作吗?

感谢您的回复,在你们中的一些人开始讲授过早优化之前,这是一个出于好奇的练习。

最佳答案

To me it seems that this will require more smartness than usual on behalf of the compiler, first to deduce that the iterator is a random access iterator, and then figure out the number of times the loop is executed.

STL 完全由模板组成,具有所有代码内联。因此,当编译器开始应用优化时,随机访问迭代器已经减少为指针。创建 STL 的原因之一是程序员不需要以智取编译器。您应该依靠 STL 来做正确的事情,直到证明不是这样。

当然,你还是要从STL中选择合适的工具来使用...

编辑:曾讨论过 g++ 是否展开任何循环。在我使用的版本上,循环展开不是 -O-O2-O3 的一部分,我得到了相同的程序集对于后两个级别,使用以下代码:

void foo (std::vector<int> &v) {
    volatile int c = 0;
    const std::vector<int>::const_iterator end = v.end();
    for (std::vector<int>::iterator i = v.begin(); i != end; ++i) {
        *i = c++;
    }
}

用对应的程序集-O2程序集:

_Z3fooRSt6vectorIiSaIiEE:
.LFB435:
        movq    8(%rdi), %rcx
        movq    (%rdi), %rax
        movl    $0, -4(%rsp)
        cmpq    %rax, %rcx
        je      .L4
        .p2align 4,,10
        .p2align 3
.L3:
        movl    -4(%rsp), %edx
        movl    %edx, (%rax)
        addq    $4, %rax
        addl    $1, %edx
        cmpq    %rax, %rcx
        movl    %edx, -4(%rsp)
        jne     .L3
.L4:
        rep
        ret

通过添加 -funroll-loops 选项,该函数可以扩展到更大的范围。但是,文档警告此选项:

Unroll loops whose number of iterations can be determined at compile time or upon entry to the loop. -funroll-loops implies -frerun-cse-after-loop. It also turns on complete loop peeling (i.e. complete removal of loops with small constant number of iterations). This option makes code larger, and may or may not make it run faster.

作为阻止您自己展开循环的进一步论据,我将用一个应用 Duff's Device 的例子来结束这个答案。到上面的 foo 函数:

void foo_duff (std::vector<int> &v) {
    volatile int c = 0;
    const std::vector<int>::const_iterator end = v.end();
    std::vector<int>::iterator i = v.begin();
    switch ((end - i) % 4) do {
    case 0: *i++ = c++;
    case 3: *i++ = c++;
    case 2: *i++ = c++;
    case 1: *i++ = c++;
    } while (i != end);
}

GCC 还有另一个循环优化标志:

-ftree-loop-optimize
Perform loop optimizations on trees. This flag is enabled by default at -O and higher.

因此,-O 选项可以对最内层循环进行简单的循环优化,包括对具有固定迭代次数的循环进行完整的循环展开(剥离)。 (感谢医生向我指出这一点。)

关于c++ - 现代编译器能否展开使用开始和结束迭代器表示的 `for` 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11529006/

相关文章:

c++ - 从字符串中删除逗号

c++ - 这是标准库错误还是我的错误?

c++ - 具有用户定义函数的输出 vector

gcc - 禁用 GCC 中特定循环的展开

metaprogramming - 循环展开?在 Julia 中使用元编程

c - Loop unrolling and its effects on pipelining and CPE(有解法,但不懂)

c++ - 有没有办法在 vector 常数时间的中间插入一些东西

c++ - 按值调用时的隐式转换和多态性

c++ - 有异常的 Windows 并发运行时任务调度

c++ - 使用 istream_iterator 范围构造时无法访问 vector