浮動小数値の種類に対応する変換ができます。
区別できる種類は、
- qNaN
- sNaN
- zero
- +1.0
- -inf
- +inf
- 負数
- 正数
の7個です。これがsrc2で指定されます。
どういう変換をするかを、src3 で決めます変換の種類は、16種類で、4bitで識別できるので、8種類の値を32bit値のテーブル引きで求めます
- qNaN -> 0-3bit
- sNaN -> 4-7bit
- zero -> 8-11bit
- +1.0 -> 12->15bit
- -inf -> 16->19bit
- +inf -> 20->23bit
- 負数 -> 24->27bit
- 正数 -> 28->31bit
この選んだ4bitで、結果が決まります。
以下Intel(R) Architecture Instruction Set Extensions Programming Reference(https://software.intel.com/en-us/intel-architecture-instruction-set-extensions-programming-reference ) からコピペ。
- 0000: dest[31:0] = dest[31:0]; ; preserve content of DEST
- 0001: dest[31:0] = tsrc[31:0]; ; pass through src1 normal input value, denormal as zero
- 0010: dest[31:0] = QNaN(tsrc[31:0]);
- 0011: dest[31:0] = QNAN_Indefinite;
- 0100: dest[31:0] = -INF;
- 0101: dest[31:0] = +INF;
- 0110: dest[31:0] = tsrc.sign? –INF : +INF;
- 0111: dest[31:0] = -0;
- 1000: dest[31:0] = +0;
- 1001: dest[31:0] = -1;
- 1010: dest[31:0] = +1;
- 1011: dest[31:0] = 1⁄2;
- 1100: dest[31:0] = 90.0;
- 1101: dest[31:0] = PI/2;
- 1110: dest[31:0] = MAX_FLOAT;
- 1111: dest[31:0] = -MAX_FLOAT;
#include <immintrin.h>
#include <stdio.h>
#include <math.h>
float data1[16] = {100.0f,
200.0f,
300.0f,
400.0f,
500.0f};
float data2[16] = {0, -0, 1, -1};
#define GEN_ENTRY(a,b,c,d, e,f,g,h) \
(((a)<<0) | ((b)<<4) | ((c)<<8) | ((d)<<12) | \
((e)<<16) | ((f)<<20) | ((g)<<24) | ((h)<<28))
int data3[16] = {
GEN_ENTRY(0, /* qnan */
1, /* snan */
14, /* zero */
15, /* 1.0 */
4, /* -inf */
5, /* +inf */
13, /* -val */
12), /* +val */
};
float data4[16];
float
test(float v)
{
__m512 a = _mm512_loadu_ps(data1);
__m512 b = _mm512_set1_ps(v);
__m512i c = _mm512_loadu_si512(data3);
__m512 out;
out = _mm512_fixupimm_ps(a, b, c, 7);
_mm512_storeu_ps(data4, out);
printf("%10f -> %8.4f\n", v, data4[0]);
}
int
main()
{
test(+1.0f);
test(+2.0f);
test(-1.0f);
test(-2.0f);
test(+0.0f);
test(-0.0f);
test(1.0f/0.0f);
test(-nanf(""));
test(+nanf(""));
test(-nanf(""));
test(+nanf(""));
}
$ ./sde -- ./a.out
1.000000 -> -340282346638528859811704183484516925440.0000
2.000000 -> 90.0000
-1.000000 -> 1.5708
-2.000000 -> 1.5708
0.000000 -> 340282346638528859811704183484516925440.0000
-0.000000 -> 340282346638528859811704183484516925440.0000
inf -> inf
-nan -> 100.0000
nan -> 100.0000
-nan -> 100.0000
nan -> 100.0000
明日は @tanakmura が vpternlogd について書きます。