drd/tests/swapcontext: Improve the portability of this test further
[valgrind.git] / none / tests / ppc32 / test_dfp1.c
blobbaf18419c75ce04bc1c9c8518cef43f2a9169202
1 /* Copyright (C) 2012 IBM
3 Author: Maynard Johnson <maynardj@us.ibm.com>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>.
18 The GNU General Public License is contained in the file COPYING.
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
25 #if defined(HAS_DFP)
27 register double f14 __asm__ ("fr14");
28 register double f15 __asm__ ("fr15");
29 register double f16 __asm__ ("fr16");
30 register double f17 __asm__ ("fr17");
31 register double f18 __asm__ ("fr18");
32 register double f19 __asm__ ("fr19");
35 typedef unsigned char Bool;
36 #define True 1
37 #define False 0
40 #define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7"
42 #define SET_CR(_arg) \
43 __asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR );
45 #define SET_XER(_arg) \
46 __asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" );
48 #define GET_CR(_lval) \
49 __asm__ __volatile__ ("mfcr %0" : "=b"(_lval) )
51 #define GET_XER(_lval) \
52 __asm__ __volatile__ ("mfxer %0" : "=b"(_lval) )
54 #define GET_CR_XER(_lval_cr,_lval_xer) \
55 do { GET_CR(_lval_cr); GET_XER(_lval_xer); } while (0)
57 #define SET_CR_ZERO \
58 SET_CR(0)
60 #define SET_XER_ZERO \
61 SET_XER(0)
63 #define SET_CR_XER_ZERO \
64 do { SET_CR_ZERO; SET_XER_ZERO; } while (0)
66 #define SET_FPSCR_ZERO \
67 do { double _d = 0.0; \
68 __asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \
69 } while (0)
71 #define GET_FPSCR(_arg) \
72 __asm__ __volatile__ ("mffs %0" : "=f"(_arg) )
74 #define SET_FPSCR_DRN \
75 __asm__ __volatile__ ("mtfsf 1, %0, 0, 1" : : "f"(f14) )
78 // The assembly-level instructions being tested
79 static Bool do_dot;
80 static void _test_dadd (void)
82 if (do_dot)
83 __asm__ __volatile__ ("dadd. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
84 else
85 __asm__ __volatile__ ("dadd %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
88 static void _test_dsub (void)
90 if (do_dot)
91 __asm__ __volatile__ ("dsub. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
92 else
93 __asm__ __volatile__ ("dsub %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
96 static void _test_dmul (void)
98 if (do_dot)
99 __asm__ __volatile__ ("dmul. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
100 else
101 __asm__ __volatile__ ("dmul %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
104 static void _test_ddiv (void)
106 if (do_dot)
107 __asm__ __volatile__ ("ddiv. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
108 else
109 __asm__ __volatile__ ("ddiv %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
112 // Quad DFP arith instructions
113 static void _test_daddq (void)
115 if (do_dot)
116 __asm__ __volatile__ ("daddq. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
117 else
118 __asm__ __volatile__ ("daddq %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
121 static void _test_dsubq (void)
123 if (do_dot)
124 __asm__ __volatile__ ("dsubq. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
125 else
126 __asm__ __volatile__ ("dsubq %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
129 static void _test_dmulq (void)
131 if (do_dot)
132 __asm__ __volatile__ ("dmulq. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
133 else
134 __asm__ __volatile__ ("dmulq %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
137 static void _test_ddivq (void)
139 if (do_dot)
140 __asm__ __volatile__ ("ddivq. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
141 else
142 __asm__ __volatile__ ("ddivq %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
145 static void _test_mffs (void)
147 __asm__ __volatile__ ("mffs %0" : "=f"(f14));
150 static void _test_mtfsf (int upper)
152 if (upper)
153 __asm__ __volatile__ ("mtfsf 1, %0, 0, 1" : : "f"(f14) );
154 else
155 __asm__ __volatile__ ("mtfsf 1, %0, 0, 0" : : "f"(f14) );
158 typedef void (*test_func_t)(void);
159 typedef struct test_table
161 test_func_t test_category;
162 char * name;
163 } test_table_t;
166 * 345.0DD (0x2207c00000000000 0xe50)
167 * 1.2300e+5DD (0x2207c00000000000 0x14c000)
168 * -16.0DD (0xa207c00000000000 0xe0)
169 * 0.00189DD (0x2206c00000000000 0xcf)
170 * -4.1235DD (0xa205c00000000000 0x10a395bcf)
171 * 9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4)
172 * 0DD (0x2208000000000000 0x0)
173 * 0DD (0x2208000000000000 0x0)
174 * infDD (0x7800000000000000 0x0)
175 * nanDD (0x7c00000000000000 0x0
177 static unsigned long long dfp128_vals[] = {
178 // Some finite numbers
179 0x2207c00000000000ULL, 0x0000000000000e50ULL,
180 0x2207c00000000000ULL, 0x000000000014c000ULL,
181 0xa207c00000000000ULL, 0x00000000000000e0ULL,
182 0x2206c00000000000ULL, 0x00000000000000cfULL,
183 0xa205c00000000000ULL, 0x000000010a395bcfULL,
184 0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number
185 0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number
186 // flavors of zero
187 0x2208000000000000ULL, 0x0000000000000000ULL,
188 0xa208000000000000ULL, 0x0000000000000000ULL, // negative
189 0xa248000000000000ULL, 0x0000000000000000ULL,
190 // flavors of NAN
191 0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet
192 0xfc00000000000000ULL, 0xc00100035b007700ULL,
193 0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling
194 // flavors of Infinity
195 0x7800000000000000ULL, 0x0000000000000000ULL,
196 0xf800000000000000ULL, 0x0000000000000000ULL, // negative
197 0xf900000000000000ULL, 0x0000000000000000ULL
200 static unsigned long long dfp64_vals[] = {
201 // various finite numbers
202 0x2234000000000e50ULL,
203 0x223400000014c000ULL,
204 0xa2340000000000e0ULL,// negative
205 0x22240000000000cfULL,
206 0xa21400010a395bcfULL,// negative
207 0x6e4d3f1f534acdd4ULL,// huge number
208 0x000400000089b000ULL,// very small number
209 // flavors of zero
210 0x2238000000000000ULL,
211 0xa238000000000000ULL,
212 0x4248000000000000ULL,
213 // flavors of NAN
214 0x7e34000000000111ULL,
215 0xfe000000d0e0a0d0ULL,//signaling
216 0xfc00000000000000ULL,//quiet
217 // flavors of Infinity
218 0x7800000000000000ULL,
219 0xf800000000000000ULL,//negative
220 0x7a34000000000000ULL,
224 typedef struct dfp_test_args {
225 int fra_idx;
226 int frb_idx;
227 } dfp_test_args_t;
230 // Index pairs from dfp64_vals or dfp128_vals array to be used with dfp_two_arg_tests
231 static dfp_test_args_t dfp_2args_x2[] = {
232 {0, 1},
233 {2, 1},
234 {3, 4},
235 {0, 6},
236 {2, 4},
237 {5, 1},
238 {5, 2},
239 {7, 8},
240 {7, 1},
241 {9, 15},
242 {8, 12},
243 {7, 11},
244 {13, 2},
245 {13, 14},
246 {15, 12},
247 {14, 11},
248 {12, 12},
249 {12, 11},
250 {11, 11}
253 // Index pairs from dfp64_vals array to be used with dfp_two_arg_tests
254 static dfp_test_args_t dfp_2args_x1[] = {
255 {0, 1},
256 {2, 1},
257 {3, 4},
258 {0, 6},
259 {2, 4},
260 {5, 1},
261 {5, 2},
262 {7, 1},
263 {7, 2},
264 {8, 0},
265 {8, 1},
266 {8, 2},
267 {7, 8},
268 {12, 14},
269 {12, 1},
270 {12, 13},
271 {12, 12},
272 {12, 11},
273 {11, 14},
274 {11, 0},
275 {11, 13},
276 {11, 11},
277 {14, 14},
278 {14, 3},
279 {14, 15},
282 typedef enum {
283 LONG_TEST,
284 QUAD_TEST
285 } precision_type_t;
287 typedef struct dfp_test
289 test_func_t test_func;
290 const char * name;
291 dfp_test_args_t * targs;
292 int num_tests;
293 precision_type_t precision;
294 const char * op;
295 Bool cr_supported;
296 } dfp_test_t;
299 static dfp_test_t
300 dfp_two_arg_tests[] = {
301 { &_test_dadd, "dadd", dfp_2args_x1, 25, LONG_TEST, "+", False},
302 { &_test_dsub, "dsub", dfp_2args_x1, 25, LONG_TEST, "-", False},
303 { &_test_dmul, "dmul", dfp_2args_x2, 19, LONG_TEST, "*", False},
304 { &_test_ddiv, "ddiv", dfp_2args_x2, 19, LONG_TEST, "/", False},
305 { &_test_daddq, "daddq", dfp_2args_x1, 25, QUAD_TEST, "+", False},
306 { &_test_dsubq, "dsubq", dfp_2args_x1, 25, QUAD_TEST, "-", False},
307 { &_test_dmulq, "dmulq", dfp_2args_x2, 19, QUAD_TEST, "*", False},
308 { &_test_ddivq, "ddivq", dfp_2args_x2, 19, QUAD_TEST, "/", False},
309 { NULL, NULL, NULL, 0, 0, NULL}
312 static void test_dfp_two_arg_ops(void)
314 test_func_t func;
315 unsigned long long u0, u0x, u1, u1x;
316 double res, d0, d1, *d0p, *d1p;
317 double d0x, d1x, *d0xp, *d1xp;
318 int k = 0;
319 u0x = u1x = 0;
320 d0p = &d0;
321 d0xp = &d0x;
322 d1p = &d1;
323 d1xp = &d1x;
325 while ((func = dfp_two_arg_tests[k].test_func)) {
326 int i, repeat = 1;
327 dfp_test_t test_group = dfp_two_arg_tests[k];
328 do_dot = False;
330 again:
331 for (i = 0; i < test_group.num_tests; i++) {
332 unsigned int condreg;
333 unsigned int flags;
335 if (test_group.precision == LONG_TEST) {
336 u0 = dfp64_vals[test_group.targs[i].fra_idx];
337 u1 = dfp64_vals[test_group.targs[i].frb_idx];
338 } else {
339 u0 = dfp128_vals[test_group.targs[i].fra_idx * 2];
340 u0x = dfp128_vals[(test_group.targs[i].fra_idx * 2) + 1];
341 u1 = dfp128_vals[test_group.targs[i].frb_idx * 2];
342 u1x = dfp128_vals[(test_group.targs[i].frb_idx * 2) + 1];
344 *(unsigned long long *)d0p = u0;
345 *(unsigned long long *)d1p = u1;
346 f14 = d0;
347 f16 = d1;
348 if (test_group.precision == QUAD_TEST) {
349 *(unsigned long long *)d0xp = u0x;
350 *(unsigned long long *)d1xp = u1x;
351 f15 = d0x;
352 f17 = d1x;
355 SET_FPSCR_ZERO;
356 SET_CR_XER_ZERO;
357 (*func)();
358 GET_CR(flags);
359 res = f18;
361 condreg = (flags & 0x000000f0) >> 4;
362 printf("%s%s %016llx", test_group.name, do_dot? "." : "", u0);
363 if (test_group.precision == LONG_TEST) {
364 printf(" %s %016llx => %016llx",
365 test_group.op, u1, *((unsigned long long *)(&res)));
366 } else {
367 double resx = f19;
368 printf(" %016llx %s %016llx %016llx ==> %016llx %016llx",
369 u0x, test_group.op, u1, u1x,
370 *((unsigned long long *)(&res)), *((unsigned long long *)(&resx)));
372 if (test_group.cr_supported)
373 printf(" (cr = %08x)\n", condreg);
374 else
375 printf("\n");
378 printf("\n");
379 if (repeat) {
380 repeat = 0;
381 do_dot = True;
382 goto again;
384 k++;
385 printf( "\n" );
389 void test_move_toFrom_fpscr(void)
391 #define BFP_MAX_RM 3
392 int shift = 0;
393 unsigned long long i, max_rm, expected_val;
394 double fpscr_in, fpscr_out;
395 unsigned long long * hex_fpscr_in = (unsigned long long *)&fpscr_in;
396 unsigned long long * hex_fpscr_out = (unsigned long long *)&fpscr_out;
399 max_rm = 4;
400 again:
401 /* NOTE: The first time through this loop is for setting the binary
402 * floating point rounding mode (bits 62:63 of FPSCR). The second time
403 * through is for setting the decimal floating point rounding mode
404 * (bits 29:31 of FPSCR). In the second time through this loop, the value
405 * returned should include the final binary FP rounding mode, along with
406 * the decimal FP rounding modes.
408 for (i = 0; i < max_rm; i++) {
409 *hex_fpscr_in = (i << shift);
410 f14 = fpscr_in;
411 _test_mtfsf(max_rm/8);
412 *hex_fpscr_in = 0ULL;
413 f14= fpscr_in;
414 _test_mffs();
415 fpscr_out = f14;
416 if (max_rm == 4) {
417 *hex_fpscr_out &= (max_rm - 1) << shift;
418 expected_val = i << shift;
419 } else {
420 *hex_fpscr_out &= BFP_MAX_RM | ((max_rm - 1) << shift);
421 expected_val = (i << shift) | BFP_MAX_RM;
424 printf("FPSCR %s floating point rounding mode %016llx == %016llx? %s\n",
425 (max_rm == 8) ? "decimal" : "binary",
426 *hex_fpscr_out, expected_val,
427 (expected_val == *hex_fpscr_out) ? "yes" : "no");
429 if (max_rm == 4) {
430 max_rm = 8;
431 shift = 32;
432 goto again;
436 void test_rounding_modes(void)
438 int j;
439 unsigned long long u0, u1, rm_idx;
440 double res, d0, d1, *d0p, *d1p, fpscr;
441 unsigned long long * hex_fpscr = (unsigned long long *)&fpscr;
442 u0 = 0x26cc3f1f534acdd4ULL;
443 u1 = 0x27feff197a42ba06ULL;
444 d0p = &d0;
445 d1p = &d1;
447 for (j = 0; j < 12; j++) {
448 for (rm_idx = 0; rm_idx < 8; rm_idx++) {
449 *hex_fpscr = 0ULL;
450 __asm__ __volatile__ ("mffs %0" : "=f"(f14));
451 fpscr = f14;
452 *hex_fpscr &= 0xFFFFFFF0FFFFFFFFULL;
453 *hex_fpscr |= (rm_idx << 32);
454 f14 = fpscr;
455 SET_FPSCR_DRN;
456 *(unsigned long long *)d0p = u0;
457 *(unsigned long long *)d1p = u1;
458 f14 = d0;
459 f16 = d1;
460 _test_dmul();
461 res = f18;
462 printf("test #%d: dmul with rounding mode %d: %016llx * %016llx => %016llx\n",
463 j, (int)rm_idx, u0, u1, *((unsigned long long *)(&res)));
464 printf("\n");
466 // Changing the least significant bit of one of the dmul arguments give us more
467 // opportunities for different rounding modes to yield different results which
468 // can then be validated.
469 u0++;
473 static test_table_t
474 all_tests[] =
476 { &test_dfp_two_arg_ops,
477 "Test DFP arithmetic instructions"},
478 { &test_rounding_modes,
479 "Test DFP rounding modes"},
480 { &test_move_toFrom_fpscr,
481 "Test move to/from FPSCR"},
482 { NULL, NULL }
484 #endif // HAS_DFP
486 int main() {
487 #if defined(HAS_DFP)
489 test_table_t aTest;
490 test_func_t func;
491 int i = 0;
493 while ((func = all_tests[i].test_category)) {
494 aTest = all_tests[i];
495 printf( "%s\n", aTest.name );
496 (*func)();
497 i++;
500 #endif // HAS_DFP
501 return 0;