2 /* Copyright (C) 2006 Dave Nomura
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.
25 typedef enum { FALSE
=0, TRUE
} bool_t
;
28 FADDS
, FSUBS
, FMULS
, FDIVS
,
29 FMADDS
, FMSUBS
, FNMADDS
, FNMSUBS
,
30 FADD
, FSUB
, FMUL
, FDIV
, FMADD
,
31 FMSUB
, FNMADD
, FNMSUB
, FSQRT
35 TO_NEAREST
=0, TO_ZERO
, TO_PLUS_INFINITY
, TO_MINUS_INFINITY
} round_mode_t
;
36 char *round_mode_name
[] = { "near", "zero", "+inf", "-inf" };
38 const char *flt_op_names
[] = {
39 "fadds", "fsubs", "fmuls", "fdivs",
40 "fmadds", "fmsubs", "fnmadds", "fnmsubs",
41 "fadd", "fsub", "fmul", "fdiv", "fmadd", "fmsub", "fnmadd",
45 typedef unsigned int fpscr_t
;
50 #if defined(VGP_ppc64le_linux)
65 #if defined(VGP_ppc64le_linux)
66 unsigned int frac_lo
:32;
67 unsigned int frac_hi
:20;
73 unsigned int frac_hi
:20;
74 unsigned int frac_lo
:32;
83 void assert_fail(const char *msg
,
84 const char* expr
, const char* file
, int line
, const char*fn
);
86 #define STRING(__str) #__str
87 #define assert(msg, expr) \
88 ((void) ((expr) ? 0 : \
89 (assert_fail (msg, STRING(expr), \
91 __PRETTY_FUNCTION__), 0)))
93 double dbl_denorm_small
;
96 bool_t long_is_64_bits
= sizeof(long) == 8;
98 void assert_fail (msg
, expr
, file
, line
, fn
)
105 printf( "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
106 msg
, file
, line
, fn
, expr
);
109 void set_rounding_mode(round_mode_t mode
)
113 asm volatile("mtfsfi 7, 0");
116 asm volatile("mtfsfi 7, 1");
118 case TO_PLUS_INFINITY
:
119 asm volatile("mtfsfi 7, 2");
121 case TO_MINUS_INFINITY
:
122 asm volatile("mtfsfi 7, 3");
127 void print_double(char *msg
, double dbl
)
132 printf("%15s : dbl %-20a = %c(%4d, %05x%08x)\n",
133 msg
, D
.dbl
, (D
.layout
.sign
== 0 ? '+' : '-'),
134 D
.layout
.exp
, D
.layout
.frac_hi
, D
.layout
.frac_lo
);
137 void print_single(char *msg
, float *flt
)
142 /* NOTE: for the purposes of comparing the fraction of a single with
143 ** a double left shift the .frac so that hex digits are grouped
144 ** from left to right. this is necessary because the size of a
145 ** single mantissa (23) bits is not a multiple of 4
147 printf("%15s : flt %-20a = %c(%4d, %06x)\n",
148 msg
, F
.flt
, (F
.layout
.sign
== 0 ? '+' : '-'), F
.layout
.exp
, F
.layout
.frac
<< 1);
151 int check_dbl_to_flt_round(round_mode_t mode
, double dbl
, float *expected
)
157 set_rounding_mode(mode
);
162 if ((R
.layout
.sign
!= E
.layout
.sign
) ||
163 (R
.layout
.exp
!= E
.layout
.exp
) ||
164 (R
.layout
.frac
!= E
.layout
.frac
)) {
171 printf("%s:%s:(double)(%-20a) = %20a",
172 round_mode_name
[mode
], result
, R
.flt
, dbl
);
174 print_single("\n\texpected", &E
.flt
);
175 print_single("\n\trounded ", &R
.flt
);
181 int test_dbl_to_float_convert(char *msg
, float *base
)
184 double half
= (double)denorm_small
/2;
186 double D_hi
= (double)*base
+ half
+ qtr
;
187 double D_lo
= (double)*base
+ half
- qtr
;
189 float F_hi
= F_lo
+ denorm_small
;
193 ** .....+-----+-----+-----+-----+---....
198 ** F_lo and F_hi are two consecutive single float model numbers
199 ** denorm_small distance apart. D_lo and D_hi are two numbers
200 ** within that range that are not representable as single floats
201 ** and will be rounded to either F_lo or F_hi.
203 printf("-------------------------- %s --------------------------\n", msg
);
205 print_double("D_lo", D_lo
);
206 print_double("D_hi", D_hi
);
207 print_single("F_lo", &F_lo
);
208 print_single("F_hi", &F_hi
);
211 /* round to nearest */
212 status
|= check_dbl_to_flt_round(TO_NEAREST
, D_hi
, &F_hi
);
213 status
|= check_dbl_to_flt_round(TO_NEAREST
, D_lo
, &F_lo
);
216 status
|= check_dbl_to_flt_round(TO_ZERO
, D_hi
, (D_hi
> 0 ? &F_lo
: &F_hi
));
217 status
|= check_dbl_to_flt_round(TO_ZERO
, D_lo
, (D_hi
> 0 ? &F_lo
: &F_hi
));
220 status
|= check_dbl_to_flt_round(TO_PLUS_INFINITY
, D_hi
, &F_hi
);
221 status
|= check_dbl_to_flt_round(TO_PLUS_INFINITY
, D_lo
, &F_hi
);
224 status
|= check_dbl_to_flt_round(TO_MINUS_INFINITY
, D_hi
, &F_lo
);
225 status
|= check_dbl_to_flt_round(TO_MINUS_INFINITY
, D_lo
, &F_lo
);
235 /* small is the smallest denormalized single float number */
239 denorm_small
= F
.flt
; /* == 2^(-149) */
241 print_single("float small", &F
.flt
);
246 D
.layout
.frac_hi
= 0;
247 D
.layout
.frac_lo
= 1;
248 dbl_denorm_small
= D
.dbl
; /* == 2^(-1022) */
250 print_double("double small", D
.dbl
);
253 /* n_small is the smallest normalized single precision float */
258 int check_int_to_flt_round(round_mode_t mode
, long L
, float *expected
)
262 char *int_name
= "int";
267 set_rounding_mode(mode
);
270 for (iter
= 0; iter
< 2; iter
++) {
272 R
.flt
= (iter
== 0 ? (float)I
: (float)L
);
274 if ((R
.layout
.sign
!= E
.layout
.sign
) ||
275 (R
.layout
.exp
!= E
.layout
.exp
) ||
276 (R
.layout
.frac
!= E
.layout
.frac
)) {
283 printf("%s:%s:(float)(%4s)%9d = %11.1f",
284 round_mode_name
[mode
], result
, int_name
, I
, R
.flt
);
286 print_single("\n\texpected: %.1f ", &E
.flt
);
287 print_single("\n\trounded ", &R
.flt
);
292 if (!long_is_64_bits
) break;
298 int check_long_to_dbl_round(round_mode_t mode
, long L
, double *expected
)
304 set_rounding_mode(mode
);
309 if ((R
.layout
.sign
!= E
.layout
.sign
) ||
310 (R
.layout
.exp
!= E
.layout
.exp
) ||
311 (R
.layout
.frac_lo
!= E
.layout
.frac_lo
) ||
312 (R
.layout
.frac_hi
!= E
.layout
.frac_hi
)) {
319 printf("%s:%s:(double)(%18ld) = %20.1f",
320 round_mode_name
[mode
], result
, L
, R
.dbl
);
322 printf("\n\texpected %.1f : ", E
.dbl
);
328 int test_int_to_float_convert(char *msg
)
331 int int24_hi
= 0x03ff0fff;
332 int int24_lo
= 0x03ff0ffd;
333 float pos_flt_lo
= 67047420.0;
334 float pos_flt_hi
= 67047424.0;
335 float neg_flt_lo
= -67047420.0;
336 float neg_flt_hi
= -67047424.0;
338 printf("-------------------------- %s --------------------------\n", msg
);
339 status
|= check_int_to_flt_round(TO_NEAREST
, int24_lo
, &pos_flt_lo
);
340 status
|= check_int_to_flt_round(TO_NEAREST
, int24_hi
, &pos_flt_hi
);
341 status
|= check_int_to_flt_round(TO_ZERO
, int24_lo
, &pos_flt_lo
);
342 status
|= check_int_to_flt_round(TO_ZERO
, int24_hi
, &pos_flt_lo
);
343 status
|= check_int_to_flt_round(TO_PLUS_INFINITY
, int24_lo
, &pos_flt_hi
);
344 status
|= check_int_to_flt_round(TO_PLUS_INFINITY
, int24_hi
, &pos_flt_hi
);
345 status
|= check_int_to_flt_round(TO_MINUS_INFINITY
, int24_lo
, &pos_flt_lo
);
346 status
|= check_int_to_flt_round(TO_MINUS_INFINITY
, int24_hi
, &pos_flt_lo
);
348 status
|= check_int_to_flt_round(TO_NEAREST
, -int24_lo
, &neg_flt_lo
);
349 status
|= check_int_to_flt_round(TO_NEAREST
, -int24_hi
, &neg_flt_hi
);
350 status
|= check_int_to_flt_round(TO_ZERO
, -int24_lo
, &neg_flt_lo
);
351 status
|= check_int_to_flt_round(TO_ZERO
, -int24_hi
, &neg_flt_lo
);
352 status
|= check_int_to_flt_round(TO_PLUS_INFINITY
, -int24_lo
, &neg_flt_lo
);
353 status
|= check_int_to_flt_round(TO_PLUS_INFINITY
, -int24_hi
, &neg_flt_lo
);
354 status
|= check_int_to_flt_round(TO_MINUS_INFINITY
, -int24_lo
, &neg_flt_hi
);
355 status
|= check_int_to_flt_round(TO_MINUS_INFINITY
, -int24_hi
, &neg_flt_hi
);
360 int test_long_to_double_convert(char *msg
)
363 long long55_hi
= 0x07ff0ffffffffff;
364 long long55_lo
= 0x07ff0fffffffffd;
365 double pos_dbl_lo
= 36012304344547324.0;
366 double pos_dbl_hi
= 36012304344547328.0;
367 double neg_dbl_lo
= -36012304344547324.0;
368 double neg_dbl_hi
= -36012304344547328.0;
370 printf("-------------------------- %s --------------------------\n", msg
);
371 status
|= check_long_to_dbl_round(TO_NEAREST
, long55_lo
, &pos_dbl_lo
);
372 status
|= check_long_to_dbl_round(TO_NEAREST
, long55_hi
, &pos_dbl_hi
);
373 status
|= check_long_to_dbl_round(TO_ZERO
, long55_lo
, &pos_dbl_lo
);
374 status
|= check_long_to_dbl_round(TO_ZERO
, long55_hi
, &pos_dbl_lo
);
375 status
|= check_long_to_dbl_round(TO_PLUS_INFINITY
, long55_lo
, &pos_dbl_hi
);
376 status
|= check_long_to_dbl_round(TO_PLUS_INFINITY
, long55_hi
, &pos_dbl_hi
);
377 status
|= check_long_to_dbl_round(TO_MINUS_INFINITY
, long55_lo
, &pos_dbl_lo
);
378 status
|= check_long_to_dbl_round(TO_MINUS_INFINITY
, long55_hi
, &pos_dbl_lo
);
380 status
|= check_long_to_dbl_round(TO_NEAREST
, -long55_lo
, &neg_dbl_lo
);
381 status
|= check_long_to_dbl_round(TO_NEAREST
, -long55_hi
, &neg_dbl_hi
);
382 status
|= check_long_to_dbl_round(TO_ZERO
, -long55_lo
, &neg_dbl_lo
);
383 status
|= check_long_to_dbl_round(TO_ZERO
, -long55_hi
, &neg_dbl_lo
);
384 status
|= check_long_to_dbl_round(TO_PLUS_INFINITY
, -long55_lo
, &neg_dbl_lo
);
385 status
|= check_long_to_dbl_round(TO_PLUS_INFINITY
, -long55_hi
, &neg_dbl_lo
);
386 status
|= check_long_to_dbl_round(TO_MINUS_INFINITY
, -long55_lo
, &neg_dbl_hi
);
387 status
|= check_long_to_dbl_round(TO_MINUS_INFINITY
, -long55_hi
, &neg_dbl_hi
);
392 int check_single_arithmetic_op(flt_op_t op
)
397 double qtr
, half
, fA
, fB
, fD
;
400 bool_t two_args
= TRUE
;
401 float whole
= denorm_small
;
405 op" %0, %1, %2\n\t" \
406 : "=f"(fD) : "f"(fA) , "f"(fB));
410 : "=f"(fD) : "f"(fA));
412 half
= (double)whole
/2;
416 print_double("qtr", qtr
);
417 print_double("whole", whole
);
418 print_double("2*whole", 2*whole
);
421 for (mode
= TO_NEAREST
; mode
<= TO_MINUS_INFINITY
; mode
++)
422 for (s
= -1; s
< 2; s
+= 2)
423 for (q
= 1; q
< 4; q
+= 2) {
426 double hi
= s
*2*whole
;
435 fB
= s
*(q
== 1 ? 3 : 1)*qtr
;
446 assert("check_single_arithmetic_op: unexpected op",
453 expected
= (q
== 1 ? lo
: hi
);
458 case TO_PLUS_INFINITY
:
459 expected
= (s
== 1 ? hi
: lo
);
461 case TO_MINUS_INFINITY
:
462 expected
= (s
== 1 ? lo
: hi
);
466 set_rounding_mode(mode
);
469 ** do the double precision dual operation just for comparison
494 assert("check_single_arithmetic_op: unexpected op",
503 if ((R
.layout
.sign
!= E
.layout
.sign
) ||
504 (R
.layout
.exp
!= E
.layout
.exp
) ||
505 (R
.layout
.frac_lo
!= E
.layout
.frac_lo
) ||
506 (R
.layout
.frac_hi
!= E
.layout
.frac_hi
)) {
514 printf("%s:%s:%s(%-13a",
515 round_mode_name
[mode
], result
, flt_op_names
[op
], fA
);
516 if (two_args
) printf(", %-13a", fB
);
517 printf(") = %-13a", R
.dbl
);
518 if (status
) printf("\n\texpected %a", E
.dbl
);
522 print_double("hi", hi
);
523 print_double("lo", lo
);
524 print_double("expected", expected
);
525 print_double("got", R
.dbl
);
526 print_double("double result", fD
);
533 int check_single_guarded_arithmetic_op(flt_op_t op
)
542 dbl_overlay Res
, Exp
;
543 double fA
, fB
, fC
, fD
;
548 fdivs_t divs_guard_cases
[16] = {
549 { 105, 56, 0x700000 }, /* : 0 */
550 { 100, 57, 0x608FB8 }, /* : 1 */
551 { 000, 00, 0x000000 }, /* : X */
552 { 100, 52, 0x762762 }, /* : 3 */
553 { 000, 00, 0x000000 }, /* : X */
554 { 100, 55, 0x68BA2E }, /* : 5 */
555 { 000, 00, 0x000000 }, /* : X */
556 { 100, 51, 0x7AFAFA }, /* : 7 */
557 { 000, 00, 0x000000 }, /* : X */
558 { 100, 56, 0x649249 }, /* : 9 */
559 { 000, 00, 0x000000 }, /* : X */
560 { 100, 54, 0x6D097B }, /* : B */
561 { 000, 00, 0x000000 }, /* : X */
562 { 100, 59, 0x58F2FB }, /* : D */
563 { 000, 00, 0x000000 }, /* : X */
564 { 101, 52, 0x789D89 } /* : F */
567 /* 0x1.00000 00000000p-3 */
568 /* set up the invariant fields of B, the arg to cause rounding */
570 B
.layout
.exp
= 124; /* -3 */
572 /* set up args so result is always Z = 1.200000000000<g>p+0 */
579 op" %0, %1, %2, %3\n\t" \
580 : "=f"(fD) : "f"(fA) , "f"(fB), "f"(fC));
584 op" %0, %1, %2\n\t" \
585 : "=f"(fD) : "f"(fA) , "f"(fB));
590 : "=f"(fD) : "f"(fA));
592 for (mode
= TO_NEAREST
; mode
<= TO_MINUS_INFINITY
; mode
++)
593 for (s
= -1; s
< 2; s
+= 2)
594 for (g
= 0; g
< 16; g
+= 1) {
595 double lo
, hi
, expected
;
601 ** one argument will have exponent = 0 as will the result (by
602 ** design) so choose the other argument with exponent -3 to
603 ** force a 3 bit shift for scaling leaving us with 3 guard bits
604 ** and the LSB bit at the bottom of the manitssa.
608 /* 1p+0 + 1.00000<g>p-3 */
614 /* set up Z to be truncated result */
616 /* mask off LSB from resulting guard bits */
619 Z
.layout
.frac
= 0x100000 | (g
>> 3);
622 /* 1.200002p+0 - 1.000000000000<g>p-3 */
624 /* add enough to avoid scaling of the result */
625 A
.layout
.frac
|= 0x2;
631 /* set up Z to be truncated result */
633 Z
.layout
.frac
= guard
>>3;
635 /* mask off LSB from resulting guard bits */
645 /* set up Z to be truncated result */
647 Z
.layout
.frac
= 0x100000;
648 Z
.layout
.frac
|= g
+ (g
>>3);
652 /* g >> 3 == LSB, g & 7 == guard bits */
654 if ((guard
& 1) == 0) {
655 /* special case: guard bit X = 0 */
656 A
.flt
= denorm_small
;
661 Z
.layout
.frac
|= (g
>> 3);
663 fA
= s
*divs_guard_cases
[g
].num
;
664 fB
= divs_guard_cases
[g
].den
;
667 Z
.layout
.frac
= divs_guard_cases
[g
].frac
;
683 fC
= (op
== FMADDS
|| op
== FNMADDS
? s
: -s
)*A
.flt
;
685 /* set up Z to be truncated result */
686 z_sign
= (op
== FNMADDS
|| op
== FNMSUBS
? -s
: s
);
687 guard
= ((g
& 7) + 0x4) & 7;
689 Z
.layout
.frac
= 0x500000;
690 Z
.layout
.frac
|= g
+ (g
>>3) + ((g
& 7)>> 2 ? 1 : 0);
693 assert("check_single_arithmetic_op: unexpected op",
698 /* get LSB for tie breaking */
699 LSB
= Z
.layout
.frac
& 1;
701 /* set up hi and lo */
708 /* look at 3 guard bits to determine expected rounding */
711 case 1: case 2: case 3:
714 case 4: /* tie: round to even */
715 if (debug
) printf("tie: LSB = %d\n", LSB
);
716 expected
= (LSB
== 0 ? lo
: hi
);
718 case 5: case 6: case 7:
722 assert("check_single_guarded_arithmetic_op: unexpected guard",
729 case TO_PLUS_INFINITY
:
734 expected
= (s
== 1 ? hi
: lo
);
737 case TO_MINUS_INFINITY
:
742 expected
= (s
== 1 ? lo
: hi
);
747 set_rounding_mode(mode
);
750 ** do the double precision dual operation just for comparison
787 assert("check_single_guarded_arithmetic_op: unexpected op",
797 if ((Res
.layout
.sign
!= Exp
.layout
.sign
) ||
798 (Res
.layout
.exp
!= Exp
.layout
.exp
) ||
799 (Res
.layout
.frac_lo
!= Exp
.layout
.frac_lo
) ||
800 (Res
.layout
.frac_hi
!= Exp
.layout
.frac_hi
)) {
808 /* There seems to be some noise in the lower bits. The value
809 * on the least significant digit seems to vary when printing
810 * based on the rounding mode of the compiler. Just trying
811 * to get rid of the noise in the least significant bits when
812 * printing the operand.
815 fA
= ((long int)(fA
*10000))/10000.0;
816 /* Change -0.0 to a positive 0.0. Some compilers print -0.0
817 * others do not. Make it consistent.
822 printf("%s:%s:%s(%-13.6f",
823 round_mode_name
[mode
], result
, flt_op_names
[op
], fA
);
824 if (arg_count
> 1) printf(", %-13a", fB
);
825 if (arg_count
> 2) printf(", %-13a", fC
);
826 printf(") = %-13a", Res
.dbl
);
827 if (status
) printf("\n\texpected %a", Exp
.dbl
);
831 print_double("hi", hi
);
832 print_double("lo", lo
);
833 print_double("expected", expected
);
834 print_double("got", Res
.dbl
);
841 int check_double_guarded_arithmetic_op(flt_op_t op
)
844 int num
, den
, hi
, lo
;
854 dbl_overlay Res
, Exp
;
855 double fA
, fB
, fC
, fD
;
859 fdiv_t div_guard_cases
[16] = {
860 { 62, 62, 0x00000, 0x00000000 }, /* 0 */
861 { 64, 62, 0x08421, 0x08421084 }, /* 1 */
862 { 66, 62, 0x10842, 0x10842108 }, /* 2 */
863 { 100, 62, 0x9ce73, 0x9ce739ce }, /* 3 */
864 { 100, 62, 0x9ce73, 0x9ce739ce }, /* X */
865 { 102, 62, 0xa5294, 0xa5294a52 }, /* 5 */
866 { 106, 62, 0xb5ad6, 0xb5ad6b5a }, /* 6 */
867 { 108, 62, 0xbdef7, 0xbdef7bde }, /* 7 */
868 { 108, 108, 0x00000, 0x00000000 }, /* 8 */
869 { 112, 62, 0xce739, 0xce739ce7 }, /* 9 */
870 { 114, 62, 0xd6b5a, 0xd6b5ad6b }, /* A */
871 { 116, 62, 0xdef7b, 0xdef7bdef }, /* B */
872 { 84, 62, 0x5ad6b, 0x5ad6b5ad }, /* X */
873 { 118, 62, 0xe739c, 0xe739ce73 }, /* D */
874 { 90, 62, 0x739ce, 0x739ce739 }, /* E */
875 { 92, 62, 0x7bdef, 0x7bdef7bd } /* F */
879 fsqrt_t sqrt_guard_cases
[16] = {
880 { 0x1.08800p0
, 0, 0x04371, 0xd9ab72fb}, /* :0 B8.8440 */
881 { 0x0.D2200p0
, -1, 0xcfdca, 0xf353049e}, /* :1 A4.6910 */
882 { 0x1.A8220p0
, 0, 0x49830, 0x2b49cd6d}, /* :2 E9.D411 */
883 { 0x1.05A20p0
, 0, 0x02cd1, 0x3b44f3bf}, /* :3 B7.82D1 */
884 { 0x0.CA820p0
, -1, 0xc7607, 0x3cec0937}, /* :4 A1.6541 */
885 { 0x1.DCA20p0
, 0, 0x5d4f8, 0xd4e4c2b2}, /* :5 F7.EE51 */
886 { 0x1.02C80p0
, 0, 0x01630, 0x9cde7483}, /* :6 B6.8164 */
887 { 0x0.DC800p0
, -1, 0xdb2cf, 0xe686fe7c}, /* :7 A8.6E40 */
888 { 0x0.CF920p0
, -1, 0xcd089, 0xb6860626}, /* :8 A3.67C9 */
889 { 0x1.1D020p0
, 0, 0x0e1d6, 0x2e78ed9d}, /* :9 BF.8E81 */
890 { 0x0.E1C80p0
, -1, 0xe0d52, 0x6020fb6b}, /* :A AA.70E4 */
891 { 0x0.C8000p0
, -1, 0xc48c6, 0x001f0abf}, /* :B A0.6400 */
892 { 0x1.48520p0
, 0, 0x21e9e, 0xd813e2e2}, /* :C CD.A429 */
893 { 0x0.F4C20p0
, -1, 0xf4a1b, 0x09bbf0b0}, /* :D B1.7A61 */
894 { 0x0.CD080p0
, -1, 0xca348, 0x79b907ae}, /* :E A2.6684 */
895 { 0x1.76B20p0
, 0, 0x35b67, 0x81aed827} /* :F DB.BB59 */
898 /* 0x1.00000 00000000p-3 */
899 /* set up the invariant fields of B, the arg to cause rounding */
903 /* set up args so result is always Z = 1.200000000000<g>p+0 */
910 op" %0, %1, %2, %3\n\t" \
911 : "=f"(fD) : "f"(fA) , "f"(fB), "f"(fC));
915 op" %0, %1, %2\n\t" \
916 : "=f"(fD) : "f"(fA) , "f"(fB));
921 : "=f"(fD) : "f"(fA));
923 for (mode
= TO_NEAREST
; mode
<= TO_MINUS_INFINITY
; mode
++)
924 for (s
= (op
!= FSQRT
? -1 : 1); s
< 2; s
+= 2)
925 for (g
= 0; g
< 16; g
+= 1) {
926 double lo
, hi
, expected
;
932 ** one argument will have exponent = 0 as will the result (by
933 ** design) so choose the other argument with exponent -3 to
934 ** force a 3 bit shift for scaling leaving us with 3 guard bits
935 ** and the LSB bit at the bottom of the manitssa.
939 /* 1p+0 + 1.000000000000<g>p-3 */
940 B
.layout
.frac_lo
= g
;
945 /* set up Z to be truncated result */
947 /* mask off LSB from resulting guard bits */
950 Z
.layout
.frac_hi
= 0x20000;
951 Z
.layout
.frac_lo
= g
>> 3;
955 /* 1.2000000000002p+0 - 1.000000000000<g>p-3 */
957 /* add enough to avoid scaling of the result */
958 A
.layout
.frac_lo
= 0x2;
961 B
.layout
.frac_lo
= g
;
964 /* set up Z to be truncated result */
966 Z
.layout
.frac_hi
= 0x0;
967 Z
.layout
.frac_lo
= guard
>>3;
969 /* mask off LSB from resulting guard bits */
975 A
.layout
.frac_lo
= g
;
979 /* set up Z to be truncated result */
981 Z
.layout
.frac_hi
= 0x20000;
982 Z
.layout
.frac_lo
= g
+ (g
>>3);
991 A
.layout
.frac_lo
= g
;
995 /* 1.0000000000001p-1 */
997 A
.layout
.frac_lo
= 1;
998 fC
= (op
== FMADD
|| op
== FNMADD
? s
: -s
)*A
.dbl
;
1000 /* set up Z to be truncated result */
1001 z_sign
= (op
== FNMADD
|| op
== FNMSUB
? -s
: s
);
1002 guard
= ((g
& 7) + 0x4) & 7;
1004 Z
.layout
.frac_hi
= 0xa0000;
1005 Z
.layout
.frac_lo
= g
+ (g
>>3) + ((g
& 7)>> 2 ? 1 : 0);
1008 /* g >> 3 == LSB, g & 7 == guard bits */
1011 /* special case guard bits == 4, inexact tie */
1015 fA
= dbl_denorm_small
+ 2*dbl_denorm_small
;
1016 Z
.layout
.frac_lo
= 0x1;
1018 fA
= dbl_denorm_small
;
1021 fA
= s
*div_guard_cases
[g
].num
;
1022 fB
= div_guard_cases
[g
].den
;
1025 s
*div_guard_cases
[g
].num
,
1026 div_guard_cases
[g
].den
);
1028 Z
.layout
.frac_hi
= div_guard_cases
[g
].hi
;
1029 Z
.layout
.frac_lo
= div_guard_cases
[g
].lo
;
1033 fA
= s
*sqrt_guard_cases
[g
].arg
;
1035 Z
.layout
.exp
= sqrt_guard_cases
[g
].exp
+ 1023;
1036 Z
.layout
.frac_hi
= sqrt_guard_cases
[g
].hi
;
1037 Z
.layout
.frac_lo
= sqrt_guard_cases
[g
].lo
;
1039 if (g
& 1) guard
|= 1;
1040 /* don't have test cases for when X bit = 0 */
1041 if (guard
== 0 || guard
== 4) continue;
1044 assert("check_double_guarded_arithmetic_op: unexpected op",
1049 /* get LSB for tie breaking */
1050 LSB
= Z
.layout
.frac_lo
& 1;
1052 /* set up hi and lo */
1054 Z
.layout
.frac_lo
+= 1;
1059 /* look at 3 guard bits to determine expected rounding */
1062 case 1: case 2: case 3:
1065 case 4: /* tie: round to even */
1066 if (debug
) printf("tie: LSB = %d\n", LSB
);
1067 expected
= (LSB
== 0 ? lo
: hi
);
1069 case 5: case 6: case 7:
1073 assert("check_double_guarded_arithmetic_op: unexpected guard",
1080 case TO_PLUS_INFINITY
:
1085 expected
= (s
== 1 ? hi
: lo
);
1088 case TO_MINUS_INFINITY
:
1093 expected
= (s
== 1 ? lo
: hi
);
1098 set_rounding_mode(mode
);
1101 ** do the double precision dual operation just for comparison
1142 assert("check_double_guarded_arithmetic_op: unexpected op",
1152 if ((Res
.layout
.sign
!= Exp
.layout
.sign
) ||
1153 (Res
.layout
.exp
!= Exp
.layout
.exp
) ||
1154 (Res
.layout
.frac_lo
!= Exp
.layout
.frac_lo
) ||
1155 (Res
.layout
.frac_hi
!= Exp
.layout
.frac_hi
)) {
1163 printf("%s:%s:%s(%-13a",
1164 round_mode_name
[mode
], result
, flt_op_names
[op
], fA
);
1165 if (arg_count
> 1) printf(", %-13a", fB
);
1166 if (arg_count
> 2) printf(", %-13a", fC
);
1167 printf(") = %-13a", Res
.dbl
);
1168 if (status
) printf("\n\texpected %a", Exp
.dbl
);
1172 print_double("hi", hi
);
1173 print_double("lo", lo
);
1174 print_double("expected", expected
);
1175 print_double("got", Res
.dbl
);
1182 int test_float_arithmetic_ops()
1188 ** choose FP operands whose result should be rounded to either
1192 printf("-------------------------- %s --------------------------\n",
1193 "test rounding of float operators without guard bits");
1194 for (op
= FADDS
; op
<= FDIVS
; op
++) {
1195 status
|= check_single_arithmetic_op(op
);
1198 printf("-------------------------- %s --------------------------\n",
1199 "test rounding of float operators with guard bits");
1200 for (op
= FADDS
; op
<= FNMSUBS
; op
++) {
1201 status
|= check_single_guarded_arithmetic_op(op
);
1204 printf("-------------------------- %s --------------------------\n",
1205 "test rounding of double operators with guard bits");
1206 for (op
= FADD
; op
<= FSQRT
; op
++) {
1207 status
|= check_double_guarded_arithmetic_op(op
);
1220 status
|= test_dbl_to_float_convert("test denormalized convert", &denorm_small
);
1221 status
|= test_dbl_to_float_convert("test normalized convert", &norm_small
);
1222 status
|= test_int_to_float_convert("test (float)int convert");
1223 status
|= test_int_to_float_convert("test (float)int convert");
1225 #ifdef __powerpc64__
1226 status
|= test_long_to_double_convert("test (double)long convert");
1228 status
|= test_float_arithmetic_ops();