9

最初に#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 が必要です

4

2 に答える 2

1

最適化とベクトル化を混同していると思います。コンパイラ エクスプローラーを使用し、x86 用に -O2 を設定しましたが、「ベクトル化」された例はありません。

ここはl1

test(unsigned char*, unsigned char const*, unsigned int):
        xorl    %eax, %eax
        andl    $134217727, %edx
        je      .L1
.L5:
        movzbl  (%rsi,%rax,2), %ecx
        movb    %cl, (%rdi,%rax)
        addq    $1, %rax
        cmpl    %eax, %edx
        ja      .L5
.L1:
        rep ret

ここはl2

test(unsigned char*, unsigned char const*, unsigned int):
        andl    $-32, %edx
        je      .L1
        leal    -1(%rdx), %eax
        leaq    1(%rdi,%rax), %rcx
        xorl    %eax, %eax
.L4:
        movl    %eax, %edx
        addq    $1, %rdi
        addl    $2, %eax
        movzbl  (%rsi,%rdx), %edx
        movb    %dl, -1(%rdi)
        cmpq    %rcx, %rdi
        jne     .L4
.L1:
        rep ret

これは驚くべきことではありません。これは、ロード インデックスがストア インデックスと同じではない、本質的に「収集」ロード操作であるためです。x86 では、ギャザー/スキャッターはサポートされていません。AVX2 と AVX512 でのみ導入され、選択されていません。

少し長いコードは、符号付き/符号なしの問題を処理していますが、ベクトル化は行われていません。

于 2016-07-15T23:05:14.053 に答える