3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

条件によって処理を変えたいとき、maskで挙動を変えるのも良いですが、maskしても命令は実行されるので、SIMD内で全部条件結果が同じだった場合は、片方の処理が完全に無駄になります。

そういうときは、SIMDの処理中でも、if文で分岐したくなります。

kortestw は、マスクレジスタの値をeflagsに持ってくる命令です。
ふたつのマスクレジスタに含まれる全32bitをorして、0ならeflags の ZFが立ちます。ふたつのマスクレジスタをorした16bitが0xffffだった場合、CFが立ちます。

これで、ベクタの全要素で条件が成立しないような場合を分岐で飛ばすことができるようになります。

#include <immintrin.h>
#include <stdio.h>

float in0[16] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
float in1[16] = {1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1};
float in2[16] = {0};
int a;

static void
testc(float *p)
{
    __m512 v0 = _mm512_loadu_ps(p);
    __m512 v1 = _mm512_set1_ps(1);

    __mmask16 test0 = _mm512_cmp_ps_mask(v0, v1, _CMP_EQ_OQ);

    if (_mm512_kortestc(test0,test0)) {
        puts("全部1だよ.");
    } else {
        puts("1じゃないのが有るよ.");
    }
}

static void
testz(float *p)
{
    __m512 v0 = _mm512_loadu_ps(p);
    __m512 v1 = _mm512_set1_ps(1);

    __mmask16 test0 = _mm512_cmp_ps_mask(v0, v1, _CMP_EQ_OQ);

    if (_mm512_kortestz(test0,test0)) {
        puts("1が無いよ.");
    } else {
        puts("1が有るよ.");
    }
}

void
test(float *p)
{
    for (int i=0; i<16; i++) {
        printf("%.0f, ", p[i]);
    }
    puts("");
    testc(p);
    testz(p);
}

int
main()
{
    test(in0);

    test(in1);

    test(in2);

}
 $ ./sde  -- ./a.out  
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
全部1だよ.
1が有るよ.
1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 
1じゃないのが有るよ.
1が有るよ.
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
1じゃないのが有るよ.
1が無いよ.

ただ、GCCだと、この例のように両オペランドが同じ値だと、普通に or, cmp 命令になってしまうようです。

#include <immintrin.h>
#include <stdio.h>

float in0[16] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
float in1[16] = {1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1};
float in2[16] = {0};
int a;

int
main()
{
    __m512 v = _mm512_set1_ps(1);
    __m512 v0 = _mm512_loadu_ps(in0);
    __m512 v1 = _mm512_loadu_ps(in1);

    __mmask16 test0 = _mm512_cmp_ps_mask(v, v0, _CMP_EQ_OQ);
    __mmask16 test1 = _mm512_cmp_ps_mask(v, v1, _CMP_EQ_OQ);

    if (_mm512_kortestc(test0,test1)) {
        a = 10;
    }
}

これだとkortestwになるようですが…

どっちが良いのかは実機がどうなってるかわからないとなんとも言えないですね。(まあGCCのコスト判定作ってるの多分intelの人だからGCCが正しいと思うけど)

明日は @tanakmura が vfpclassps について書きます。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?