インテル® Fortran コンパイラー 14.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 のみが対象です。

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

!! file simdmain.f90 
program simdtest 
! Test vector function in external file.
 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.
 
! compute random numbers for arrays
 do j = 1, N
  do i = 1, M
   a1(i,j) = rand() * M
   a2(i,j) = rand() * M
  end do
 end do
 
 ! compute serial results
 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
 
 ! compute vector results
  do j = 1, N 
   do i = 1, M
    v_a3(i,j) = foo(a1(i,j), a2(i,j))
   end do
  end do
 
 ! compare serial and vector results
 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
 
!! file: 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 宣言のあるユーザー定義関数を持つループが自動ベクトル化するケース

!! file simdmain.f90 
program simdtest 
! Test vector function in external file.
 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.
 
! compute random numbers for arrays
 do j = 1, N
  do i = 1, M
   a1(i,j) = rand() * M
   a2(i,j) = rand() * M
  end do
 end do
 
 ! compute serial results
 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
 
 ! compute vector results
  do j = 1, N 
   do i = 1, M
    v_a3(i,j) = foo(a1(i,j), a2(i,j))
   end do
  end do
 
 ! compare serial and vector results
 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
 
!! file: 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 宣言を使用する場合、使用できない機能は次のとおりです。

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

関連情報


このヘルプトピックについてのフィードバックを送信