!DIR$ IVDEP 指令指示编译器忽略其在循环中找到的部分或全部对数组引用的循环附带依赖性,使编译器能够在其他循环之间执行各种循环优化,例如微向量化、分布、软件流水化,否则这些优化将无法实现。当用户知道这些依赖性无关紧要或者实际上永远不会发生时,可以使用该指令。
例如:
DO I = 1, N A(V(I)) = A(V(I)) + C(I) END DO
在此循环中,存在几处对 A(V(I)) 的循环附带依赖性,因为 V(I) 可能会将重复值传递给索引 A,对循环重新排序可能会产生不同的结果。但如果已知 V 仅包含不同的值,则可以安全地对循环进行重新排序,并且可以使用 IVDEP 指令来实现优化。
可以使用 —xivdep 编译器选项(请参见–xivdep[=p])来禁用或确定 IVDEP 指令的解释。
IVDEP 指令的某些传统解释仅能断言不存在向后循环附带依赖性。Fortran 编译器的缺省值是 —xivdep=loop,表示 IVDEP 指令断言不存在假定的循环依赖性。
下面的示例解释向后依赖性与向前依赖性。
do i = 1, n ! BACKWARD LOOP-CARRIED DEPENDENCE ... = a(i-1) ! S1 a(i) = ... ! S2 end do
do i = 1, n ! FORWARD LOOP-CARRIED DEPENDENCE a(i) = ... ! S3 ... = a(i-1) ! S4 end do
第一个循环有一个从 S2 到 S1 的向后循环附带依赖性,第二个循环中有一个从 S3 到 S4 的向前循环附带依赖性。由于第二个循环只有一个向前依赖性,因此可以安全地进行分布和/或微向量化,而第一个循环则不能。
下面是使用缺省值 -xivdep=loop 的情况下使用 IVDEP 的示例:
integer target a(n) integer, pointer :: p(:), q(:) !DIR$ IVDEP do i = 1, n p(i) = q(i) a(i) = a(i-1) end do
p(i) 与 q(i) 之间以及 p(i) 与 a(*) 之间的假定依赖性将被忽略,而 a(i) 与 a(i-1) 之间的显式依赖性则不被忽略。该循环可分割为两个循环,所生成的 p(i) = q(i) 循环可以实现微向量化。
IVDEP 指令应用于紧随其后的 DO 循环。在指令与循环之间不允许有其他代码。!DIR$ IVDEP 也可以应用于数组赋值语句 FORALL 或 WHERE 结构。如果特定的循环存在多个指令(例如 IVDEP 和 UNROLL),编译器会尽可能服从所有指令。