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
vfminmax(unsigned int op,unsigned int m4,unsigned int m5,unsigned int m6,void * v1,const void * v2,const void * v3)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
dump_v(FILE * f,const void * v,size_t n)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
signed_test(struct signed_test * test,int m4,int m5,const void * v1_exp,bool xi_exp,const void * v2,const void * v3)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
snan_to_qnan(char * v,int m4)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
main(void)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