6月
10
その1の続き
要素の並べ替え(正確にはアンパック)を行う場合はどうでしょうか。 UtVideo では packed フォーマットと planar フォーマットの変換でこの処理が出てきます。
とりあえず簡単な例として以下のようなコードで試します。
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[0] = *a++; dst[1] = *b++; dst += 2; } } 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] movdqu xmm1, [r8] movdqa xmm2, xmm0 puhpcklbw xmm0, xmm1 punpckhbw xmm2, xmm1 movdqu [rcx], xmm0 movdqu [rcx+16], xmm2
で、実際にやってみると、
D:\>cl /c /O2 /Qvec-report:2 autovec2.cpp Microsoft(R) C/C++ Optimizing Compiler Version 19.10.25019 for x64 Copyright (C) Microsoft Corporation. All rights reserved. autovec2.cpp --- 分析関数: void __cdecl foo<float>(float * __ptr64 __restrict,float const * __ptr64 __restrict,float const * __ptr64 __restrict,unsigned __int64) d:\autovec2.cpp(4) : info C5002: ループはベクター化されません。理由: '1300' --- 分析関数: void __cdecl foo<char>(char * __ptr64 __restrict,char const * __ptr64 __restrict,char const * __ptr64 __restrict,unsigned __int64) d:\autovec2.cpp(4) : info C5002: ループはベクター化されません。理由: '1300' --- 分析関数: void __cdecl foo<int>(int * __ptr64 __restrict,int const * __ptr64 __restrict,int const * __ptr64 __restrict,unsigned __int64) d:\autovec2.cpp(4) : info C5002: ループはベクター化されません。理由: '1300' --- 分析関数: void __cdecl foo<short>(short * __ptr64 __restrict,short const * __ptr64 __restrict,short const * __ptr64 __restrict,unsigned __int64) d:\autovec2.cpp(4) : info C5002: ループはベクター化されません。理由: '1300'
えっ
ちなみに理由コードの一覧はここにあって、1300 は「ループ本体に計算がまったくかほとんど含まれていません。」だそうです。確かに計算はしてないけどさ。
さて、最近の Visual C++ には Clang/C2 という「別のコンパイラ」が含まれているので、こっちも試してみましょう。
D:\>"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\ClangC2\14.10.25903\bin\HostX64\clang.exe" --version clang with Microsoft CodeGen version 3.8.0 Provided as - is without support C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\ClangC2\14.10.25903\bin\HostX64\x64\c2.dll version 19.10.25903.0 Target: x86_64-pc-windows-msvc Thread model: posix InstalledDir: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\ClangC2\14.10.25903\bin\HostX64 D:\>"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\ClangC2\14.10.25903\bin\HostX64\clang.exe" -c -O2 -msse4.1 autovec2.cpp
umezawa@selene /cygdrive/d $ objdump -d -M intel autovec2.o autovec2.o: ファイル形式 pe-bigobj-x86-64 セクション .text$mn の逆アセンブル: 0000000000000000 <??$foo@D@@YAXPEIADPEIBD1_K@Z>: 0: 4d 85 c9 test r9,r9 3: 74 29 je 2e <??$foo@D@@YAXPEIADPEIBD1_K@Z+0x2e> 5: 66 66 66 0f 1f 84 00 data16 data16 nop WORD PTR [rax+rax*1+0x0] c: 00 00 00 00 10: 0f b6 02 movzx eax,BYTE PTR [rdx] 13: 48 8d 52 01 lea rdx,[rdx+0x1] 17: 88 01 mov BYTE PTR [rcx],al 19: 48 8d 49 02 lea rcx,[rcx+0x2] 1d: 41 0f b6 00 movzx eax,BYTE PTR [r8] 21: 4d 8d 40 01 lea r8,[r8+0x1] 25: 88 41 ff mov BYTE PTR [rcx-0x1],al 28: 49 83 e9 01 sub r9,0x1 2c: 75 e2 jne 10 <??$foo@D@@YAXPEIADPEIBD1_K@Z+0x10> 2e: c3 ret
ダメじゃねぇか
wandbox 上でいろいろ試した結果、 GCC の場合は少なくともだいぶ前のバージョンである 4.4.7 の時点で -O3 オプション(より正確には -ftree-vectorize オプション。-O2 ではダメ)を付けた時にベクトル化してくれますが、 Clang だと最新版である 4.0.0 でようやくベクトル化してくれるようです。
一番簡単な2要素のケースですらこれでは先が思いやられます。
その3に続く
自動ベクトル化はどれくらい使い物になるか(その3)
その2の続き 2要素の場合で既にかなり残念なことになっていますが、3要素の場合はどうでしょうか。 template<typename T> void foo(T* __restrict dst, const T* __restrict a, const T* __restrict b, const T* __r…