1a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
2a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj/*  Copyright (C) 2006 Dave Nomura
3a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj       dcnltc@us.ibm.com
4a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
5a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    This program is free software; you can redistribute it and/or
6a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    modify it under the terms of the GNU General Public License as
7a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    published by the Free Software Foundation; either version 2 of the
8a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    License, or (at your option) any later version.
9a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
10a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    This program is distributed in the hope that it will be useful, but
11a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    WITHOUT ANY WARRANTY; without even the implied warranty of
12a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    General Public License for more details.
14a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
15a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    You should have received a copy of the GNU General Public License
16a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    along with this program; if not, write to the Free Software
17a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    02111-1307, USA.
19a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
20a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj    The GNU General Public License is contained in the file COPYING.
21a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj*/
22a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
23a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#include <stdio.h>
24a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#include <stdlib.h>
25a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#include <limits.h>
26a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
27a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjtypedef enum { FALSE=0, TRUE } bool_t;
28a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
29a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjtypedef enum {
30a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	FADDS, FSUBS, FMULS, FDIVS,
31a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	FMADDS, FMSUBS, FNMADDS, FNMSUBS,
32a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	FADD, FSUB, FMUL, FDIV, FMADD,
33a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	FMSUB, FNMADD, FNMSUB, FSQRT
34a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj} flt_op_t;
35a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
36a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjtypedef enum {
37a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	TO_NEAREST=0, TO_ZERO, TO_PLUS_INFINITY, TO_MINUS_INFINITY } round_mode_t;
38a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjchar *round_mode_name[] = { "near", "zero", "+inf", "-inf" };
39a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
40a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjconst char *flt_op_names[] = {
41a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	"fadds", "fsubs", "fmuls", "fdivs",
42a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	"fmadds", "fmsubs", "fnmadds", "fnmsubs",
43a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	"fadd", "fsub", "fmul", "fdiv", "fmadd", "fmsub", "fnmadd",
44a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	"fnmsub", "fsqrt"
45a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj};
46a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
47a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjtypedef unsigned int fpscr_t;
48a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
49a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjtypedef union {
50a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	float flt;
51a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	struct {
52ee55dc246230e70529b70c4bfb431db66e51525ccarll#if defined(VGP_ppc64le_linux)
53ee55dc246230e70529b70c4bfb431db66e51525ccarll      unsigned int frac:23;
54ee55dc246230e70529b70c4bfb431db66e51525ccarll      unsigned int exp:8;
55ee55dc246230e70529b70c4bfb431db66e51525ccarll      unsigned int sign:1;
56ee55dc246230e70529b70c4bfb431db66e51525ccarll#else
57a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		unsigned int sign:1;
58a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		unsigned int exp:8;
59a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		unsigned int frac:23;
60ee55dc246230e70529b70c4bfb431db66e51525ccarll#endif
61a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	} layout;
62a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj} flt_overlay;
63a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
64a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjtypedef union {
65a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	double dbl;
66a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	struct {
67ee55dc246230e70529b70c4bfb431db66e51525ccarll#if defined(VGP_ppc64le_linux)
68ee55dc246230e70529b70c4bfb431db66e51525ccarll      unsigned int frac_lo:32;
69ee55dc246230e70529b70c4bfb431db66e51525ccarll      unsigned int frac_hi:20;
70ee55dc246230e70529b70c4bfb431db66e51525ccarll      unsigned int exp:11;
71ee55dc246230e70529b70c4bfb431db66e51525ccarll      unsigned int sign:1;
72ee55dc246230e70529b70c4bfb431db66e51525ccarll#else
73a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		unsigned int sign:1;
74a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		unsigned int exp:11;
75a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		unsigned int frac_hi:20;
76a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		unsigned int frac_lo:32;
77ee55dc246230e70529b70c4bfb431db66e51525ccarll#endif
78a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	} layout;
79a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	struct {
80a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		unsigned int hi;
81a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		unsigned int lo;
82a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	} dbl_pair;
83a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj} dbl_overlay;
84a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
85a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjvoid assert_fail(const char *msg,
86a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	const char* expr, const char* file, int line, const char*fn);
87a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
88a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#define STRING(__str)  #__str
89a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#define assert(msg, expr)                                           \
90a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj  ((void) ((expr) ? 0 :                                         \
91a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj           (assert_fail (msg, STRING(expr),                  \
92a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj                             __FILE__, __LINE__,                \
93a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj                             __PRETTY_FUNCTION__), 0)))
94a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjfloat denorm_small;
95a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjdouble dbl_denorm_small;
96a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjfloat norm_small;
97a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjbool_t debug = FALSE;
98a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjbool_t long_is_64_bits = sizeof(long) == 8;
99a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
100a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjvoid assert_fail (msg, expr, file, line, fn)
101a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjconst char* msg;
102a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjconst char* expr;
103a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjconst char* file;
104a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint line;
105a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjconst char*fn;
106a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
107a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj   printf( "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
108a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj               msg, file, line, fn, expr );
109a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj   exit( 1 );
110a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
111a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjvoid set_rounding_mode(round_mode_t mode)
112a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
113a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	switch(mode) {
114a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	case TO_NEAREST:
115a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		asm volatile("mtfsfi 7, 0");
116a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		break;
117a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	case TO_ZERO:
118a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		asm volatile("mtfsfi 7, 1");
119a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		break;
120a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	case TO_PLUS_INFINITY:
121a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		asm volatile("mtfsfi 7, 2");
122a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		break;
123a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	case TO_MINUS_INFINITY:
124a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		asm volatile("mtfsfi 7, 3");
125a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		break;
126a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
127a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
128a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
129a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjvoid print_double(char *msg, double dbl)
130a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
131a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	dbl_overlay D;
132a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	D.dbl = dbl;
133a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
134a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	printf("%15s : dbl %-20a = %c(%4d, %05x%08x)\n",
135a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			msg, D.dbl, (D.layout.sign == 0 ? '+' : '-'),
136a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			D.layout.exp, D.layout.frac_hi, D.layout.frac_lo);
137a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
138a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
139a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjvoid print_single(char *msg, float *flt)
140a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
141a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	flt_overlay F;
142a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	F.flt = *flt;
143a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
144a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/* NOTE: for the purposes of comparing the fraction of a single with
145a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	**       a double left shift the .frac so that hex digits are grouped
146a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	**	     from left to right.  this is necessary because the size of a
147a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	**		 single mantissa (23) bits is not a multiple of 4
148a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	*/
149a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	printf("%15s : flt %-20a = %c(%4d, %06x)\n",
150a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		msg, F.flt, (F.layout.sign == 0 ? '+' : '-'), F.layout.exp, F.layout.frac << 1);
151a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
152a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
153a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint check_dbl_to_flt_round(round_mode_t mode, double dbl, float *expected)
154a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
155a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int status = 0;
156a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	flt_overlay R, E;
157a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	char *result;
158a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
159a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	set_rounding_mode(mode);
160a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
161a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	E.flt = *expected;
162a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	R.flt = (float)dbl;
163a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
164a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	if ((R.layout.sign != E.layout.sign) ||
165a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		(R.layout.exp != E.layout.exp) ||
166a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		(R.layout.frac != E.layout.frac)) {
167a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		result = "FAILED";
168a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		status = 1;
169a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	} else {
170a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		result = "PASSED";
171a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		status = 0;
172a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
173a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	printf("%s:%s:(double)(%-20a) = %20a",
174a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		round_mode_name[mode], result, R.flt, dbl);
175a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	if (status) {
176a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		print_single("\n\texpected", &E.flt);
177a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		print_single("\n\trounded ", &R.flt);
178a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
179a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	putchar('\n');
180a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	return status;
181a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
182a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
183a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint test_dbl_to_float_convert(char *msg, float *base)
184a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
185a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int status = 0;
186a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	double half = (double)denorm_small/2;
187a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	double qtr = half/2;
188a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	double D_hi = (double)*base + half + qtr;
189a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	double D_lo = (double)*base + half - qtr;
190a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	float F_lo = *base;
191a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	float F_hi = F_lo + denorm_small;
192a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
193a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
194a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/*
195a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	** .....+-----+-----+-----+-----+---....
196a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	**      ^F_lo ^           ^     ^
197a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	**            D_lo
198a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	**                        D_hi
199a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	**                              F_hi
200a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	** F_lo and F_hi are two consecutive single float model numbers
201a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	** denorm_small distance apart. D_lo and D_hi are two numbers
202a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	** within that range that are not representable as single floats
203a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	** and will be rounded to either F_lo or F_hi.
204a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	*/
205a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	printf("-------------------------- %s --------------------------\n", msg);
206a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	if (debug) {
207a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		print_double("D_lo", D_lo);
208a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		print_double("D_hi", D_hi);
209a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		print_single("F_lo", &F_lo);
210a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		print_single("F_hi", &F_hi);
211a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
212a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
213a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/* round to nearest */
214a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_dbl_to_flt_round(TO_NEAREST, D_hi, &F_hi);
215a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_dbl_to_flt_round(TO_NEAREST, D_lo, &F_lo);
216a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
217a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/* round to zero */
218a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_dbl_to_flt_round(TO_ZERO, D_hi, (D_hi > 0 ? &F_lo : &F_hi));
219a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_dbl_to_flt_round(TO_ZERO, D_lo, (D_hi > 0 ? &F_lo : &F_hi));
220a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
221a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/* round to +inf */
222a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_dbl_to_flt_round(TO_PLUS_INFINITY, D_hi, &F_hi);
223a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_dbl_to_flt_round(TO_PLUS_INFINITY, D_lo, &F_hi);
224a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
225a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/* round to -inf */
226a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_dbl_to_flt_round(TO_MINUS_INFINITY, D_hi, &F_lo);
227a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_dbl_to_flt_round(TO_MINUS_INFINITY, D_lo, &F_lo);
228a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	return status;
229a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
230a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
231a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjvoid
232a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjinit()
233a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
234a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	flt_overlay F;
235a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	dbl_overlay D;
236a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
237a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/* small is the smallest denormalized single float number */
238a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	F.layout.sign = 0;
239a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	F.layout.exp = 0;
240a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	F.layout.frac = 1;
241a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	denorm_small = F.flt;	/* == 2^(-149) */
242a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	if (debug) {
243ee55dc246230e70529b70c4bfb431db66e51525ccarll		print_single("float small", &F.flt);
244a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
245a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
246a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	D.layout.sign = 0;
247a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	D.layout.exp = 0;
248a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	D.layout.frac_hi = 0;
249a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	D.layout.frac_lo = 1;
250a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	dbl_denorm_small = D.dbl;	/* == 2^(-1022) */
251a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	if (debug) {
252a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		print_double("double small", D.dbl);
253a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
254a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
255a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/* n_small is the smallest normalized single precision float */
256a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	F.layout.exp = 1;
257a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	norm_small = F.flt;
258a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
259a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
260a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint check_int_to_flt_round(round_mode_t mode, long L, float *expected)
261a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
262a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int status = 0;
263a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int I = L;
264a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	char *int_name = "int";
265a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	flt_overlay R, E;
266a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	char *result;
267a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int iter;
268a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
269a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	set_rounding_mode(mode);
270a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	E.flt = *expected;
271a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
272a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	for (iter = 0; iter < 2; iter++) {
273a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int stat = 0;
274a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		R.flt = (iter == 0 ? (float)I : (float)L);
275a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
276a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if ((R.layout.sign != E.layout.sign) ||
277a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			(R.layout.exp != E.layout.exp) ||
278a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			(R.layout.frac != E.layout.frac)) {
279a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			result = "FAILED";
280a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			stat = 1;
281a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		} else {
282a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			result = "PASSED";
283a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			stat = 0;
284a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
285a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		printf("%s:%s:(float)(%4s)%9d = %11.1f",
286a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			round_mode_name[mode], result, int_name, I, R.flt);
287a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if (stat) {
288a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_single("\n\texpected: %.1f ", &E.flt);
289a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_single("\n\trounded ", &R.flt);
290a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
291a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		putchar('\n');
292a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		status |= stat;
293a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
294a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if (!long_is_64_bits) break;
295a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int_name = "long";
296a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
297a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	return status;
298a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
299a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
300a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint check_long_to_dbl_round(round_mode_t mode, long L, double *expected)
301a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
302a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int status = 0;
303a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	dbl_overlay R, E;
304a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	char *result;
305a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
306a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	set_rounding_mode(mode);
307a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	E.dbl = *expected;
308a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
309a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	R.dbl = (double)L;
310a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
311a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	if ((R.layout.sign != E.layout.sign) ||
312a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		(R.layout.exp != E.layout.exp) ||
313a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		(R.layout.frac_lo != E.layout.frac_lo) ||
314a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		(R.layout.frac_hi != E.layout.frac_hi)) {
315a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		result = "FAILED";
316a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		status = 1;
317a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	} else {
318a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		result = "PASSED";
319a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		status = 0;
320a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
321a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	printf("%s:%s:(double)(%18ld) = %20.1f",
322a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		round_mode_name[mode], result, L, R.dbl);
323a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	if (status) {
324a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		printf("\n\texpected %.1f : ", E.dbl);
325a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
326a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	putchar('\n');
327a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	return status;
328a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
329a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
330a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint test_int_to_float_convert(char *msg)
331a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
332a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int status = 0;
333a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int int24_hi = 0x03ff0fff;
334a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int int24_lo = 0x03ff0ffd;
335a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	float pos_flt_lo = 67047420.0;
336a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	float pos_flt_hi = 67047424.0;
337a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	float neg_flt_lo = -67047420.0;
338a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	float neg_flt_hi = -67047424.0;
339a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
340a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	printf("-------------------------- %s --------------------------\n", msg);
341a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_NEAREST, int24_lo, &pos_flt_lo);
342a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_NEAREST, int24_hi, &pos_flt_hi);
343a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_ZERO, int24_lo, &pos_flt_lo);
344a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_ZERO, int24_hi, &pos_flt_lo);
345a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_PLUS_INFINITY, int24_lo, &pos_flt_hi);
346a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_PLUS_INFINITY, int24_hi, &pos_flt_hi);
347a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_MINUS_INFINITY, int24_lo, &pos_flt_lo);
348a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_MINUS_INFINITY, int24_hi, &pos_flt_lo);
349a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
350a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_NEAREST, -int24_lo, &neg_flt_lo);
351a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_NEAREST, -int24_hi, &neg_flt_hi);
352a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_ZERO, -int24_lo, &neg_flt_lo);
353a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_ZERO, -int24_hi, &neg_flt_lo);
354a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_PLUS_INFINITY, -int24_lo, &neg_flt_lo);
355a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_PLUS_INFINITY, -int24_hi, &neg_flt_lo);
356a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_MINUS_INFINITY, -int24_lo, &neg_flt_hi);
357a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_int_to_flt_round(TO_MINUS_INFINITY, -int24_hi, &neg_flt_hi);
358a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	return status;
359a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
360a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
361a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#ifdef __powerpc64__
362a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint test_long_to_double_convert(char *msg)
363a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
364a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int status = 0;
365a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	long long55_hi = 0x07ff0ffffffffff;
366a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	long long55_lo = 0x07ff0fffffffffd;
367a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	double pos_dbl_lo = 36012304344547324.0;
368a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	double pos_dbl_hi = 36012304344547328.0;
369a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	double neg_dbl_lo = -36012304344547324.0;
370a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	double neg_dbl_hi = -36012304344547328.0;
371a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
372a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	printf("-------------------------- %s --------------------------\n", msg);
373a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_NEAREST, long55_lo, &pos_dbl_lo);
374a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_NEAREST, long55_hi, &pos_dbl_hi);
375a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_ZERO, long55_lo, &pos_dbl_lo);
376a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_ZERO, long55_hi, &pos_dbl_lo);
377a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_PLUS_INFINITY, long55_lo, &pos_dbl_hi);
378a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_PLUS_INFINITY, long55_hi, &pos_dbl_hi);
379a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_MINUS_INFINITY, long55_lo, &pos_dbl_lo);
380a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_MINUS_INFINITY, long55_hi, &pos_dbl_lo);
381a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
382a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_NEAREST, -long55_lo, &neg_dbl_lo);
383a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_NEAREST, -long55_hi, &neg_dbl_hi);
384a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_ZERO, -long55_lo, &neg_dbl_lo);
385a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_ZERO, -long55_hi, &neg_dbl_lo);
386a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_PLUS_INFINITY, -long55_lo, &neg_dbl_lo);
387a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_PLUS_INFINITY, -long55_hi, &neg_dbl_lo);
388a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_MINUS_INFINITY, -long55_lo, &neg_dbl_hi);
389a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= check_long_to_dbl_round(TO_MINUS_INFINITY, -long55_hi, &neg_dbl_hi);
390a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	return status;
391a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
392a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#endif
393a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
394a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint check_single_arithmetic_op(flt_op_t op)
395a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
396a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		char *result;
397a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        int status = 0;
398a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        dbl_overlay R, E;
399a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        double qtr, half, fA, fB, fD;
400a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		round_mode_t mode;
401a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int q, s;
402a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		bool_t two_args = TRUE;
403a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		float whole = denorm_small;
404a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
405a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#define BINOP(op) \
406a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        __asm__ volatile( \
407a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					op" %0, %1, %2\n\t" \
408a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					: "=f"(fD) : "f"(fA) , "f"(fB));
409a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#define UNOP(op) \
410a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        __asm__ volatile( \
411a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					op" %0, %1\n\t" \
412a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					: "=f"(fD) : "f"(fA));
413a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
414a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		half = (double)whole/2;
415a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		qtr = half/2;
416a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
417a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if (debug) {
418a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_double("qtr", qtr);
419a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_double("whole", whole);
420a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_double("2*whole", 2*whole);
421a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
422a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
423a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		for (mode = TO_NEAREST; mode <= TO_MINUS_INFINITY; mode++)
424a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		for (s = -1; s < 2; s += 2)
425a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		for (q = 1; q < 4; q += 2) {
426a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			double expected;
427a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			double lo = s*whole;
428a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			double hi = s*2*whole;
429a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
430a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			switch(op) {
431a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case FADDS:
432a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fA = s*whole;
433a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fB = s*q*qtr;
434a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
435a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case FSUBS:
436a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fA = s*2*whole;
437a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fB = s*(q == 1 ? 3 : 1)*qtr;
438a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
439a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case FMULS:
440a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fA = 0.5;
441a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fB = s*(4+q)*half;
442a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
443a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case FDIVS:
444a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fA = s*(4+q)*half;
445a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fB = 2.0;
446a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
447a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			default:
448a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				assert("check_single_arithmetic_op: unexpected op",
449a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					FALSE);
450a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
451a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
452a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
453a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			switch(mode) {
454a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case TO_NEAREST:
455a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = (q == 1 ? lo : hi);
456a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
457a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case TO_ZERO:
458a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = lo;
459a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
460a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case TO_PLUS_INFINITY:
461a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = (s == 1 ? hi : lo);
462a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
463a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case TO_MINUS_INFINITY:
464a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = (s == 1 ? lo : hi);
465a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
466a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
467a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
468a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			set_rounding_mode(mode);
469a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
470a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/*
471a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			** do the double precision dual operation just for comparison
472a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			** when debugging
473a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			*/
474a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			switch(op) {
475a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case FADDS:
476a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				BINOP("fadds");
477a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				R.dbl = fD;
478a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				BINOP("fadd");
479a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
480a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case FSUBS:
481a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				BINOP("fsubs");
482a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				R.dbl = fD;
483a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				BINOP("fsub");
484a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
485a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case FMULS:
486a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				BINOP("fmuls");
487a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				R.dbl = fD;
488a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				BINOP("fmul");
489a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
490a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case FDIVS:
491a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				BINOP("fdivs");
492a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				R.dbl = fD;
493a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				BINOP("fdiv");
494a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
495a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			default:
496a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				assert("check_single_arithmetic_op: unexpected op",
497a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					FALSE);
498a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
499a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
500a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#undef UNOP
501a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#undef BINOP
502a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
503a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			E.dbl = expected;
504a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
505a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if ((R.layout.sign != E.layout.sign) ||
506a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				(R.layout.exp != E.layout.exp) ||
507a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				(R.layout.frac_lo != E.layout.frac_lo) ||
508a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				(R.layout.frac_hi != E.layout.frac_hi)) {
509a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				result = "FAILED";
510a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				status = 1;
511a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			} else {
512a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				result = "PASSED";
513a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				status = 0;
514a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
515a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
516a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			printf("%s:%s:%s(%-13a",
517a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				round_mode_name[mode], result, flt_op_names[op], fA);
518a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if (two_args) printf(", %-13a", fB);
519a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			printf(") = %-13a", R.dbl);
520a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if (status) printf("\n\texpected %a", E.dbl);
521a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			putchar('\n');
522a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
523a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if (debug) {
524a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				print_double("hi", hi);
525a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				print_double("lo", lo);
526a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				print_double("expected", expected);
527a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				print_double("got", R.dbl);
528a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				print_double("double result", fD);
529a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
530a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
531a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
532a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		return status;
533a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
534a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
535a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint check_single_guarded_arithmetic_op(flt_op_t op)
536a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
537a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		typedef struct {
538a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			int num, den, frac;
539a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		} fdivs_t;
540a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
541a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		char *result;
542a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        int status = 0;
543a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        flt_overlay A, B, Z;
544a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        dbl_overlay Res, Exp;
545a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        double fA, fB, fC, fD;
546a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		round_mode_t mode;
547a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int g, s;
548a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int arg_count;
549a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
550a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		fdivs_t divs_guard_cases[16] = {
551a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 105, 56, 0x700000 },  /* : 0 */
552a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 100, 57, 0x608FB8 },  /* : 1 */
553a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 000, 00, 0x000000 },  /* : X */
554a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 100, 52, 0x762762 },  /* : 3 */
555a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 000, 00, 0x000000 },  /* : X */
556a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 100, 55, 0x68BA2E },  /* : 5 */
557a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 000, 00, 0x000000 },  /* : X */
558a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 100, 51, 0x7AFAFA },  /* : 7 */
559a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 000, 00, 0x000000 },  /* : X */
560a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 100, 56, 0x649249 },  /* : 9 */
561a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 000, 00, 0x000000 },  /* : X */
562a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 100, 54, 0x6D097B },  /* : B */
563a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 000, 00, 0x000000 },  /* : X */
564a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 100, 59, 0x58F2FB },  /* : D */
565a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 000, 00, 0x000000 },  /* : X */
566a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			{ 101, 52, 0x789D89 }  /* : F */
567a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		};
568a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
569a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		/*	0x1.00000 00000000p-3 */
570a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		/* set up the invariant fields of B, the arg to cause rounding */
571a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		B.flt = 0.0;
572a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		B.layout.exp = 124;  /* -3 */
573a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
574a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		/* set up args so result is always Z = 1.200000000000<g>p+0 */
575a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		Z.flt = 1.0;
576a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		Z.layout.sign = 0;
577a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
578a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#define TERNOP(op) \
579a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		arg_count = 3; \
580a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        __asm__ volatile( \
581a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					op" %0, %1, %2, %3\n\t" \
582a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					: "=f"(fD) : "f"(fA) , "f"(fB), "f"(fC));
583a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#define BINOP(op) \
584a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		arg_count = 2; \
585a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        __asm__ volatile( \
586a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					op" %0, %1, %2\n\t" \
587a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					: "=f"(fD) : "f"(fA) , "f"(fB));
588a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#define UNOP(op) \
589a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		arg_count = 1; \
590a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        __asm__ volatile( \
591a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					op" %0, %1\n\t" \
592a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					: "=f"(fD) : "f"(fA));
593a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
594a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	for (mode = TO_NEAREST; mode <= TO_MINUS_INFINITY; mode++)
595a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	for (s = -1; s < 2; s += 2)
596a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	for (g = 0; g < 16; g += 1) {
597a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		double lo, hi, expected;
598a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int LSB;
599a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int guard = 0;
600a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int z_sign = s;
601a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
602a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		/*
603a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** one argument will have exponent = 0 as will the result (by
604a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** design) so choose the other argument with exponent -3 to
605a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** force a 3 bit shift for scaling leaving us with 3 guard bits
606a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** and the LSB bit at the bottom of the manitssa.
607a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		*/
608a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		switch(op) {
609a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FADDS:
610a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* 1p+0 + 1.00000<g>p-3 */
611a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			B.layout.frac = g;
612a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
613a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fB = s*B.flt;
614a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fA = s*1.0;
615a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
616a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* set up Z to be truncated result */
617a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
618a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* mask off LSB from resulting guard bits */
619a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard = g & 7;
620a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
621a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac = 0x100000 | (g >> 3);
622a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
623a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FSUBS:
624a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* 1.200002p+0 - 1.000000000000<g>p-3 */
625a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.flt = 1.125;
626a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* add enough to avoid scaling of the result */
627a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.layout.frac |= 0x2;
628a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fA = s*A.flt;
629a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
630a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			B.layout.frac = g;
631a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fB = s*B.flt;
632a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
633a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* set up Z to be truncated result */
634a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard = (0x10-g);
635a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac = guard>>3;
636a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
637a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* mask off LSB from resulting guard bits */
638a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard &= 7;
639a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
640a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMULS:
641a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* 1 + g*2^-23 */
642a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.flt = 1.0;
643a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.layout.frac = g;
644a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fA = s*A.flt;
645a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fB = 1.125;
646a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
647a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* set up Z to be truncated result */
648a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.flt = 1.0;
649a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac = 0x100000;
650a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac |= g + (g>>3);
651a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard = g & 7;
652a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
653a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FDIVS:
654a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* g >> 3 == LSB, g & 7 == guard bits */
655a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard = g & 7;
656a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if ((guard & 1) == 0) {
657a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				/* special case: guard bit X = 0 */
658a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				A.flt = denorm_small;
659a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				A.layout.frac = g;
660a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fA = A.flt;
661a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fB = s*8.0;
662a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				Z.flt = 0.0;
663a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				Z.layout.frac |= (g >> 3);
664a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			} else {
665a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fA = s*divs_guard_cases[g].num;
666a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fB = divs_guard_cases[g].den;
667a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
668a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				Z.flt = 1.0;
669a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				Z.layout.frac = divs_guard_cases[g].frac;
670a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
671a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
672a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMADDS:
673a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMSUBS:
674a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FNMADDS:
675a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FNMSUBS:
676a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* 1 + g*2^-23 */
677a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.flt = 1.0;
678a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.layout.frac = g;
679a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fA = s*A.flt;
680a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fB = 1.125;
681a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
682a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* 1.000001p-1 */
683a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.flt = 0.5;
684a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.layout.frac = 1;
685a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fC = (op == FMADDS || op == FNMADDS ? s : -s)*A.flt;
686a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
687a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* set up Z to be truncated result */
688a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			z_sign = (op == FNMADDS || op == FNMSUBS ? -s : s);
689a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard = ((g & 7) + 0x4) & 7;
690a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.flt = 1.0;
691a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac = 0x500000;
692a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac |= g + (g>>3) + ((g & 7)>> 2 ? 1 : 0);
693a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
694a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		default:
695a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			assert("check_single_arithmetic_op: unexpected op",
696a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				FALSE);
697a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
698a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
699a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
700a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		/* get LSB for tie breaking */
701a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		LSB = Z.layout.frac & 1;
702a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
703a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		/* set up hi and lo */
704a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		lo = z_sign*Z.flt;
705a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		Z.layout.frac += 1;
706a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		hi = z_sign*Z.flt;
707a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
708a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		switch(mode) {
709a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case TO_NEAREST:
710a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* look at 3 guard bits to determine expected rounding */
711a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			switch(guard) {
712a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case 0:
713a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case 1: case 2: case 3:
714a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = lo;
715a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
716a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case 4:	/* tie: round to even */
717a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				if (debug) printf("tie: LSB = %d\n", LSB);
718a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = (LSB == 0 ? lo : hi);
719a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
720a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case 5: case 6: case 7:
721a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = hi;
722a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
723a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			default:
724a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				assert("check_single_guarded_arithmetic_op: unexpected guard",
725a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					FALSE);
726a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
727a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
728a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case TO_ZERO:
729a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			expected = lo;
730a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
731a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case TO_PLUS_INFINITY:
732a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if (guard == 0) {
733a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				/* no rounding */
734a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = lo;
735a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			} else {
736a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = (s == 1 ? hi : lo);
737a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
738a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
739a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case TO_MINUS_INFINITY:
740a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if (guard == 0) {
741a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				/* no rounding */
742a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = lo;
743a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			} else {
744a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = (s == 1 ? lo : hi);
745a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
746a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
747a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
748a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
749a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		set_rounding_mode(mode);
750a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
751a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		/*
752a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** do the double precision dual operation just for comparison
753a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** when debugging
754a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		*/
755a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		switch(op) {
756a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FADDS:
757a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			BINOP("fadds");
758a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
759a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
760a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FSUBS:
761a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			BINOP("fsubs");
762a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
763a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
764a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMULS:
765a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			BINOP("fmuls");
766a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
767a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
768a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FDIVS:
769a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			BINOP("fdivs");
770a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
771a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
772a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMADDS:
773a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			TERNOP("fmadds");
774a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
775a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
776a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMSUBS:
777a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			TERNOP("fmsubs");
778a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
779a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
780a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FNMADDS:
781a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			TERNOP("fnmadds");
782a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
783a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
784a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FNMSUBS:
785a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			TERNOP("fnmsubs");
786a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
787a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
788a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		default:
789a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			assert("check_single_guarded_arithmetic_op: unexpected op",
790a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				FALSE);
791a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
792a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
793a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#undef UNOP
794a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#undef BINOP
795a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#undef TERNOP
796a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
797a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		Exp.dbl = expected;
798a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
799a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if ((Res.layout.sign != Exp.layout.sign) ||
800a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			(Res.layout.exp != Exp.layout.exp) ||
801a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			(Res.layout.frac_lo != Exp.layout.frac_lo) ||
802a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			(Res.layout.frac_hi != Exp.layout.frac_hi)) {
803a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			result = "FAILED";
804a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			status = 1;
805a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		} else {
806a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			result = "PASSED";
807a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			status = 0;
808a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
809a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
810ee55dc246230e70529b70c4bfb431db66e51525ccarll		/* There seems to be some noise in the lower bits. The value
811ee55dc246230e70529b70c4bfb431db66e51525ccarll		* on the least significant digit seems to vary when printing
812ee55dc246230e70529b70c4bfb431db66e51525ccarll		* based on the rounding mode of the compiler.  Just trying
813ee55dc246230e70529b70c4bfb431db66e51525ccarll		* to get rid of the noise in the least significant bits when
814ee55dc246230e70529b70c4bfb431db66e51525ccarll		* printing the operand.
815ee55dc246230e70529b70c4bfb431db66e51525ccarll		*/
816ee55dc246230e70529b70c4bfb431db66e51525ccarll
817ee55dc246230e70529b70c4bfb431db66e51525ccarll		fA = ((long int)(fA*10000))/10000.0;
818ee55dc246230e70529b70c4bfb431db66e51525ccarll		/* Change -0.0 to a positive 0.0.  Some compilers print -0.0
819ee55dc246230e70529b70c4bfb431db66e51525ccarll		 * others do not.  Make it consistent.
820ee55dc246230e70529b70c4bfb431db66e51525ccarll		 */
821ee55dc246230e70529b70c4bfb431db66e51525ccarll		if (fA == -0.0)
822ee55dc246230e70529b70c4bfb431db66e51525ccarll		  fA = 0.0;
823ee55dc246230e70529b70c4bfb431db66e51525ccarll
824ee55dc246230e70529b70c4bfb431db66e51525ccarll		printf("%s:%s:%s(%-13.6f",
825a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			round_mode_name[mode], result, flt_op_names[op], fA);
826a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if (arg_count > 1) printf(", %-13a", fB);
827a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if (arg_count > 2) printf(", %-13a", fC);
828a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		printf(") = %-13a", Res.dbl);
829a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if (status) printf("\n\texpected %a", Exp.dbl);
830a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		putchar('\n');
831a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
832a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if (debug) {
833a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_double("hi", hi);
834a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_double("lo", lo);
835a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_double("expected", expected);
836a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_double("got", Res.dbl);
837a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
838a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
839a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
840a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	return status;
841a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
842a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
843a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint check_double_guarded_arithmetic_op(flt_op_t op)
844a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
845a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	typedef struct {
846a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int num, den, hi, lo;
847a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	} fdiv_t;
848a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	typedef struct {
849a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		double arg;
850a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int exp, hi, lo;
851a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	} fsqrt_t;
852a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
853a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	char *result;
854a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int status = 0;
855a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	dbl_overlay A, B, Z;
856a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	dbl_overlay Res, Exp;
857a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	double fA, fB, fC, fD;
858a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	round_mode_t mode;
859a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int g, s;
860a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int arg_count;
861a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	fdiv_t div_guard_cases[16] = {
862a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 62, 62, 0x00000, 0x00000000 },	/* 0 */
863a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 64, 62, 0x08421, 0x08421084 },	/* 1 */
864a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 66, 62, 0x10842, 0x10842108 },	/* 2 */
865a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 100, 62, 0x9ce73, 0x9ce739ce },	/* 3 */
866a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 100, 62, 0x9ce73, 0x9ce739ce },	/* X */
867a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 102, 62, 0xa5294, 0xa5294a52 },	/* 5 */
868a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 106, 62, 0xb5ad6, 0xb5ad6b5a },	/* 6 */
869a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 108, 62, 0xbdef7, 0xbdef7bde },	/* 7 */
870a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 108, 108, 0x00000, 0x00000000 },	/* 8 */
871a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 112, 62, 0xce739, 0xce739ce7 },	/* 9 */
872a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 114, 62, 0xd6b5a, 0xd6b5ad6b },	/* A */
873a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 116, 62, 0xdef7b, 0xdef7bdef },	/* B */
874a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 84, 62, 0x5ad6b, 0x5ad6b5ad },	/* X */
875a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 118, 62, 0xe739c, 0xe739ce73 },	/* D */
876a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 90, 62, 0x739ce, 0x739ce739 },	/* E */
877a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		{ 92, 62, 0x7bdef, 0x7bdef7bd }		/* F */
878a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	};
879a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
880a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
881a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	fsqrt_t sqrt_guard_cases[16] = {
882e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x1.08800p0,  0, 0x04371, 0xd9ab72fb}, /* :0 B8.8440  */
883e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x0.D2200p0, -1, 0xcfdca, 0xf353049e}, /* :1 A4.6910  */
884e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x1.A8220p0,  0, 0x49830, 0x2b49cd6d}, /* :2 E9.D411  */
885e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x1.05A20p0,  0, 0x02cd1, 0x3b44f3bf}, /* :3 B7.82D1  */
886e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x0.CA820p0, -1, 0xc7607, 0x3cec0937}, /* :4 A1.6541  */
887e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x1.DCA20p0,  0, 0x5d4f8, 0xd4e4c2b2}, /* :5 F7.EE51  */
888e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x1.02C80p0,  0, 0x01630, 0x9cde7483}, /* :6 B6.8164  */
889e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x0.DC800p0, -1, 0xdb2cf, 0xe686fe7c}, /* :7 A8.6E40  */
890e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x0.CF920p0, -1, 0xcd089, 0xb6860626}, /* :8 A3.67C9  */
891e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x1.1D020p0,  0, 0x0e1d6, 0x2e78ed9d}, /* :9 BF.8E81  */
892e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x0.E1C80p0, -1, 0xe0d52, 0x6020fb6b}, /* :A AA.70E4  */
893e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x0.C8000p0, -1, 0xc48c6, 0x001f0abf}, /* :B A0.6400  */
894e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x1.48520p0,  0, 0x21e9e, 0xd813e2e2}, /* :C CD.A429  */
895e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x0.F4C20p0, -1, 0xf4a1b, 0x09bbf0b0}, /* :D B1.7A61  */
896e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x0.CD080p0, -1, 0xca348, 0x79b907ae}, /* :E A2.6684  */
897e87dba33a7dc7c42e760b2af34dbf01affcbd330sewardj		{ 0x1.76B20p0,  0, 0x35b67, 0x81aed827}  /* :F DB.BB59  */
898a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	};
899a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
900a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/*	0x1.00000 00000000p-3 */
901a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/* set up the invariant fields of B, the arg to cause rounding */
902a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	B.dbl = 0.0;
903a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	B.layout.exp = 1020;
904a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
905a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/* set up args so result is always Z = 1.200000000000<g>p+0 */
906a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	Z.dbl = 1.0;
907a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	Z.layout.sign = 0;
908a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
909a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#define TERNOP(op) \
910a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		arg_count = 3; \
911a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        __asm__ volatile( \
912a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					op" %0, %1, %2, %3\n\t" \
913a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					: "=f"(fD) : "f"(fA) , "f"(fB), "f"(fC));
914a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#define BINOP(op) \
915a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		arg_count = 2; \
916a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        __asm__ volatile( \
917a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					op" %0, %1, %2\n\t" \
918a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					: "=f"(fD) : "f"(fA) , "f"(fB));
919a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#define UNOP(op) \
920a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		arg_count = 1; \
921a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj        __asm__ volatile( \
922a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					op" %0, %1\n\t" \
923a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					: "=f"(fD) : "f"(fA));
924a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
925a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	for (mode = TO_NEAREST; mode <= TO_MINUS_INFINITY; mode++)
926a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	for (s = (op != FSQRT ? -1 : 1); s < 2; s += 2)
927a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	for (g = 0; g < 16; g += 1) {
928a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		double lo, hi, expected;
929a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int LSB;
930a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int guard;
931a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		int z_sign = s;
932a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
933a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		/*
934a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** one argument will have exponent = 0 as will the result (by
935a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** design) so choose the other argument with exponent -3 to
936a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** force a 3 bit shift for scaling leaving us with 3 guard bits
937a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** and the LSB bit at the bottom of the manitssa.
938a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		*/
939a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		switch(op) {
940a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FADD:
941a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* 1p+0 + 1.000000000000<g>p-3 */
942a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			B.layout.frac_lo = g;
943a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
944a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fB = s*B.dbl;
945a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fA = s*1.0;
946a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
947a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* set up Z to be truncated result */
948a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
949a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* mask off LSB from resulting guard bits */
950a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard = g & 7;
951a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
952a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac_hi = 0x20000;
953a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac_lo = g >> 3;
954a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
955a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
956a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FSUB:
957a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* 1.2000000000002p+0 - 1.000000000000<g>p-3 */
958a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.dbl = 1.125;
959a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* add enough to avoid scaling of the result */
960a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.layout.frac_lo = 0x2;
961a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fA = s*A.dbl;
962a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
963a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			B.layout.frac_lo = g;
964a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fB = s*B.dbl;
965a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
966a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* set up Z to be truncated result */
967a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard = (0x10-g);
968a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac_hi = 0x0;
969a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac_lo = guard>>3;
970a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
971a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* mask off LSB from resulting guard bits */
972a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard &= 7;
973a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
974a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMUL:
975a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* 1 + g*2^-52 */
976a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.dbl = 1.0;
977a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.layout.frac_lo = g;
978a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fA = s*A.dbl;
979a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fB = 1.125;
980a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
981a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* set up Z to be truncated result */
982a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.dbl = 1.0;
983a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac_hi = 0x20000;
984a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac_lo = g + (g>>3);
985a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard = g & 7;
986a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
987a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMADD:
988a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMSUB:
989a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FNMADD:
990a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FNMSUB:
991a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* 1 + g*2^-52 */
992a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.dbl = 1.0;
993a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.layout.frac_lo = g;
994a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fA = s*A.dbl;
995a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fB = 1.125;
996a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
997a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* 1.0000000000001p-1 */
998a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.dbl = 0.5;
999a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			A.layout.frac_lo = 1;
1000a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fC = (op == FMADD || op == FNMADD ? s : -s)*A.dbl;
1001a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1002a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* set up Z to be truncated result */
1003a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			z_sign = (op == FNMADD || op == FNMSUB ? -s : s);
1004a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard = ((g & 7) + 0x4) & 7;
1005a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.dbl = 1.0;
1006a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac_hi = 0xa0000;
1007a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac_lo = g + (g>>3) + ((g & 7)>> 2 ? 1 : 0);
1008a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1009a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FDIV:
1010a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* g >> 3 == LSB, g & 7 == guard bits */
1011a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard = g & 7;
1012a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if (guard == 0x4) {
1013a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				/* special case guard bits == 4, inexact tie */
1014a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fB = s*2.0;
1015a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				Z.dbl = 0.0;
1016a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				if (g >> 3) {
1017a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					fA = dbl_denorm_small + 2*dbl_denorm_small;
1018a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					Z.layout.frac_lo = 0x1;
1019a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				} else {
1020a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					fA = dbl_denorm_small;
1021a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				}
1022a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			} else {
1023a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fA = s*div_guard_cases[g].num;
1024a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				fB = div_guard_cases[g].den;
1025a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1026a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				printf("%d/%d\n",
1027a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					s*div_guard_cases[g].num,
1028a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					div_guard_cases[g].den);
1029a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				Z.dbl = 1.0;
1030a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				Z.layout.frac_hi = div_guard_cases[g].hi;
1031a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				Z.layout.frac_lo = div_guard_cases[g].lo;
1032a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
1033a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1034a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FSQRT:
1035a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			fA = s*sqrt_guard_cases[g].arg;
1036a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.dbl = 1.0;
1037a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.exp = sqrt_guard_cases[g].exp + 1023;
1038a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac_hi = sqrt_guard_cases[g].hi;
1039a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Z.layout.frac_lo = sqrt_guard_cases[g].lo;
1040a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			guard = g >> 1;
1041a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if (g & 1) guard |= 1;
1042a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* don't have test cases for when X bit = 0 */
1043a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if (guard == 0 || guard == 4) continue;
1044a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1045a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		default:
1046a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			assert("check_double_guarded_arithmetic_op: unexpected op",
1047a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				FALSE);
1048a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1049a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
1050a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1051a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		/* get LSB for tie breaking */
1052a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		LSB = Z.layout.frac_lo & 1;
1053a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1054a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		/* set up hi and lo */
1055a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		lo = z_sign*Z.dbl;
1056a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		Z.layout.frac_lo += 1;
1057a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		hi = z_sign*Z.dbl;
1058a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1059a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		switch(mode) {
1060a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case TO_NEAREST:
1061a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			/* look at 3 guard bits to determine expected rounding */
1062a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			switch(guard) {
1063a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case 0:
1064a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case 1: case 2: case 3:
1065a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = lo;
1066a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
1067a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case 4:	/* tie: round to even */
1068a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				if (debug) printf("tie: LSB = %d\n", LSB);
1069a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = (LSB == 0 ? lo : hi);
1070a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
1071a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			case 5: case 6: case 7:
1072a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = hi;
1073a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				break;
1074a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			default:
1075a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				assert("check_double_guarded_arithmetic_op: unexpected guard",
1076a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj					FALSE);
1077a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
1078a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1079a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case TO_ZERO:
1080a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			expected = lo;
1081a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1082a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case TO_PLUS_INFINITY:
1083a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if (guard == 0) {
1084a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				/* no rounding */
1085a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = lo;
1086a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			} else {
1087a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = (s == 1 ? hi : lo);
1088a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
1089a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1090a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case TO_MINUS_INFINITY:
1091a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			if (guard == 0) {
1092a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				/* no rounding */
1093a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = lo;
1094a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			} else {
1095a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				expected = (s == 1 ? lo : hi);
1096a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			}
1097a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1098a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
1099a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1100a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		set_rounding_mode(mode);
1101a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1102a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		/*
1103a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** do the double precision dual operation just for comparison
1104a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		** when debugging
1105a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		*/
1106a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		switch(op) {
1107a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FADD:
1108a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			BINOP("fadd");
1109a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
1110a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1111a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FSUB:
1112a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			BINOP("fsub");
1113a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
1114a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1115a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMUL:
1116a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			BINOP("fmul");
1117a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
1118a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1119a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMADD:
1120a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			TERNOP("fmadd");
1121a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
1122a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1123a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FMSUB:
1124a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			TERNOP("fmsub");
1125a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
1126a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1127a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FNMADD:
1128a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			TERNOP("fnmadd");
1129a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
1130a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1131a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FNMSUB:
1132a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			TERNOP("fnmsub");
1133a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
1134a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1135a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FDIV:
1136a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			BINOP("fdiv");
1137a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
1138a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1139a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		case FSQRT:
1140a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			UNOP("fsqrt");
1141a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			Res.dbl = fD;
1142a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1143a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		default:
1144a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			assert("check_double_guarded_arithmetic_op: unexpected op",
1145a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj				FALSE);
1146a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			break;
1147a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
1148a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#undef UNOP
1149a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#undef BINOP
1150a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#undef TERNOP
1151a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1152a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		Exp.dbl = expected;
1153a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1154a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if ((Res.layout.sign != Exp.layout.sign) ||
1155a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			(Res.layout.exp != Exp.layout.exp) ||
1156a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			(Res.layout.frac_lo != Exp.layout.frac_lo) ||
1157a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			(Res.layout.frac_hi != Exp.layout.frac_hi)) {
1158a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			result = "FAILED";
1159a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			status = 1;
1160a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		} else {
1161a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			result = "PASSED";
1162a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			status = 0;
1163a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
1164a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1165a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		printf("%s:%s:%s(%-13a",
1166a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			round_mode_name[mode], result, flt_op_names[op], fA);
1167a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if (arg_count > 1) printf(", %-13a", fB);
1168a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if (arg_count > 2) printf(", %-13a", fC);
1169a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		printf(") = %-13a", Res.dbl);
1170a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if (status) printf("\n\texpected %a", Exp.dbl);
1171a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		putchar('\n');
1172a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1173a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		if (debug) {
1174a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_double("hi", hi);
1175a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_double("lo", lo);
1176a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_double("expected", expected);
1177a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj			print_double("got", Res.dbl);
1178a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		}
1179a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
1180a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1181a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	return status;
1182a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
1183a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1184a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint test_float_arithmetic_ops()
1185a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
1186a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int status = 0;
1187a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	flt_op_t op;
1188a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1189a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	/*
1190a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	** choose FP operands whose result should be rounded to either
1191a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	** lo or hi.
1192a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	*/
1193a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1194a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	printf("-------------------------- %s --------------------------\n",
1195a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		"test rounding of float operators without guard bits");
1196a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	for (op = FADDS; op <= FDIVS; op++) {
1197a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		status |= check_single_arithmetic_op(op);
1198a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
1199a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1200a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	printf("-------------------------- %s --------------------------\n",
1201a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		"test rounding of float operators with guard bits");
1202a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	for (op = FADDS; op <= FNMSUBS; op++) {
1203a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		status |= check_single_guarded_arithmetic_op(op);
1204a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
1205a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1206a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	printf("-------------------------- %s --------------------------\n",
1207a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		"test rounding of double operators with guard bits");
1208a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	for (op = FADD; op <= FSQRT; op++) {
1209a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj		status |= check_double_guarded_arithmetic_op(op);
1210a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	}
1211a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	return status;
1212a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
1213a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1214a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1215a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjint
1216a0d693b676ca016942849cb4243c3bfaae37f9bfsewardjmain()
1217a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj{
1218a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	int status = 0;
1219a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1220a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	init();
1221a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1222a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= test_dbl_to_float_convert("test denormalized convert", &denorm_small);
1223a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= test_dbl_to_float_convert("test normalized convert", &norm_small);
1224a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= test_int_to_float_convert("test (float)int convert");
1225a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= test_int_to_float_convert("test (float)int convert");
1226a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj
1227a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#ifdef __powerpc64__
1228a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= test_long_to_double_convert("test (double)long convert");
1229a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj#endif
1230a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	status |= test_float_arithmetic_ops();
1231a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj	return status;
1232a0d693b676ca016942849cb4243c3bfaae37f9bfsewardj}
1233