在遇到#pragma unroll
指令时,我们对nvcc的展开功能了解多少?它有多复杂?有没有人尝试过越来越复杂的循环结构来看看它放弃了什么?
例如,
#pragma unroll
for(int i = 0; i < constexpr_value; i++) { foo(i); }
肯定会展开(最多相当大的旅行次数,请参阅this answer)。怎么样:
#pragma unroll
for(int i = 0; i < runtime_variable_value and i < constexpr_value; i++) {
foo(i);
}
此处不知道循环行程计数,但它具有恒定的上限,并且可以执行循环的完全展开,并进行一些条件跳转。
然后,怎么样:
template <typename T>
constexpr T simple_min(const T& x, const T& y) { return x < y ? x : y; }
#pragma unroll
for(int i = 0; i < simple_min(runtime_variable_value, constexpr_value); i++) {
foo(i);
}
哪个应该编译成与上面相同的东西?
注意:如果您打算回答“进行自己的实验”,那么 - 我打算这样做,至少在我的例子中,如果没有人知道一般的答案,请查看PTX在这种情况下,我将部分回答这个问题。但我更喜欢一些更具权威性并且基于更广泛经验的东西。
答案 0 :(得分:2)
展开的规则非常简单 - 如果编译器不能将循环行程计数推导为整数常量值,它将不会自动展开循环。在这种情况下,它还会发出警告通知您。
如果您的代码具有非常量循环行程计数,您仍然可以通过在展开编译指示之后添加一个值大于1的整数常量表达式来强制编译器展开(即#pragma unroll 8
)
所有这一切都在documentation的相关部分中进行了非常清楚的讨论。