インテル® Fortran コンパイラー 16.0 ユーザー・リファレンス・ガイド

ユーザー指示または SIMD ベクトル化

ユーザー指示または SIMD ベクトル化は、OpenMP* 並列化が自動並列化を補足するように、自動ベクトル化を補足します。下記の図でこの関係を示します。ユーザー指示によるベクトル化は SIMD (Single-Instruction, Multiple-Data) 機能として実装され、SIMD ベクトル化と呼ばれます。

SIMD ベクトル化機能は、インテル製マイクロプロセッサーおよび互換マイクロプロセッサーの両方で利用可能です。ベクトル化により呼び出されるライブラリー・ルーチンは、互換マイクロプロセッサーよりもインテル製マイクロプロセッサーにおいてより優れたパフォーマンスが得られる可能性があります。また、ベクトル化は、/arch (Windows*)、-m (Linux* および OS X*)、[Q]x などの特定のオプションによる影響を受けます。

次の図は、ハードウェアのベクトル化機能を活用するベクトル化コードを生成するためのさまざまなアプローチの中で、SIMD ベクトル化がどこに位置付けされているかを示しています。SIMD ベクトル化を用いて記述されたプログラムは、自動ベクトル化ヒントを使用して記述されたものと似ています。SIMD ベクトル化を使用すると、ベクトル化コードの取得に必要なコードの変更を最小限にすることができます。

SIMD ベクトル化は !DIR$ SIMD 宣言子を使用してループをベクトル化します。ループにこの宣言子を追加して、ループがベクトル化されるように再コンパイルしなければなりません ([Q]simd オプションがデフォルトで有効になります)。

不明なデータ依存性の距離 "X" のために、コンパイラーが自動でループをベクトル化しない Fortran の例ついて考えてみます。自動ベクトル化ヒント !DIR$ IVDEP でデータ依存性のアサーションを追加してループをベクトル化するかどうかをコンパイラーに判断させるか、または !DIR$ SIMD を使ってループのベクトル化を強制実行することができます。

!DIR$ SIMD なしの例

[D:/simd] cat example1.f 
subroutine add(A, N, X) 
integer N, X 
real    A(N) 
DO I=X+1, N
  A(I) = A(I) + A(I-X) 
ENDDO 
end
[D:/simd] ifort example1.f -nologo -Qvec-report2 
  D:\simd\example1.f(6): (列 9) リマーク: ループはベクトル化されませんでした: ベクトル依存関係が存在しています。

!DIR$ SIMD ありの例

[D:/simd] cat example1.f 
subroutine add(A, N, X) 
integer N, X 
real    A(N) 
!DIR$ SIMD 
DO I=X+1, N
  A(I) = A(I) + A(I-X) 
ENDDO 
end
[D:/simd] ifort example1.f -nologo -Qvec-report2 -Qsimd 
  D:\simd\example1.f(7): (列 9) リマーク: ループがベクトル化されました。

SIMD 宣言子と自動ベクトル化ヒントの主な違いは、SIMD 宣言子では、コンパイラーはループをベクトル化できない場合に警告を発行します。自動ベクトル化ヒントでは、!DIR$ VECTOR ALWAYS ヒントを使用した場合でも、実際のベクトル化はコンパイラーの判断にまかせられます。

SIMD 宣言子にはオプション節があり、コンパイラーにベクトル化の方法を指示できます。コンパイラーが正しいベクトル化コードを生成するための十分な情報を得られるように、これらの節を適切に使用してください。節についての詳細は、!DIR$ SIMD の説明を参照してください。

追加のセマンティクス

!DIR$ SIMD 宣言子の使用に関して、次の点に注意してください。

vector 宣言の使用

次のユーザー定義関数 foo() を使用してシリアル計算とベクトル計算を比較するプログラムの Fortran サンプルコードについて考えてみます。

このセクションで示すコード例はすべて Windows* の Fortran のみが対象です。

ユーザー定義関数がベクトル化しない例

!! ファイル: simdmain.f90 
program simdtest 
! 外部ファイルのベクトル関数をテストします。
implicit none
 interface
   integer function foo(a, b)
   integer a, b
   end function foo
 end interface
 
 integer, parameter :: M = 48, N = 64
 
  integer  i, j
  integer, dimension(M,N) :: a1  
  integer, dimension(M,N) :: a2
  integer, dimension(M,N) :: s_a3
  integer, dimension(M,N) :: v_a3 
logical :: err_flag = .false. 
 
! 配列用の乱数を計算します。
do j = 1, N
  do i = 1, M
   a1(i,j) = rand() * M
   a2(i,j) = rand() * M
  end do
 end do
 
! シリアル結果を計算します。
do j = 1, N 
!dir$ novector 
  do i = 1, M
   s_a3(i,j) = foo(a1(i,j), a2(i,j))
  end do
 end do
 
! ベクトル結果を計算します。
do j = 1, N 
   do i = 1, M
    v_a3(i,j) = foo(a1(i,j), a2(i,j))
   end do
  end do
 
! シリアル結果とベクトル結果を比較します。
do j = 1, N 
  do i = 1, M
   if (s_a3(i,j) .ne. v_a3(i,j)) then
    err_flag = .true. 
    print *, s_a3(i, j), v_a3(i,j)
   end if
  end do 
 end do
 if (err_flag .eq. .true.) then
  write(*,*) "FAILED"
   else
  write(*,*) "PASSED"
 end if 
end program
 
!! ファイル: vecfoo.f90 
integer function foo(a, b)
 implicit none
 integer, intent(in) :: a, b
  foo = a - b 
end function 
[49 C:/temp] ifort -Qvec-report simdmain.f90 vecfoo.f90 simdmain.f90 vecfoo.f90 
  C:\temp\simdmain.f90(3): (列 3) リマーク: ループはベクトル化されませんでした: ベクトル依存関係が存在しています。C:\temp\vecfoo.f90(3): (列 3) リマーク: 関数はベクトル化されませんでした。

上記のコードをコンパイルすると、この呼び出しで foo() がインライン展開されていない限り、自動ベクトル化はこの関数が何をするか分からないため、foo() 関数を含むループは自動ベクトル化されません。

関数呼び出しがインライン展開されていない場合は、!DIR$ attributes vector::function-name-list 宣言を使用して、ループと foo() 関数をベクトル化できます。vector 宣言を関数宣言に追加して、コードを再コンパイルするだけです。これで、ループと関数はベクトル化されます。

vector 宣言のあるユーザー定義関数を持つループが自動ベクトル化する例

!! ファイル: simdmain.f90 
program simdtest 
! 外部ファイルのベクトル関数をテストします。
implicit none
 interface
   integer function foo(a, b) 
!dir$ attributes vector :: foo
   integer a, b
   end function foo
 end interface
 
 integer, parameter :: M = 48, N = 64
 
  integer  i, j
  integer, dimension(M,N) :: a1  
  integer, dimension(M,N) :: a2
  integer, dimension(M,N) :: s_a3
  integer, dimension(M,N) :: v_a3 
logical :: err_flag = .false. 
 
! 配列用の乱数を計算します。
do j = 1, N
  do i = 1, M
   a1(i,j) = rand() * M
   a2(i,j) = rand() * M
  end do
 end do
 
! シリアル結果を計算します。
do j = 1, N 
!dir$ novector 
  do i = 1, M
   s_a3(i,j) = foo(a1(i,j), a2(i,j))
  end do
 end do
 
! ベクトル結果を計算します。
do j = 1, N 
   do i = 1, M
    v_a3(i,j) = foo(a1(i,j), a2(i,j))
   end do
  end do
 
! シリアル結果とベクトル結果を比較します。
do j = 1, N 
  do i = 1, M
   if (s_a3(i,j) .ne. v_a3(i,j)) then
    err_flag = .true. 
    print *, s_a3(i, j), v_a3(i,j)
   end if
  end do 
 end do
 if (err_flag .eq. .true.) then
  write(*,*) "FAILED"
   else
  write(*,*) "PASSED"
 end if 
end program
 
!! ファイル: vecfoo.f90 
integer function foo(a, b) 
!dir$ attributes vector :: foo
 implicit none
 integer, intent(in) :: a, b
  foo = a - b 
end function 
[49 C:/temp] ifort -Qvec-report simdmain.f90 vecfoo.f90 simdmain.f90 vecfoo.f90 
  C:\temp\simdmain.f90(3): (列 3) リマーク: ループがベクトル化されました。C:\temp\vecfoo.f90(3): (列 3) リマーク: 関数がベクトル化されました。

vector 宣言の使用に関する制約

ベクトル化は、ハードウェアとソースコードのスタイルという 2 つの主な要因により制約されます。vector 宣言を使用する場合、使用できない機能は次のとおりです。

仮パラメーターは次のデータ型でなければなりません。

関連情報