値が範囲に入っているかどうかを比較する時、絶対値で比較したい場合はたまにありますね。
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 について書きます。