【问题标题】:clang: Force loop unroll for specific loopclang:强制循环展开特定循环
【发布时间】:2013-03-07 15:27:00
【问题描述】:

有没有办法告诉 clang 展开特定循环?


在谷歌上搜索答案会给我命令行选项,这些选项会影响整个编译器,而不是单个循环。


GCC 有一个类似的问题 --- Tell gcc to specifically unroll a loop --- 但那里提供的答案不适用于 clang。

那里建议的选项 1:

#pragma GCC optimize ("unroll-loops")

似乎被默默地忽略了。其实

#pragma GCC akjhdfkjahsdkjfhskdfhd

也会被默默忽略。

选项 2:

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

导致警告:

warning: unknown attribute 'optimize' ignored [-Wattributes]

更新

joshuanapoli 提供了一个很好的解决方案,如何在不创建循环的情况下通过模板元编程和 C++11 进行迭代。该构造将在编译时解析,从而导致重复内联的主体。虽然它不完全是问题的答案,但它基本上实现了相同的目标。

这就是我接受答案的原因。但是,如果您碰巧知道如何使用标准 C 循环(forwhile)并强制展开它 - 请与我们分享知识!

【问题讨论】:

  • 通常情况下,编译器非常清楚何时适合展开循环以及何时不适合。您试图解决哪些不适用的特殊情况?
  • 它可能不会强制展开,但__attribute__ ((hot)) 可能值得一试。
  • @MatsPetersson 我想明确衡量循环展开的好处。手写的unroll其实把代码提速了3倍,但是编译器没有搞清楚。

标签: c++ c clang


【解决方案1】:

对于 C++ 程序,您可以在该语言中展开循环。您无需弄清楚特定于编译器的选项。例如,

#include <cstddef>
#include <iostream>

template<std::size_t N, typename FunctionType, std::size_t I>
class repeat_t
{
public:
  repeat_t(FunctionType function) : function_(function) {}
  FunctionType operator()()
  {
    function_(I);
    return repeat_t<N,FunctionType,I+1>(function_)();
  }
private:
  FunctionType function_;
};

template<std::size_t N, typename FunctionType>
class repeat_t<N,FunctionType,N>
{
public:
  repeat_t(FunctionType function) : function_(function) {}
  FunctionType operator()() { return function_; }
private:
  FunctionType function_;
};

template<std::size_t N, typename FunctionType>
repeat_t<N,FunctionType,0> repeat(FunctionType function)
{
  return repeat_t<N,FunctionType,0>(function);
}

void loop_function(std::size_t index)
{
  std::cout << index << std::endl;
}

int main(int argc, char** argv)
{
  repeat<10>(loop_function)();
  return 0;
}

复杂循环函数示例

template<typename T, T V1>
struct sum_t
{
  sum_t(T v2) : v2_(v2) {}
  void operator()(std::size_t) { v2_ += V1; }
  T result() const { return v2_; }
private:
  T v2_;
};

int main(int argc, char* argv[])
{
  typedef sum_t<int,2> add_two;
  std::cout << repeat<4>(add_two(3))().result() << std::endl;
  return 0;
}
// output is 11 (3+2+2+2+2)

使用闭包代替显式函数对象

int main(int argc, char* argv[])
{
  int accumulator{3};
  repeat<4>( [&](std::size_t)
  {
    accumulator += 2;
  })();
  std::cout << accumulator << std::endl;
}

【讨论】:

  • 是的,这是我的默认方式。但由于我已经在一个模板中,其中包含需要进入loop_function 的参数,它变得非常丑陋......这就是为什么我正在寻找一些更“令人赏心悦目”的解决方案:)
  • 如果你可以使用 C++11,那么你可以使用 constexpr 函数来减少模板语法噪音。
  • 如果只有一些参数是 constexpr/template 而一些是常规动态参数...或者?
  • 您应该能够在概念上和语法上将循环“算法”与循环函数分开。我添加了一个带有模板和变量参数的复杂循环函数对象的示例。
  • 什么能保证所有编译器实际上都内联函数,而不是生成嵌套函数调用调用?我认为您还应该使用always_inlineforce_inline,具体取决于您使用的编译器。
【解决方案2】:

Clang 最近获得了循环展开编译指示(例如#pragma unroll),可用于指定完全/部分展开。有关详细信息,请参阅http://clang.llvm.org/docs/AttributeReference.html#pragma-unroll-pragma-nounroll

【讨论】:

    【解决方案3】:

    尽管它可能很严重,但您可以将所述 for 循环隔离到它自己的文件中,单独编译它(使用它自己的命令行标志)。

    relevant, but currently unanswered clang-developers question

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-08
      • 2019-09-18
      • 2014-11-10
      • 1970-01-01
      • 2011-07-23
      • 1970-01-01
      • 1970-01-01
      • 2016-08-03
      相关资源
      最近更新 更多