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