自动做到这一点并不容易。 DO CONCURRENT 构造具有 forall-header,这意味着它可以接受多个循环、索引变量定义和掩码。基本上,你需要更换:
DO CONCURRENT([<type-spec> :: ]<forall-triplet-spec 1>, <forall-triplet-spec 2>, ...[, <scalar-mask-expression>])
<block>
END DO
与:
[BLOCK
<type-spec> :: <indexes>]
!$omp parallel do
DO <forall-triplet-spec 1>
DO <forall-triplet-spec 2>
...
[IF (<scalar-mask-expression>) THEN]
<block>
[END IF]
...
END DO
END DO
!$omp end parallel do
[END BLOCK]
(方括号中的内容是可选的,基于 forall-header 中相应部分的存在)
请注意,这不如使用<iters 1>*<iters 2>*... 独立迭代并行一个大循环有效,而这是DO CONCURRENT 所期望的。另请注意,forall-header 允许 type-spec 允许在标题内定义循环索引,并且您需要将整个事物包围在 BLOCK ... END BLOCK 构造中以保留语义。您还需要检查 scalar-mask-expr 是否存在于 forall-header 的末尾,如果存在,您还应该将 IF ... END IF 放在最里面循环。
如果您在 DO CONCURRENT 的主体内只有数组分配,您也可以将其转换为 FORALL 并使用 workshare OpenMP 指令。这会比上面的要容易得多。
DO CONCURRENT <forall-header>
<block>
END DO
会变成:
!$omp parallel workshare
FORALL <forall-header>
<block>
END FORALL
!$omp end parallel workshare
鉴于以上所有情况,我能想到的唯一系统方法是系统地检查您的源代码,搜索DO CONCURRENT和系统地 根据 forall-header 和循环体的内容,将其替换为上述转换后的结构之一。
编辑: 目前不鼓励使用 OpenMP workshare 指令。事实证明,至少英特尔 Fortran 编译器和 GCC 在编译期间通过用 OpenMP single 指令将它们包围在 OpenMP workshare 指令内部序列化 FORALL 语句和构造,这不会带来任何加速。其他编译器可能会以不同的方式实现它,但如果要实现可移植性能,最好避免使用它。