OpenACC:如何为使用宏定义的循环添加OpenACC编译制导指令
问题原因
你遇到的编译错误是因为宏展开后,#pragma acc parallel loop collapse(2) 后面紧跟的不是for循环语句,而是_ibeg = g->lbeg[IDIR]; _iend = g->lend[IDIR];两个赋值语句。OpenACC规范要求loop前缀的编译指示必须直接修饰紧跟在它后面的for/do/while循环,放在赋值语句前编译器无法识别。
另外注意你现有J_LOOP宏存在笔误:循环条件写为i <= _jend,实际应该是j <= _jend,如果不修正即使编译通过运行结果也会出错。
保留现有宏的可行解决方案
不需要修改宏定义,只需要调整编译指示的写法和位置即可:
// 首先声明边界变量为并行区域私有,按需添加数据 copy/copyin/copyout 子句 #pragma acc parallel private(_ibeg, _iend, _jbeg, _jend) copyin(g[0:1], Uc[0:J_MAX][0:I_MAX]) copyout(U0[0:J_MAX][0:I_MAX]) { // 预先执行宏里的边界计算逻辑,避免放在loop指示后面 _ibeg = g->lbeg[IDIR]; _iend = g->lend[IDIR]; _jbeg = g->lbeg[JDIR]; _jend = g->lend[JDIR]; // 这里直接用你原来的宏调用即可,展开后loop指示后直接跟for循环,符合语法要求 #pragma acc loop collapse(2) I_LOOP(g, i){ J_LOOP(g, j){ U0[j][i] = Uc[j][i]; }} }
这种写法的原理是把宏内的边界计算提前放到并行区域的普通执行逻辑里,loop指示后面紧跟的就是宏展开后的for循环,完全符合OpenACC语法要求,同时你原来的宏定义不需要做任何修改。
可选优化(如果后续允许微调宏)
如果后续可以调整宏定义,更优雅的写法是把边界计算放到for循环的初始化语句中,这样直接在宏调用前加loop指示也不会报错,修改后的宏示例:
#define I_LOOP(g, i) for (int _ibeg = g->lbeg[IDIR], _iend = g->lend[IDIR], i = _ibeg; i <= _iend; i++) #define J_LOOP(g, j) for (int _jbeg = g->lbeg[JDIR], _jend = g->lend[JDIR], j = _jbeg; j <= _jend; j++)
修改后你原来的写法就可以直接运行,不需要提前计算边界。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

