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