10

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


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


GCC 有一个类似的问题 ---告诉 gcc 专门展开一个循环--- 但那里提供的答案不适用于 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 循环 ( for, while) 并强制展开它 - 请与我们分享知识!

4

3 回答 3

9

对于 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;
}
于 2013-03-07T15:54:28.087 回答
3

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

于 2015-09-13T18:53:27.153 回答
2

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

相关但目前尚未回答的 clang-developers 问题

于 2013-03-07T16:30:03.780 回答