qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

vfminmax.c (22604B)


      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 
     13 extern char insn[6];
     14 asm(".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 
     20 static 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
     44 static const size_t float_sizes[N_FORMATS] = {
     45     /* M4 == 2: short    */ 4,
     46     /* M4 == 3: long     */ 8,
     47     /* M4 == 4: extended */ 16,
     48 };
     49 static const size_t e_bits[N_FORMATS] = {
     50     /* M4 == 2: short    */ 8,
     51     /* M4 == 3: long     */ 11,
     52     /* M4 == 4: extended */ 15,
     53 };
     54 static 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  */
    119 struct 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 
    288 static 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 
    295 static 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 
    323 static 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 
    329 int 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 }