qemu/tests/tcg/s390x/vfminmax.c
<<
>>
Prefs
   1#define _GNU_SOURCE
   2#include <fenv.h>
   3#include <stdbool.h>
   4#include <stdio.h>
   5#include <string.h>
   6
   7/*
   8 * vfmin/vfmax instruction execution.
   9 */
  10#define VFMIN 0xEE
  11#define VFMAX 0xEF
  12
  13extern char insn[6];
  14asm(".pushsection .rwx,\"awx\",@progbits\n"
  15    ".globl insn\n"
  16    /* e7 89 a0 00 2e ef */
  17    "insn: vfmaxsb %v24,%v25,%v26,0\n"
  18    ".popsection\n");
  19
  20static void vfminmax(unsigned int op,
  21                     unsigned int m4, unsigned int m5, unsigned int m6,
  22                     void *v1, const void *v2, const void *v3)
  23{
  24   insn[3] = (m6 << 4) | m5;
  25   insn[4] = (m4 << 4) | 0x0e;
  26   insn[5] = op;
  27
  28    asm("vl %%v25,%[v2]\n"
  29        "vl %%v26,%[v3]\n"
  30        "ex 0,%[insn]\n"
  31        "vst %%v24,%[v1]\n"
  32        : [v1] "=m" (*(char (*)[16])v1)
  33        : [v2] "m" (*(char (*)[16])v2)
  34        , [v3] "m" (*(char (*)[16])v3)
  35        , [insn] "m"(insn)
  36        : "v24", "v25", "v26");
  37}
  38
  39/*
  40 * Floating-point value classes.
  41 */
  42#define N_FORMATS 3
  43#define N_SIGNED_CLASSES 8
  44static const size_t float_sizes[N_FORMATS] = {
  45    /* M4 == 2: short    */ 4,
  46    /* M4 == 3: long     */ 8,
  47    /* M4 == 4: extended */ 16,
  48};
  49static const size_t e_bits[N_FORMATS] = {
  50    /* M4 == 2: short    */ 8,
  51    /* M4 == 3: long     */ 11,
  52    /* M4 == 4: extended */ 15,
  53};
  54static const unsigned char signed_floats[N_FORMATS][N_SIGNED_CLASSES][2][16] = {
  55    /* M4 == 2: short */
  56    {
  57        /* -inf */ {{0xff, 0x80, 0x00, 0x00},
  58                    {0xff, 0x80, 0x00, 0x00}},
  59        /* -Fn */  {{0xc2, 0x28, 0x00, 0x00},
  60                    {0xc2, 0x29, 0x00, 0x00}},
  61        /* -0 */   {{0x80, 0x00, 0x00, 0x00},
  62                    {0x80, 0x00, 0x00, 0x00}},
  63        /* +0 */   {{0x00, 0x00, 0x00, 0x00},
  64                    {0x00, 0x00, 0x00, 0x00}},
  65        /* +Fn */  {{0x42, 0x28, 0x00, 0x00},
  66                    {0x42, 0x2a, 0x00, 0x00}},
  67        /* +inf */ {{0x7f, 0x80, 0x00, 0x00},
  68                    {0x7f, 0x80, 0x00, 0x00}},
  69        /* QNaN */ {{0x7f, 0xff, 0xff, 0xff},
  70                    {0x7f, 0xff, 0xff, 0xfe}},
  71        /* SNaN */ {{0x7f, 0xbf, 0xff, 0xff},
  72                    {0x7f, 0xbf, 0xff, 0xfd}},
  73    },
  74
  75    /* M4 == 3: long */
  76    {
  77        /* -inf */ {{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  78                    {0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  79        /* -Fn */  {{0xc0, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  80                    {0xc0, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  81        /* -0 */   {{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  82                    {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  83        /* +0 */   {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  84                    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  85        /* +Fn */  {{0x40, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  86                    {0x40, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  87        /* +inf */ {{0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  88                    {0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  89        /* QNaN */ {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  90                    {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}},
  91        /* SNaN */ {{0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  92                    {0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd}},
  93    },
  94
  95    /* M4 == 4: extended */
  96    {
  97        /* -inf */ {{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  98                    {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  99        /* -Fn */  {{0xc0, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
 100                    {0xc0, 0x04, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
 101        /* -0 */   {{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
 102                    {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
 103        /* +0 */   {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
 104                    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
 105        /* +Fn */  {{0x40, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
 106                    {0x40, 0x04, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
 107        /* +inf */ {{0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
 108                    {0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
 109        /* QNaN */ {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
 110                    {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}},
 111        /* SNaN */ {{0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
 112                    {0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd}},
 113    },
 114};
 115
 116/*
 117 * PoP tables as close to the original as possible.
 118 */
 119struct signed_test {
 120    int op;
 121    int m6;
 122    const char *m6_desc;
 123    const char *table[N_SIGNED_CLASSES][N_SIGNED_CLASSES];
 124} signed_tests[] = {
 125    {
 126        .op = VFMIN,
 127        .m6 = 0,
 128        .m6_desc = "IEEE MinNum",
 129        .table = {
 130             /*         -inf         -Fn          -0           +0           +Fn          +inf         QNaN         SNaN     */
 131            {/* -inf */ "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "Xi: T(b*)"},
 132            {/* -Fn  */ "T(b)",      "T(M(a,b))", "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "Xi: T(b*)"},
 133            {/* -0   */ "T(b)",      "T(b)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "Xi: T(b*)"},
 134            {/* +0   */ "T(b)",      "T(b)",      "T(b)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "Xi: T(b*)"},
 135            {/* +Fn  */ "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(M(a,b))", "T(a)",      "T(a)",      "Xi: T(b*)"},
 136            {/* +inf */ "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(a)",      "T(a)",      "Xi: T(b*)"},
 137            {/* QNaN */ "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(a)",      "Xi: T(b*)"},
 138            {/* SNaN */ "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)"},
 139        },
 140    },
 141    {
 142        .op = VFMIN,
 143        .m6 = 1,
 144        .m6_desc = "JAVA Math.Min()",
 145        .table = {
 146             /*         -inf         -Fn          -0           +0           +Fn          +inf         QNaN         SNaN     */
 147            {/* -inf */ "T(b)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(b)",      "Xi: T(b*)"},
 148            {/* -Fn  */ "T(b)",      "T(M(a,b))", "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(b)",      "Xi: T(b*)"},
 149            {/* -0   */ "T(b)",      "T(b)",      "T(b)",      "T(a)",      "T(a)",      "T(a)",      "T(b)",      "Xi: T(b*)"},
 150            {/* +0   */ "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(a)",      "T(a)",      "T(b)",      "Xi: T(b*)"},
 151            {/* +Fn  */ "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(M(a,b))", "T(a)",      "T(b)",      "Xi: T(b*)"},
 152            {/* +inf */ "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "Xi: T(b*)"},
 153            {/* QNaN */ "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "Xi: T(b*)"},
 154            {/* SNaN */ "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)"},
 155        },
 156    },
 157    {
 158        .op = VFMIN,
 159        .m6 = 2,
 160        .m6_desc = "C-style Min Macro",
 161        .table = {
 162             /*         -inf        -Fn          -0          +0          +Fn          +inf        QNaN        SNaN    */
 163            {/* -inf */ "T(b)",     "T(a)",      "T(a)",     "T(a)",     "T(a)",      "T(a)",     "Xi: T(b)", "Xi: T(b)"},
 164            {/* -Fn  */ "T(b)",     "T(M(a,b))", "T(a)",     "T(a)",     "T(a)",      "T(a)",     "Xi: T(b)", "Xi: T(b)"},
 165            {/* -0   */ "T(b)",     "T(b)",      "T(b)",     "T(b)",     "T(a)",      "T(a)",     "Xi: T(b)", "Xi: T(b)"},
 166            {/* +0   */ "T(b)",     "T(b)",      "T(b)",     "T(b)",     "T(a)",      "T(a)",     "Xi: T(b)", "Xi: T(b)"},
 167            {/* +Fn  */ "T(b)",     "T(b)",      "T(b)",     "T(b)",     "T(M(a,b))", "T(a)",     "Xi: T(b)", "Xi: T(b)"},
 168            {/* +inf */ "T(b)",     "T(b)",      "T(b)",     "T(b)",     "T(b)",      "T(a)",     "Xi: T(b)", "Xi: T(b)"},
 169            {/* QNaN */ "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(b)", "Xi: T(b)"},
 170            {/* SNaN */ "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(b)", "Xi: T(b)"},
 171        },
 172    },
 173    {
 174        .op = VFMIN,
 175        .m6 = 3,
 176        .m6_desc = "C++ algorithm.min()",
 177        .table = {
 178             /*         -inf        -Fn          -0          +0          +Fn          +inf        QNaN        SNaN    */
 179            {/* -inf */ "T(b)",     "T(a)",      "T(a)",     "T(a)",     "T(a)",      "T(a)",     "Xi: T(a)", "Xi: T(a)"},
 180            {/* -Fn  */ "T(b)",     "T(M(a,b))", "T(a)",     "T(a)",     "T(a)",      "T(a)",     "Xi: T(a)", "Xi: T(a)"},
 181            {/* -0   */ "T(b)",     "T(b)",      "T(a)",     "T(a)",     "T(a)",      "T(a)",     "Xi: T(a)", "Xi: T(a)"},
 182            {/* +0   */ "T(b)",     "T(b)",      "T(a)",     "T(a)",     "T(a)",      "T(a)",     "Xi: T(a)", "Xi: T(a)"},
 183            {/* +Fn  */ "T(b)",     "T(b)",      "T(b)",     "T(b)",     "T(M(a,b))", "T(a)",     "Xi: T(a)", "Xi: T(a)"},
 184            {/* +inf */ "T(b)",     "T(b)",      "T(b)",     "T(b)",     "T(b)",      "T(a)",     "Xi: T(a)", "Xi: T(a)"},
 185            {/* QNaN */ "Xi: T(a)", "Xi: T(a)",  "Xi: T(a)", "Xi: T(a)", "Xi: T(a)",  "Xi: T(a)", "Xi: T(a)", "Xi: T(a)"},
 186            {/* SNaN */ "Xi: T(a)", "Xi: T(a)",  "Xi: T(a)", "Xi: T(a)", "Xi: T(a)",  "Xi: T(a)", "Xi: T(a)", "Xi: T(a)"},
 187        },
 188    },
 189    {
 190        .op = VFMIN,
 191        .m6 = 4,
 192        .m6_desc = "fmin()",
 193        .table = {
 194             /*         -inf        -Fn          -0          +0          +Fn          +inf        QNaN        SNaN    */
 195            {/* -inf */ "T(a)",     "T(a)",      "T(a)",     "T(a)",     "T(a)",      "T(a)",     "T(a)",     "Xi: T(a)"},
 196            {/* -Fn  */ "T(b)",     "T(M(a,b))", "T(a)",     "T(a)",     "T(a)",      "T(a)",     "T(a)",     "Xi: T(a)"},
 197            {/* -0   */ "T(b)",     "T(b)",      "T(a)",     "T(a)",     "T(a)",      "T(a)",     "T(a)",     "Xi: T(a)"},
 198            {/* +0   */ "T(b)",     "T(b)",      "T(b)",     "T(a)",     "T(a)",      "T(a)",     "T(a)",     "Xi: T(a)"},
 199            {/* +Fn  */ "T(b)",     "T(b)",      "T(b)",     "T(b)",     "T(M(a,b))", "T(a)",     "T(a)",     "Xi: T(a)"},
 200            {/* +inf */ "T(b)",     "T(b)",      "T(b)",     "T(b)",     "T(b)",      "T(a)",     "T(a)",     "Xi: T(a)"},
 201            {/* QNaN */ "T(b)",     "T(b)",      "T(b)",     "T(b)",     "T(b)",      "T(b)",     "T(a)",     "Xi: T(a)"},
 202            {/* SNaN */ "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(a)", "Xi: T(a)"},
 203        },
 204    },
 205
 206    {
 207        .op = VFMAX,
 208        .m6 = 0,
 209        .m6_desc = "IEEE MaxNum",
 210        .table = {
 211             /*         -inf         -Fn          -0           +0           +Fn          +inf         QNaN         SNaN     */
 212            {/* -inf */ "T(a)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(a)",      "Xi: T(b*)"},
 213            {/* -Fn  */ "T(a)",      "T(M(a,b))", "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(a)",      "Xi: T(b*)"},
 214            {/* -0   */ "T(a)",      "T(a)",      "T(a)",      "T(b)",      "T(b)",      "T(b)",      "T(a)",      "Xi: T(b*)"},
 215            {/* +0   */ "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(b)",      "T(b)",      "T(a)",      "Xi: T(b*)"},
 216            {/* +Fn  */ "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(M(a,b))", "T(b)",      "T(a)",      "Xi: T(b*)"},
 217            {/* +inf */ "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "Xi: T(b*)"},
 218            {/* QNaN */ "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(a)",      "Xi: T(b*)"},
 219            {/* SNaN */ "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)"},
 220        },
 221    },
 222    {
 223        .op = VFMAX,
 224        .m6 = 1,
 225        .m6_desc = "JAVA Math.Max()",
 226        .table = {
 227             /*         -inf         -Fn          -0           +0           +Fn          +inf         QNaN         SNaN     */
 228            {/* -inf */ "T(a)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "Xi: T(b*)"},
 229            {/* -Fn  */ "T(a)",      "T(M(a,b))", "T(b)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "Xi: T(b*)"},
 230            {/* -0   */ "T(a)",      "T(a)",      "T(a)",      "T(b)",      "T(b)",      "T(b)",      "T(b)",      "Xi: T(b*)"},
 231            {/* +0   */ "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(b)",      "T(b)",      "T(b)",      "Xi: T(b*)"},
 232            {/* +Fn  */ "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(M(a,b))", "T(b)",      "T(b)",      "Xi: T(b*)"},
 233            {/* +inf */ "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(b)",      "Xi: T(b*)"},
 234            {/* QNaN */ "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "T(a)",      "Xi: T(b*)"},
 235            {/* SNaN */ "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)"},
 236        },
 237    },
 238    {
 239        .op = VFMAX,
 240        .m6 = 2,
 241        .m6_desc = "C-style Max Macro",
 242        .table = {
 243             /*         -inf        -Fn          -0          +0          +Fn          +inf        QNaN        SNaN    */
 244            {/* -inf */ "T(b)",     "T(b)",      "T(b)",     "T(b)",     "T(b)",      "T(b)",     "Xi: T(b)", "Xi: T(b)"},
 245            {/* -Fn  */ "T(a)",     "T(M(a,b))", "T(b)",     "T(b)",     "T(b)",      "T(b)",     "Xi: T(b)", "Xi: T(b)"},
 246            {/* -0   */ "T(a)",     "T(a)",      "T(b)",     "T(b)",     "T(b)",      "T(b)",     "Xi: T(b)", "Xi: T(b)"},
 247            {/* +0   */ "T(a)",     "T(a)",      "T(b)",     "T(b)",     "T(b)",      "T(b)",     "Xi: T(b)", "Xi: T(b)"},
 248            {/* +Fn  */ "T(a)",     "T(a)",      "T(a)",     "T(a)",     "T(M(a,b))", "T(b)",     "Xi: T(b)", "Xi: T(b)"},
 249            {/* +inf */ "T(a)",     "T(a)",      "T(a)",     "T(a)",     "T(a)",      "T(b)",     "Xi: T(b)", "Xi: T(b)"},
 250            {/* QNaN */ "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(b)", "Xi: T(b)"},
 251            {/* SNaN */ "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(b)", "Xi: T(b)"},
 252        },
 253    },
 254    {
 255        .op = VFMAX,
 256        .m6 = 3,
 257        .m6_desc = "C++ algorithm.max()",
 258        .table = {
 259             /*         -inf        -Fn          -0          +0          +Fn          +inf        QNaN        SNaN    */
 260            {/* -inf */ "T(a)",     "T(b)",      "T(b)",     "T(b)",     "T(b)",      "T(b)",     "Xi: T(a)", "Xi: T(a)"},
 261            {/* -Fn  */ "T(a)",     "T(M(a,b))", "T(b)",     "T(b)",     "T(b)",      "T(b)",     "Xi: T(a)", "Xi: T(a)"},
 262            {/* -0   */ "T(a)",     "T(a)",      "T(a)",     "T(a)",     "T(b)",      "T(b)",     "Xi: T(a)", "Xi: T(a)"},
 263            {/* +0   */ "T(a)",     "T(a)",      "T(a)",     "T(a)",     "T(b)",      "T(b)",     "Xi: T(a)", "Xi: T(a)"},
 264            {/* +Fn  */ "T(a)",     "T(a)",      "T(a)",     "T(a)",     "T(M(a,b))", "T(b)",     "Xi: T(a)", "Xi: T(a)"},
 265            {/* +inf */ "T(a)",     "T(a)",      "T(a)",     "T(a)",     "T(a)",      "T(a)",     "Xi: T(a)", "Xi: T(a)"},
 266            {/* QNaN */ "Xi: T(a)", "Xi: T(a)",  "Xi: T(a)", "Xi: T(a)", "Xi: T(a)",  "Xi: T(a)", "Xi: T(a)", "Xi: T(a)"},
 267            {/* SNaN */ "Xi: T(a)", "Xi: T(a)",  "Xi: T(a)", "Xi: T(a)", "Xi: T(a)",  "Xi: T(a)", "Xi: T(a)", "Xi: T(a)"},
 268        },
 269    },
 270    {
 271        .op = VFMAX,
 272        .m6 = 4,
 273        .m6_desc = "fmax()",
 274        .table = {
 275             /*         -inf        -Fn          -0          +0          +Fn          +inf        QNaN        SNaN    */
 276            {/* -inf */ "T(a)",     "T(b)",      "T(b)",     "T(b)",     "T(b)",      "T(b)",     "T(a)",     "Xi: T(a)"},
 277            {/* -Fn  */ "T(a)",     "T(M(a,b))", "T(b)",     "T(b)",     "T(b)",      "T(b)",     "T(a)",     "Xi: T(a)"},
 278            {/* -0   */ "T(a)",     "T(a)",      "T(a)",     "T(b)",     "T(b)",      "T(b)",     "T(a)",     "Xi: T(a)"},
 279            {/* +0   */ "T(a)",     "T(a)",      "T(a)",     "T(a)",     "T(b)",      "T(b)",     "T(a)",     "Xi: T(a)"},
 280            {/* +Fn  */ "T(a)",     "T(a)",      "T(a)",     "T(a)",     "T(M(a,b))", "T(b)",     "T(a)",     "Xi: T(a)"},
 281            {/* +inf */ "T(a)",     "T(a)",      "T(a)",     "T(a)",     "T(a)",      "T(a)",     "T(a)",     "Xi: T(a)"},
 282            {/* QNaN */ "T(b)",     "T(b)",      "T(b)",     "T(b)",     "T(b)",      "T(b)",     "T(a)",     "Xi: T(a)"},
 283            {/* SNaN */ "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(b)", "Xi: T(b)",  "Xi: T(b)", "Xi: T(a)", "Xi: T(a)"},
 284        },
 285    },
 286};
 287
 288static void dump_v(FILE *f, const void *v, size_t n)
 289{
 290    for (int i = 0; i < n; i++) {
 291        fprintf(f, "%02x", ((const unsigned char *)v)[i]);
 292    }
 293}
 294
 295static int signed_test(struct signed_test *test, int m4, int m5,
 296                       const void *v1_exp, bool xi_exp,
 297                       const void *v2, const void *v3)
 298{
 299    size_t n = (m5 & 8) ? float_sizes[m4 - 2] : 16;
 300    char v1[16];
 301    bool xi;
 302
 303    feclearexcept(FE_ALL_EXCEPT);
 304    vfminmax(test->op, m4, m5, test->m6, v1, v2, v3);
 305    xi = fetestexcept(FE_ALL_EXCEPT) == FE_INVALID;
 306
 307    if (memcmp(v1, v1_exp, n) != 0 || xi != xi_exp) {
 308        fprintf(stderr, "[  FAILED  ] %s ", test->m6_desc);
 309        dump_v(stderr, v2, n);
 310        fprintf(stderr, ", ");
 311        dump_v(stderr, v3, n);
 312        fprintf(stderr, ", %d, %d, %d: actual=", m4, m5, test->m6);
 313        dump_v(stderr, v1, n);
 314        fprintf(stderr, "/%d, expected=", (int)xi);
 315        dump_v(stderr, v1_exp, n);
 316        fprintf(stderr, "/%d\n", (int)xi_exp);
 317        return 1;
 318    }
 319
 320    return 0;
 321}
 322
 323static void snan_to_qnan(char *v, int m4)
 324{
 325    size_t bit = 1 + e_bits[m4 - 2];
 326    v[bit / 8] |= 1 << (7 - (bit % 8));
 327}
 328
 329int main(void)
 330{
 331    int ret = 0;
 332    size_t i;
 333
 334    for (i = 0; i < sizeof(signed_tests) / sizeof(signed_tests[0]); i++) {
 335        struct signed_test *test = &signed_tests[i];
 336        int m4;
 337
 338        for (m4 = 2; m4 <= 4; m4++) {
 339            const unsigned char (*floats)[2][16] = signed_floats[m4 - 2];
 340            size_t float_size = float_sizes[m4 - 2];
 341            int m5;
 342
 343            for (m5 = 0; m5 <= 8; m5 += 8) {
 344                char v1_exp[16], v2[16], v3[16];
 345                bool xi_exp = false;
 346                int pos = 0;
 347                int i2;
 348
 349                for (i2 = 0; i2 < N_SIGNED_CLASSES * 2; i2++) {
 350                    int i3;
 351
 352                    for (i3 = 0; i3 < N_SIGNED_CLASSES * 2; i3++) {
 353                        const char *spec = test->table[i2 / 2][i3 / 2];
 354
 355                        memcpy(&v2[pos], floats[i2 / 2][i2 % 2], float_size);
 356                        memcpy(&v3[pos], floats[i3 / 2][i3 % 2], float_size);
 357                        if (strcmp(spec, "T(a)") == 0 ||
 358                            strcmp(spec, "Xi: T(a)") == 0) {
 359                            memcpy(&v1_exp[pos], &v2[pos], float_size);
 360                        } else if (strcmp(spec, "T(b)") == 0 ||
 361                                   strcmp(spec, "Xi: T(b)") == 0) {
 362                            memcpy(&v1_exp[pos], &v3[pos], float_size);
 363                        } else if (strcmp(spec, "Xi: T(a*)") == 0) {
 364                            memcpy(&v1_exp[pos], &v2[pos], float_size);
 365                            snan_to_qnan(&v1_exp[pos], m4);
 366                        } else if (strcmp(spec, "Xi: T(b*)") == 0) {
 367                            memcpy(&v1_exp[pos], &v3[pos], float_size);
 368                            snan_to_qnan(&v1_exp[pos], m4);
 369                        } else if (strcmp(spec, "T(M(a,b))") == 0) {
 370                            /*
 371                             * Comparing floats is risky, since the compiler
 372                             * might generate the same instruction that we are
 373                             * testing. Compare ints instead. This works,
 374                             * because we get here only for +-Fn, and the
 375                             * corresponding test values have identical
 376                             * exponents.
 377                             */
 378                            int v2_int = *(int *)&v2[pos];
 379                            int v3_int = *(int *)&v3[pos];
 380
 381                            if ((v2_int < v3_int) ==
 382                                ((test->op == VFMIN) != (v2_int < 0))) {
 383                                memcpy(&v1_exp[pos], &v2[pos], float_size);
 384                            } else {
 385                                memcpy(&v1_exp[pos], &v3[pos], float_size);
 386                            }
 387                        } else {
 388                            fprintf(stderr, "Unexpected spec: %s\n", spec);
 389                            return 1;
 390                        }
 391                        xi_exp |= spec[0] == 'X';
 392                        pos += float_size;
 393
 394                        if ((m5 & 8) || pos == 16) {
 395                            ret |= signed_test(test, m4, m5,
 396                                               v1_exp, xi_exp, v2, v3);
 397                            pos = 0;
 398                            xi_exp = false;
 399                        }
 400                    }
 401                }
 402
 403                if (pos != 0) {
 404                    ret |= signed_test(test, m4, m5, v1_exp, xi_exp, v2, v3);
 405                }
 406            }
 407        }
 408    }
 409
 410    return ret;
 411}
 412