一次元配列へスカラー値を加算します。C++、x86アセンブラー、AVX2、AVX-512の例を示します。
C++で記述
#include <iostream> #include <iomanip> using namespace std; // print template <typename T> void printData(const size_t length, T a[]) { cout.setf(ios::right); for (int i = 0 ; i < length; i++) cout << fixed << setprecision(0) << setw(3) << a[i] << ","; cout << "\b \b" << endl; } //main int main(void) { int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; const size_t units = sizeof(a)/sizeof(a[0]); int c[units]; const int f = 2; for(int i = 0; i < units; i++) { c[i] = a[i] + f; } cout << " f = " << f << endl; printData(units, (int*)a); printData(units, (int*)c); return 0; }
実行結果
cl /EHsc addSisd.cpp
C:\>addSisd
f = 2
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
x86アセンブラーで記述
まず、C++のコードを示します。
#include <iostream> #include <iomanip> using namespace std; extern "C" void asmCode(const int *a, const int f, int *c); // print template <typename T> void printData(const size_t length, T a[]) { cout.setf(ios::right); for (int i = 0 ; i < length; i++) cout << fixed << setprecision(0) << setw(3) << a[i] << ","; cout << "\b \b" << endl; } //main int main(void) { int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; const size_t units = sizeof(a)/sizeof(a[0]); int c[units]; const int f = 2; //for(int i = 0; i < units; i++) //{ // c[i] = a[i] + f; //} asmCode(a, f, c); cout << " f = " << f << endl; printData(units, (int*)a); printData(units, (int*)c); return 0; }
「asmCode(a, f, c);」をコメントアウトし、上の行を生かせばC++単独で動作させることがでる。
アセンブリのコードを示します。
_TEXT segment public asmCode align 16 ;------------------------------------------------------------------- ; rcx: a, rdx: f, r8: c ; ; a: int[] ; b: int ; c: int[] ; ;--- ;for(int i = 0; i < units; i++) ;{ ; c[i] = a[i] + f; ;} ; ;------------------------------------------------------------------- asmCode proc ;__m256i t = _mm256_set1_epi32(f); mov r9, rcx mov rcx, 16 mov edx, 2 loop_f: mov eax, dword ptr[r9] add eax, edx mov dword ptr [r8], eax lea r8, qword ptr[r8+4] lea r9, qword ptr[r9+4] loop loop_f ret asmCode endp _TEXT ends end
AVX2で記述
まず、C++のコードを示します。
#include <immintrin.h> #include "../common256.h" extern "C" void asmCode(const int *a, const int f, int *c); //main int main(void) { __m256i a = _mm256_set_epi32(1, 2, 3, 4, 5, 6, 7, 8); __m256i c; const int f = 2; //__m256i t = _mm256_set1_epi32(f); //__m256i c = _mm256_add_epi32(a, t); asmCode((int*)&a, f, (int*)&c); cout << " f = " << f << endl; printData((int*)&a); printData((int*)&c); return 0; }
「asmCode((int*)&a, f, (int*)&c);」をコメントアウトし、上の行を生かせばC++単独で動作させることがでる。その際はintrinsicが使われる。
アセンブリのコードを示します。
_TEXT segment public asmCode align 16 ;------------------------------------------------------------------- ; rcx: a, rdx: f, r8: c ; ; a: aligned ; b: int ; c: aligned ; ;--- ;__m256i a = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); ;const int f = 2; ; ;__m256i t = _mm256_set1_epi32(f); ;__m256i c = _mm256_add_epi32(a, t); ;------------------------------------------------------------------- asmCode proc ;__m256i t = _mm256_set1_epi32(f); movd xmm1, edx vbroadcastss ymm1, xmm1 ;__m256i c = _mm256_add_epi32(a, t); vpaddd ymm0, ymm1, ymmword ptr [rcx] ; zmm1 = a + t vmovaps ymmword ptr [r8], ymm0 ; store ymm0 to c ret asmCode endp _TEXT ends end
AVX-512で記述
まず、C++のコードを示します。
#include <immintrin.h> #include "../common.h" extern "C" void asmCode(const int *a, const int f, int *c); //main int main(void) { __m512i a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); __m512i c; const int f = 2; //__m512i t = _mm512_set1_epi32(f); //__m512i c = _mm512_add_epi32(a, t); asmCode((int*)&a, f, (int*)&c); cout << " f = " << f << endl; printData((int*)&a); printData((int*)&c); return 0; }
「asmCode(a, f, c);」をコメントアウトし、上の行を生かせばC++単独で動作させることがでる。その際はintrinsicが使われる。
アセンブリのコードを示します。
_TEXT segment public asmCode align 16 ;------------------------------------------------------------------- ; rcx: a, rdx: f, r8: c ; ; a: aligned ; b: int ; c: aligned ; ;--- ;__m512i a = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); ;const int f = 2; ; ;__m512i t = _mm512_set1_epi32(f); ;__m512i c = _mm512_add_epi32(a, t); ; ;------------------------------------------------------------------- asmCode proc ;__m512i t = _mm512_set1_epi32(f); vpbroadcastd zmm1, edx ; zmm1 = t ;__m512i c = _mm512_add_epi32(a, t); vpaddd zmm0, zmm1, zmmword ptr [rcx] ; zmm1 = a + t vmovdqa32 zmmword ptr [r8], zmm0 ; store zmm0 to c ret asmCode endp _TEXT ends end