g ++,基于范围和矢量化

时间:2013-05-22 09:36:55

标签: c++ c++11 g++ vectorization clang++

考虑以下基于C ++ 11循环的范围

for ( T k : j )
{
  ...
}

g++clang++优化标志可以加快编译代码的速度吗?

我不是在谈论任何for周期我只考虑这个新的C ++ 11结构。

2 个答案:

答案 0 :(得分:3)

GCC documentation about auto-vectorization未提及有关基于范围的for循环的任何内容。此外,它的代码归结为:

{
    auto && __range = range_expression ;
    for (auto __begin = begin_expr,
                __end = end_expr;
            __begin != __end; ++__begin) {
        range_declaration = *__begin;
        loop_statement
    }
}

因此,从技术上讲,任何有助于自动矢量化这种常规for结构的标志都应该自动矢量化类似的基于范围的for循环。我真的这样编译器只将基于范围的for循环转换为常规for循环,然后让自动向量化在这些旧循环上完成它的工作。这意味着在任何情况下都不需要标志来告诉编译器自动矢量化基于范围的for循环。


由于要求GCC的实现,这里是源代码中的相关注释,描述了基于范围的for循环的实际操作(如果你想拥有,你可以检查实现文件parser.c)看一下代码):

/* Converts a range-based for-statement into a normal
   for-statement, as per the definition.

      for (RANGE_DECL : RANGE_EXPR)
    BLOCK

   should be equivalent to:

      {
    auto &&__range = RANGE_EXPR;
    for (auto __begin = BEGIN_EXPR, end = END_EXPR;
          __begin != __end;
          ++__begin)
      {
          RANGE_DECL = *__begin;
          BLOCK
      }
      }

   If RANGE_EXPR is an array:
    BEGIN_EXPR = __range
    END_EXPR = __range + ARRAY_SIZE(__range)
   Else if RANGE_EXPR has a member 'begin' or 'end':
    BEGIN_EXPR = __range.begin()
    END_EXPR = __range.end()
   Else:
    BEGIN_EXPR = begin(__range)
    END_EXPR = end(__range);

   If __range has a member 'begin' but not 'end', or vice versa, we must
   still use the second alternative (it will surely fail, however).
   When calling begin()/end() in the third alternative we must use
   argument dependent lookup, but always considering 'std' as an associated
   namespace.  */

正如您所看到的,他们只做标准实际描述的内容。

答案 1 :(得分:3)

优化循环很少是为了优化实际的循环迭代代码(在这种情况下为for ( T k : j )),而是非常关于优化循环中的内容。

现在,因为在这种情况下这是...,所以不可能说,例如,展开循环是否有帮助,或者声明函数内联[或只是移动它们以便编译器可以看到它们并放置它们是内联的,使用自动矢量化,或者可能在循环中使用完全不同的算法。

上面段落中的示例更详细一点:

  1. 展开循环 - 基本上可以完成几个循环迭代而无需回到循环的开始。当循环内容非常小时,这是最有用的。有自动展开,编译器执行展开,或者您可以手动展开代码,只需在每个循环迭代中执行四个项目,然后在每个循环变量更新中逐步执行四个项目或在期间多次更新迭代器循环本身[但这当然意味着不使用基于范围的for循环]。
  2. 内联函数 - 编译器将采用(通常很小的)函数并将它们放入循环本身,而不是进行调用。这节省了处理器呼叫代码中的另一个地方并返回的时间。大多数编译器只针对编译期间编译器“可见”的函数执行此操作 - 因此源必须位于相同的源文件中,或者包含在编译的源文件中的头文件中。
  3. 自动矢量化 - 使用SSE,MMX或AVX指令在一条指令中处理多个数据项(例如,一条SSE指令可以在一条指令中向另外四条float添加四个float值。这比一次操作单个数据项更快(大多数时候,有时它没有任何好处,因为尝试组合不同的数据项然后整理计算完成时的内容会有额外的复杂性)。
  4. 选择不同的算法 - 通常有几种方法可以解决特定问题。根据你想要实现的目标,一个for循环[无论何种类型]可能不是首先正确的解决方案,或者循环内部的代码可能使用更聪明的方式来计算/重新排列/无论如何 - 达到你需要的结果。
  5. 但是...过于模糊,无法说出上述哪些解决方案可以改善您的代码。

相关问题