6月
09
intrinsic に移行したけどそれもやっぱり辛いよね、という話を以前書きましたが、ではコンパイラによる自動ベクトル化はどれくらい使い物になるのかを調べようと思います。
動機が「UtVideo で使いたい」であるため、まずは Visual C++ 2017 で試します。 Visual C++ 自体にはオブジェクトファイルの中身を逆アセンブルするツールが(たぶん)無いため、Cygwin の objdump を使います。ターゲットは x64 & SSE4.2 です。
1つ目は以下のようなコード。どこからどう見てもベクトル化されることが期待されます。
template<typename T> void foo(T* __restrict dst, const T* __restrict a, const T* __restrict b, size_t n) { for (size_t i = 0; i < n; ++i) *dst++ = *a++ + *b++; } template void foo<float>(float* __restrict, const float* __restrict, const float* __restrict, size_t); template void foo<int>(int* __restrict, const int* __restrict, const int* __restrict, size_t); template void foo<short>(short* __restrict, const short* __restrict, const short* __restrict, size_t); template void foo<char>(char* __restrict, const char* __restrict, const char* __restrict, size_t);
ちなみに char の場合の模範解答はこんな感じ。
movdqu xmm0, [rdx] paddb xmm0, [r8] movdqu [rcx], xmm0
で、結果。
D:\>cl /c /O2 /Qvec-report:2 autovec1.cpp Microsoft(R) C/C++ Optimizing Compiler Version 19.10.25019 for x64 Copyright (C) Microsoft Corporation. All rights reserved. autovec1.cpp --- 分析関数: void __cdecl foo<float>(float * __ptr64 __restrict,float const * _ _ptr64 __restrict,float const * __ptr64 __restrict,unsigned __int64) d:\autovec1.cpp(4) : info C5001: ループがベクター化されています --- 分析関数: void __cdecl foo<short>(short * __ptr64 __restrict,short const * _ _ptr64 __restrict,short const * __ptr64 __restrict,unsigned __int64) d:\autovec1.cpp(4) : info C5001: ループがベクター化されています --- 分析関数: void __cdecl foo<int>(int * __ptr64 __restrict,int const * __ptr64 __restrict,int const * __ptr64 __restrict,unsigned __int64) d:\autovec1.cpp(4) : info C5001: ループがベクター化されています --- 分析関数: void __cdecl foo<char>(char * __ptr64 __restrict,char const * __pt r64 __restrict,char const * __ptr64 __restrict,unsigned __int64) d:\autovec1.cpp(4) : info C5001: ループがベクター化されています
umezawa@selene /cygdrive/d $ objdump -d -M intel autovec1.obj autovec1.obj: ファイル形式 pe-x86-64 セクション .text$mn の逆アセンブル: 0000000000000000 <??$foo@D@@YAXPEIADPEIBD1_K@Z>: (略) 20: f3 41 0f 6f 00 movdqu xmm0,XMMWORD PTR [r8] 25: 48 83 c0 20 add rax,0x20 29: f3 0f 6f 0a movdqu xmm1,XMMWORD PTR [rdx] 2d: 66 0f fc c8 paddb xmm1,xmm0 31: f3 41 0f 6f 40 10 movdqu xmm0,XMMWORD PTR [r8+0x10] 37: 49 83 c0 20 add r8,0x20 3b: f3 0f 7f 09 movdqu XMMWORD PTR [rcx],xmm1 3f: f3 0f 6f 4a 10 movdqu xmm1,XMMWORD PTR [rdx+0x10] 44: 48 83 c2 20 add rdx,0x20 48: 66 0f fc c8 paddb xmm1,xmm0 4c: f3 0f 7f 49 10 movdqu XMMWORD PTR [rcx+0x10],xmm1 51: 48 83 c1 20 add rcx,0x20 55: 49 3b c2 cmp rax,r10 58: 72 c6 jb 20 <??$foo@D@@YAXPEIADPEIBD1_K@Z+0x20> (略)
長いのでバッサリ省略しますが、char 以外も同様の出力になっています。アンロールのオマケつき。paddb がメモリオペランドになっていないのが気になるところですが。
まあ、これぐらいはできて当然なので特に感動もありません。最適化オプションの指定が合ってるかどうかの確認ぐらいにはなります。
その2に続く
自動ベクトル化はどれくらい使い物になるか(その2)
その1の続き 要素の並べ替え(正確にはアンパック)を行う場合はどうでしょうか。 UtVideo では packed フォーマットと planar フォーマットの変換でこの処理が出てきます。 とりあえず簡単…
VCの逆アセンブルは
link /dump /disasm ○○.obj
もしくは
dumpbin /disasm ○○.obj
です。
おお、できました。ありがとうございます。