次のように定義された関数があります
inline void vec_add(__m512d &v3, const __m512d &v1, const __m512d &v2) {
v3 = _mm512_add_pd(v1, v2);
}
(これ__m512d
は、インテル MIC アーキテクチャーの SIMD レジスターへのネイティブ データ型マッピングです)
この関数はかなり短く、頻繁に呼び出されるため、呼び出しのたびにインライン化する必要があります。しかし、Intel のコンパイラは、オプション-inline-forceinline
と-O3
オプションを使用した後でも、この関数をインライン化することに消極的です。コンパイル中に「Forceinline が呼び出されませんでした ...」と報告されます。タイプなど、コンパイラー固有の機能を使用する必要があるため__m512d
、Intel コンパイラーが唯一の選択肢です。
より詳しい情報:
ファイル構造は非常に単純です。関数は、別のファイルに含まれるvec_add
ヘッダー ファイルで定義されます。関数はループ内で繰り返し呼び出されるだけで、関数ポインターは関係ありません。コードの簡略化されたバージョンは次のようになりますmic.h
test.cc
vec_add
test.cc
for (int i = 0; i < LENGTH; i += 8) {
// a, b, c are arrays of doubles, and each SIMD register can hold 8 doubles
__mm512d va = _mm512_load_pd(a + i); // load SIMD register from memory
__mm512d vb = _mm512_load_pd(b + i); // ditto
__mm512d vc;
vec_add(vc, va, vb); // store SIMD register to memory
_mm512_store_pd(c + i, vc);
}
、 、コンパイラ オプションなど__attribute__((always_inline))
、あらゆる種類のヒントを試しましたが、まだ機能していません。__forceinline
-inline-forceinline
完全なコード
関連するすべてのコードを簡略化された形式にまとめました。Intel コンパイラをお持ちの場合は、試すことができます。オプション-Winline
を使用して、インライン レポートを表示し、-inline-forceinline
インライン化を強制します。
#include <stdio.h>
#include <stdlib.h>
#include <immintrin.h>
#define LEN (1<<20)
__attribute((target(mic)))
inline void vec_add(__m512d &v3, const __m512d &v1, const __m512d &v2) {
v3 = _mm512_add_pd(v1, v2);
}
int main() {
#pragma offload target(mic)
{
double *a = (double*)_mm_malloc(LEN*sizeof(double), 64);
double *b = (double*)_mm_malloc(LEN*sizeof(double), 64);
double *c = (double*)_mm_malloc(LEN*sizeof(double), 64);
for (int i = 0; i < LEN; i++) {
a[i] = (double)rand()/RAND_MAX;
b[i] = (double)rand()/RAND_MAX;
}
for (int i = 0; i < LEN; i += 8) {
__m512d va = _mm512_load_pd(a + i);
__m512d vb = _mm512_load_pd(b + i);
__m512d vc;
vec_add(vc, va, vb);
_mm512_store_pd(c + i, vc);
}
_mm_free(a);
_mm_free(b);
_mm_free(c);
}
}
構成
- コンパイラ: インテル コンパイラ(ICC) 14.0.2
- コンパイル オプション:
-O3 -inline-forceinline -Winline
この関数をインライン化できない理由がわかりましたか? 結局、どうすればインライン化できますか(マクロにはなりたくありません)?