最初に#pragma omp simd
ディレクティブの効果を調査したところ、単純な for ループのベクトル化に関連する、説明できない動作に遭遇しました。次のコード サンプルは、-O3ディレクティブが適用され、x86 アーキテクチャを使用している場合、この優れたコンパイラ エクスプローラーでテストできます。
次の観察の背後にある論理を説明してくれる人はいますか?
#include <stdint.h>
void test(uint8_t* out, uint8_t const* in, uint32_t length)
{
unsigned const l1 = (length * 32)/32; // This is vectorized
unsigned const l2 = (length / 32)*32; // This is not vectorized
unsigned const l3 = (length << 5)>>5; // This is vectorized
unsigned const l4 = (length >> 5)<<5; // This is not vectorized
unsigned const l5 = length -length%32; // This is not vectorized
unsigned const l6 = length & ~(32 -1); // This is not vectorized
for (unsigned i = 0; i<l1 /*pick your choice*/; ++i)
{
out[i] = in[i*2];
}
}
私が困惑しているのは、l1 と l3 の両方が 32 の倍数であることが保証されていないにもかかわらず、ベクトル化されたコードを生成することです。他のすべての長さはベクトル化されたコードを生成しませんが、32 の倍数にする必要があります。これには理由がありますか?
余談ですが、#pragma omp simd ディレクティブを使用しても、実際には何も変わりません。
編集: さらに調査した結果、インデックス タイプが size_t の場合 (境界操作も必要ない場合)、動作の違いはなくなります。これは、ベクトル化されたコードが生成されることを意味します。
#include <stdint.h>
#include <string>
void test(uint8_t* out, uint8_t const* in, size_t length)
{
for (size_t i = 0; i<length; ++i)
{
out[i] = in[i*2];
}
}
ループのベクトル化がインデックスの種類に大きく依存する理由を誰かが知っているなら、もっと知りたいです!
Edit2、Mark Lakata のおかげで、実際には O3 が必要です