微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用GCC / ICC在C ++中使用模板参数进行可移植循环展开

如何解决使用GCC / ICC在C ++中使用模板参数进行可移植循环展开

我正在研究一个high-performance parallel computational fluid dynamics code,它涉及许多轻量级循环,因此,如果所有重要的循环都完全展开,则性能大约提高30%。

使用编译器指令,可以很容易地在固定数量的循环中完成此操作:#pragma GCC unroll (16)被我所针对的两个编译器Intel C ++编译器ICC和GCC识别,而#pragma unroll (16)被GCC不幸地忽略了。例如,我还可以将模板参数或预处理器指令用作限制,例如ICC(similar to what you can do with nvcc

template <int N>
// ...
#pragma unroll (N)
for (int i = 0; i < N; ++i) {
// ...
}

#define N 16

#pragma unroll (N)
for (int i = 0; i < N; ++i) {
// ...
}

使用ICC进行编译时,使用-Wall -w2 -w3不会引发任何错误或警告,而使用GCC(#pragma GCC unroll (N))的互补语法-Wall -pedantic会在Ubuntu 18.04的GCC 9.2.1 20191102中引发错误

error: ‘#pragma GCC unroll’ requires an assignment-expression that evaluates to a non-negative integral constant less than 65535
#pragma GCC unroll (N)

有人知道一种方法,可以使基于模板参数的循环展开与编译器指令一起以可移植的方式工作(至少与GCC和ICC一起使用)吗?实际上,我只需要整个循环的完全展开,因此#pragma GCC unroll (all)之类的东西已经对我有很大帮助。

我知道unroll loops with template meta-programming存在或多或少的复杂策略,但是在我的应用程序中,循环可能是嵌套的,并且可能包含更复杂的循环体,我觉得这种策略会使我的代码过于复杂并降低可读性。

解决方法

遗憾的是,目前似乎没有一致的方法。

我最后使用了预处理器指令,该指令决定是否根据模板参数进行解压缩(如果可以使用Intel C ++编译器ICC的话),或者使用常数因子对其他所有编译器进行解压缩(例如GCC)。可以将此思想与user dfri的注释结合起来,并通过相应的预处理器指令禁用push / pop选项。这是一个小例子:

template <int N>
void exampleContainingLoop()
{
    #if defined(__ICC) || defined(__ICL)
    #pragma unroll (N)
    #else
    #pragma GCC unroll (4)
    #endif
    for (int i = 0; i < N; ++i)
    {
        // ...
    }
    
    return;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。