avx512
AVX-512Day 5

vfixupimmps

More than 3 years have passed since last update.

浮動小数値の種類に対応する変換ができます。

区別できる種類は、

  • 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 について書きます。