飽和算術演算を行う for ループがいくつかあります。例えば:
私の場合の飽和加算の実装は次のとおりです。
static void addsat(Vector &R, Vector &A, Vector &B)
{
int32_t a, b, r;
int32_t max_add;
int32_t min_add;
const int32_t SAT_VALUE = (1<<(16-1))-1;
const int32_t SAT_VALUE2 = (-SAT_VALUE - 1);
const int32_t sat_cond = (SAT_VALUE <= 0x7fffffff);
const uint32_t SAT = 0xffffffff >> 16;
for (int i=0; i<R.length; i++)
{
a = static_cast<uint32_t>(A.data[i]);
b = static_cast<uint32_t>(B.data[i]);
max_add = (int32_t)0x7fffffff - a;
min_add = (int32_t)0x80000000 - a;
r = (a>0 && b>max_add) ? 0x7fffffff : a + b;
r = (a<0 && b<min_add) ? 0x80000000 : a + b;
if ( sat_cond == 1)
{
std_max(r,r,SAT_VALUE2);
std_min(r,r,SAT_VALUE);
}
else
{
r = static_cast<uint16_t> (static_cast<int32_t> (r));
}
R.data[i] = static_cast<uint16_t>(r);
}
}
x86 には、このループの完璧な解決策となる可能性のある組み込みの paddsat があることがわかりました。コードは自動ベクトル化されますが、コードに従って複数の操作を組み合わせています。自動ベクトライザーがaddsat操作の一致を正しく検出するこのループを記述する最良の方法を知りたいです。
ベクトル構造は次のとおりです。
struct V {
static constexpr int length = 32;
unsigned short data[32];
};
使用するコンパイラは clang 3.8 で、コードは AVX2 Haswell x86-64 アーキテクチャ用にコンパイルされています。