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 } 412