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に続く

Trackback

only 1 comment untill now

  1. 自動ベクトル化はどれくらい使い物になるか(その2)

    その1の続き 要素の並べ替え(正確にはアンパック)を行う場合はどうでしょうか。 UtVideo では packed フォーマットと planar フォーマットの変換でこの処理が出てきます。 とりあえず簡単…

Add your comment now