avx512
More than 3 years have passed since last update.

値が範囲に入っているかどうかを比較する時、絶対値で比較したい場合はたまにありますね。

rangeps は、符号を多少操作して min, max します。

即値4bitのうち2bitで、

  • min
  • max
  • 絶対値比較の min
  • 絶対値比較の max

が選べて、残り2bitで、結果の符号を、

  • src1 の符号
  • min,max 結果の符号
  • 符号クリア
  • 符号セット

が選べます。

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

float out[16];

static inline __attribute__((always_inline)) void
test(float a, float b, const int imm)
{
    __m512 v1 = _mm512_set1_ps(a);
    __m512 v2 = _mm512_set1_ps(b);
    __m512 v3;

    __asm__ __volatile__ ("vrangeps %[imm], %[src2], %[src1], %[dest]\n\t"
                          :[dest]"=v"(v3)
                          :[src1]"v"(v1),
                           [src2]"v"(v2),
                           [imm]"i"(imm)
        );

    _mm512_storeu_ps(out, v3);

    printf("src1=%4.0f, src2=%4.0f, cmp=%d, signsel=%d : result=%5.1f\n", a, b, (imm)&3, (imm>>2)&3, out[0]);
}

#define CMP_MIN 0
#define CMP_MAX 1
#define CMP_ABS_MIN 2
#define CMP_ABS_MAX 3

#define SIGNSEL_PRESERVE_SRC1 (0<<2)
#define SIGNSEL_PRESERVE_RESULT (1<<2)
#define SIGNSEL_SETZERO (2<<2)
#define SIGNSEL_SET1 (3<<2)

int
main()
{
    test(-2, 1, CMP_ABS_MIN|SIGNSEL_PRESERVE_SRC1);
    test(2, -1, CMP_ABS_MIN|SIGNSEL_PRESERVE_SRC1);
    test(2, -1, CMP_ABS_MIN|SIGNSEL_PRESERVE_SRC1);

    test(2, -1, CMP_MIN|SIGNSEL_PRESERVE_RESULT);

    test(-2,-2, CMP_MAX|SIGNSEL_SETZERO);
    test(2,2, CMP_MIN|SIGNSEL_SET1);
}
$ ./sde -skx -- ./a.out 
src1=  -2, src2=   1, cmp=2, signsel=0 : result= -1.0
src1=   2, src2=  -1, cmp=2, signsel=0 : result=  1.0
src1=   2, src2=  -1, cmp=2, signsel=0 : result=  1.0
src1=   2, src2=  -1, cmp=0, signsel=1 : result= -1.0
src1=  -2, src2=  -2, cmp=1, signsel=2 : result=  2.0
src1=   2, src2=   2, cmp=0, signsel=3 : result= -2.0

完全に浮動小数演算の気がしますが、何故か AVX-512DQ 拡張です。KNLでは動きません。

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