xref: /OK3568_Linux_fs/kernel/arch/x86/math-emu/fpu_trig.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*---------------------------------------------------------------------------+
3*4882a593Smuzhiyun  |  fpu_trig.c                                                               |
4*4882a593Smuzhiyun  |                                                                           |
5*4882a593Smuzhiyun  | Implementation of the FPU "transcendental" functions.                     |
6*4882a593Smuzhiyun  |                                                                           |
7*4882a593Smuzhiyun  | Copyright (C) 1992,1993,1994,1997,1999                                    |
8*4882a593Smuzhiyun  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
9*4882a593Smuzhiyun  |                       Australia.  E-mail   billm@melbpc.org.au            |
10*4882a593Smuzhiyun  |                                                                           |
11*4882a593Smuzhiyun  |                                                                           |
12*4882a593Smuzhiyun  +---------------------------------------------------------------------------*/
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include "fpu_system.h"
15*4882a593Smuzhiyun #include "exception.h"
16*4882a593Smuzhiyun #include "fpu_emu.h"
17*4882a593Smuzhiyun #include "status_w.h"
18*4882a593Smuzhiyun #include "control_w.h"
19*4882a593Smuzhiyun #include "reg_constant.h"
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun static void rem_kernel(unsigned long long st0, unsigned long long *y,
22*4882a593Smuzhiyun 		       unsigned long long st1, unsigned long long q, int n);
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define BETTER_THAN_486
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define FCOS  4
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* Used only by fptan, fsin, fcos, and fsincos. */
29*4882a593Smuzhiyun /* This routine produces very accurate results, similar to
30*4882a593Smuzhiyun    using a value of pi with more than 128 bits precision. */
31*4882a593Smuzhiyun /* Limited measurements show no results worse than 64 bit precision
32*4882a593Smuzhiyun    except for the results for arguments close to 2^63, where the
33*4882a593Smuzhiyun    precision of the result sometimes degrades to about 63.9 bits */
trig_arg(FPU_REG * st0_ptr,int even)34*4882a593Smuzhiyun static int trig_arg(FPU_REG *st0_ptr, int even)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	FPU_REG tmp;
37*4882a593Smuzhiyun 	u_char tmptag;
38*4882a593Smuzhiyun 	unsigned long long q;
39*4882a593Smuzhiyun 	int old_cw = control_word, saved_status = partial_status;
40*4882a593Smuzhiyun 	int tag, st0_tag = TAG_Valid;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	if (exponent(st0_ptr) >= 63) {
43*4882a593Smuzhiyun 		partial_status |= SW_C2;	/* Reduction incomplete. */
44*4882a593Smuzhiyun 		return -1;
45*4882a593Smuzhiyun 	}
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	control_word &= ~CW_RC;
48*4882a593Smuzhiyun 	control_word |= RC_CHOP;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	setpositive(st0_ptr);
51*4882a593Smuzhiyun 	tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
52*4882a593Smuzhiyun 			SIGN_POS);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	FPU_round_to_int(&tmp, tag);	/* Fortunately, this can't overflow
55*4882a593Smuzhiyun 					   to 2^64 */
56*4882a593Smuzhiyun 	q = significand(&tmp);
57*4882a593Smuzhiyun 	if (q) {
58*4882a593Smuzhiyun 		rem_kernel(significand(st0_ptr),
59*4882a593Smuzhiyun 			   &significand(&tmp),
60*4882a593Smuzhiyun 			   significand(&CONST_PI2),
61*4882a593Smuzhiyun 			   q, exponent(st0_ptr) - exponent(&CONST_PI2));
62*4882a593Smuzhiyun 		setexponent16(&tmp, exponent(&CONST_PI2));
63*4882a593Smuzhiyun 		st0_tag = FPU_normalize(&tmp);
64*4882a593Smuzhiyun 		FPU_copy_to_reg0(&tmp, st0_tag);
65*4882a593Smuzhiyun 	}
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	if ((even && !(q & 1)) || (!even && (q & 1))) {
68*4882a593Smuzhiyun 		st0_tag =
69*4882a593Smuzhiyun 		    FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
70*4882a593Smuzhiyun 			    FULL_PRECISION);
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #ifdef BETTER_THAN_486
73*4882a593Smuzhiyun 		/* So far, the results are exact but based upon a 64 bit
74*4882a593Smuzhiyun 		   precision approximation to pi/2. The technique used
75*4882a593Smuzhiyun 		   now is equivalent to using an approximation to pi/2 which
76*4882a593Smuzhiyun 		   is accurate to about 128 bits. */
77*4882a593Smuzhiyun 		if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)
78*4882a593Smuzhiyun 		    || (q > 1)) {
79*4882a593Smuzhiyun 			/* This code gives the effect of having pi/2 to better than
80*4882a593Smuzhiyun 			   128 bits precision. */
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 			significand(&tmp) = q + 1;
83*4882a593Smuzhiyun 			setexponent16(&tmp, 63);
84*4882a593Smuzhiyun 			FPU_normalize(&tmp);
85*4882a593Smuzhiyun 			tmptag =
86*4882a593Smuzhiyun 			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
87*4882a593Smuzhiyun 				      FULL_PRECISION, SIGN_POS,
88*4882a593Smuzhiyun 				      exponent(&CONST_PI2extra) +
89*4882a593Smuzhiyun 				      exponent(&tmp));
90*4882a593Smuzhiyun 			setsign(&tmp, getsign(&CONST_PI2extra));
91*4882a593Smuzhiyun 			st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
92*4882a593Smuzhiyun 			if (signnegative(st0_ptr)) {
93*4882a593Smuzhiyun 				/* CONST_PI2extra is negative, so the result of the addition
94*4882a593Smuzhiyun 				   can be negative. This means that the argument is actually
95*4882a593Smuzhiyun 				   in a different quadrant. The correction is always < pi/2,
96*4882a593Smuzhiyun 				   so it can't overflow into yet another quadrant. */
97*4882a593Smuzhiyun 				setpositive(st0_ptr);
98*4882a593Smuzhiyun 				q++;
99*4882a593Smuzhiyun 			}
100*4882a593Smuzhiyun 		}
101*4882a593Smuzhiyun #endif /* BETTER_THAN_486 */
102*4882a593Smuzhiyun 	}
103*4882a593Smuzhiyun #ifdef BETTER_THAN_486
104*4882a593Smuzhiyun 	else {
105*4882a593Smuzhiyun 		/* So far, the results are exact but based upon a 64 bit
106*4882a593Smuzhiyun 		   precision approximation to pi/2. The technique used
107*4882a593Smuzhiyun 		   now is equivalent to using an approximation to pi/2 which
108*4882a593Smuzhiyun 		   is accurate to about 128 bits. */
109*4882a593Smuzhiyun 		if (((q > 0)
110*4882a593Smuzhiyun 		     && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
111*4882a593Smuzhiyun 		    || (q > 1)) {
112*4882a593Smuzhiyun 			/* This code gives the effect of having p/2 to better than
113*4882a593Smuzhiyun 			   128 bits precision. */
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 			significand(&tmp) = q;
116*4882a593Smuzhiyun 			setexponent16(&tmp, 63);
117*4882a593Smuzhiyun 			FPU_normalize(&tmp);	/* This must return TAG_Valid */
118*4882a593Smuzhiyun 			tmptag =
119*4882a593Smuzhiyun 			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
120*4882a593Smuzhiyun 				      FULL_PRECISION, SIGN_POS,
121*4882a593Smuzhiyun 				      exponent(&CONST_PI2extra) +
122*4882a593Smuzhiyun 				      exponent(&tmp));
123*4882a593Smuzhiyun 			setsign(&tmp, getsign(&CONST_PI2extra));
124*4882a593Smuzhiyun 			st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp,
125*4882a593Smuzhiyun 					  FULL_PRECISION);
126*4882a593Smuzhiyun 			if ((exponent(st0_ptr) == exponent(&CONST_PI2)) &&
127*4882a593Smuzhiyun 			    ((st0_ptr->sigh > CONST_PI2.sigh)
128*4882a593Smuzhiyun 			     || ((st0_ptr->sigh == CONST_PI2.sigh)
129*4882a593Smuzhiyun 				 && (st0_ptr->sigl > CONST_PI2.sigl)))) {
130*4882a593Smuzhiyun 				/* CONST_PI2extra is negative, so the result of the
131*4882a593Smuzhiyun 				   subtraction can be larger than pi/2. This means
132*4882a593Smuzhiyun 				   that the argument is actually in a different quadrant.
133*4882a593Smuzhiyun 				   The correction is always < pi/2, so it can't overflow
134*4882a593Smuzhiyun 				   into yet another quadrant. */
135*4882a593Smuzhiyun 				st0_tag =
136*4882a593Smuzhiyun 				    FPU_sub(REV | LOADED | TAG_Valid,
137*4882a593Smuzhiyun 					    (int)&CONST_PI2, FULL_PRECISION);
138*4882a593Smuzhiyun 				q++;
139*4882a593Smuzhiyun 			}
140*4882a593Smuzhiyun 		}
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun #endif /* BETTER_THAN_486 */
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	FPU_settag0(st0_tag);
145*4882a593Smuzhiyun 	control_word = old_cw;
146*4882a593Smuzhiyun 	partial_status = saved_status & ~SW_C2;	/* Reduction complete. */
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return (q & 3) | even;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun /* Convert a long to register */
convert_l2reg(long const * arg,int deststnr)152*4882a593Smuzhiyun static void convert_l2reg(long const *arg, int deststnr)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	int tag;
155*4882a593Smuzhiyun 	long num = *arg;
156*4882a593Smuzhiyun 	u_char sign;
157*4882a593Smuzhiyun 	FPU_REG *dest = &st(deststnr);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	if (num == 0) {
160*4882a593Smuzhiyun 		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
161*4882a593Smuzhiyun 		return;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (num > 0) {
165*4882a593Smuzhiyun 		sign = SIGN_POS;
166*4882a593Smuzhiyun 	} else {
167*4882a593Smuzhiyun 		num = -num;
168*4882a593Smuzhiyun 		sign = SIGN_NEG;
169*4882a593Smuzhiyun 	}
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	dest->sigh = num;
172*4882a593Smuzhiyun 	dest->sigl = 0;
173*4882a593Smuzhiyun 	setexponent16(dest, 31);
174*4882a593Smuzhiyun 	tag = FPU_normalize(dest);
175*4882a593Smuzhiyun 	FPU_settagi(deststnr, tag);
176*4882a593Smuzhiyun 	setsign(dest, sign);
177*4882a593Smuzhiyun 	return;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
single_arg_error(FPU_REG * st0_ptr,u_char st0_tag)180*4882a593Smuzhiyun static void single_arg_error(FPU_REG *st0_ptr, u_char st0_tag)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	if (st0_tag == TAG_Empty)
183*4882a593Smuzhiyun 		FPU_stack_underflow();	/* Puts a QNaN in st(0) */
184*4882a593Smuzhiyun 	else if (st0_tag == TW_NaN)
185*4882a593Smuzhiyun 		real_1op_NaN(st0_ptr);	/* return with a NaN in st(0) */
186*4882a593Smuzhiyun #ifdef PARANOID
187*4882a593Smuzhiyun 	else
188*4882a593Smuzhiyun 		EXCEPTION(EX_INTERNAL | 0x0112);
189*4882a593Smuzhiyun #endif /* PARANOID */
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
single_arg_2_error(FPU_REG * st0_ptr,u_char st0_tag)192*4882a593Smuzhiyun static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	int isNaN;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	switch (st0_tag) {
197*4882a593Smuzhiyun 	case TW_NaN:
198*4882a593Smuzhiyun 		isNaN = (exponent(st0_ptr) == EXP_OVER)
199*4882a593Smuzhiyun 		    && (st0_ptr->sigh & 0x80000000);
200*4882a593Smuzhiyun 		if (isNaN && !(st0_ptr->sigh & 0x40000000)) {	/* Signaling ? */
201*4882a593Smuzhiyun 			EXCEPTION(EX_Invalid);
202*4882a593Smuzhiyun 			if (control_word & CW_Invalid) {
203*4882a593Smuzhiyun 				/* The masked response */
204*4882a593Smuzhiyun 				/* Convert to a QNaN */
205*4882a593Smuzhiyun 				st0_ptr->sigh |= 0x40000000;
206*4882a593Smuzhiyun 				push();
207*4882a593Smuzhiyun 				FPU_copy_to_reg0(st0_ptr, TAG_Special);
208*4882a593Smuzhiyun 			}
209*4882a593Smuzhiyun 		} else if (isNaN) {
210*4882a593Smuzhiyun 			/* A QNaN */
211*4882a593Smuzhiyun 			push();
212*4882a593Smuzhiyun 			FPU_copy_to_reg0(st0_ptr, TAG_Special);
213*4882a593Smuzhiyun 		} else {
214*4882a593Smuzhiyun 			/* pseudoNaN or other unsupported */
215*4882a593Smuzhiyun 			EXCEPTION(EX_Invalid);
216*4882a593Smuzhiyun 			if (control_word & CW_Invalid) {
217*4882a593Smuzhiyun 				/* The masked response */
218*4882a593Smuzhiyun 				FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
219*4882a593Smuzhiyun 				push();
220*4882a593Smuzhiyun 				FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
221*4882a593Smuzhiyun 			}
222*4882a593Smuzhiyun 		}
223*4882a593Smuzhiyun 		break;		/* return with a NaN in st(0) */
224*4882a593Smuzhiyun #ifdef PARANOID
225*4882a593Smuzhiyun 	default:
226*4882a593Smuzhiyun 		EXCEPTION(EX_INTERNAL | 0x0112);
227*4882a593Smuzhiyun #endif /* PARANOID */
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun /*---------------------------------------------------------------------------*/
232*4882a593Smuzhiyun 
f2xm1(FPU_REG * st0_ptr,u_char tag)233*4882a593Smuzhiyun static void f2xm1(FPU_REG *st0_ptr, u_char tag)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	FPU_REG a;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	clear_C1();
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	if (tag == TAG_Valid) {
240*4882a593Smuzhiyun 		/* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */
241*4882a593Smuzhiyun 		if (exponent(st0_ptr) < 0) {
242*4882a593Smuzhiyun 		      denormal_arg:
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 			FPU_to_exp16(st0_ptr, &a);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 			/* poly_2xm1(x) requires 0 < st(0) < 1. */
247*4882a593Smuzhiyun 			poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
248*4882a593Smuzhiyun 		}
249*4882a593Smuzhiyun 		set_precision_flag_up();	/* 80486 appears to always do this */
250*4882a593Smuzhiyun 		return;
251*4882a593Smuzhiyun 	}
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	if (tag == TAG_Zero)
254*4882a593Smuzhiyun 		return;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	if (tag == TAG_Special)
257*4882a593Smuzhiyun 		tag = FPU_Special(st0_ptr);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	switch (tag) {
260*4882a593Smuzhiyun 	case TW_Denormal:
261*4882a593Smuzhiyun 		if (denormal_operand() < 0)
262*4882a593Smuzhiyun 			return;
263*4882a593Smuzhiyun 		goto denormal_arg;
264*4882a593Smuzhiyun 	case TW_Infinity:
265*4882a593Smuzhiyun 		if (signnegative(st0_ptr)) {
266*4882a593Smuzhiyun 			/* -infinity gives -1 (p16-10) */
267*4882a593Smuzhiyun 			FPU_copy_to_reg0(&CONST_1, TAG_Valid);
268*4882a593Smuzhiyun 			setnegative(st0_ptr);
269*4882a593Smuzhiyun 		}
270*4882a593Smuzhiyun 		return;
271*4882a593Smuzhiyun 	default:
272*4882a593Smuzhiyun 		single_arg_error(st0_ptr, tag);
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun 
fptan(FPU_REG * st0_ptr,u_char st0_tag)276*4882a593Smuzhiyun static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	FPU_REG *st_new_ptr;
279*4882a593Smuzhiyun 	int q;
280*4882a593Smuzhiyun 	u_char arg_sign = getsign(st0_ptr);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	/* Stack underflow has higher priority */
283*4882a593Smuzhiyun 	if (st0_tag == TAG_Empty) {
284*4882a593Smuzhiyun 		FPU_stack_underflow();	/* Puts a QNaN in st(0) */
285*4882a593Smuzhiyun 		if (control_word & CW_Invalid) {
286*4882a593Smuzhiyun 			st_new_ptr = &st(-1);
287*4882a593Smuzhiyun 			push();
288*4882a593Smuzhiyun 			FPU_stack_underflow();	/* Puts a QNaN in the new st(0) */
289*4882a593Smuzhiyun 		}
290*4882a593Smuzhiyun 		return;
291*4882a593Smuzhiyun 	}
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	if (STACK_OVERFLOW) {
294*4882a593Smuzhiyun 		FPU_stack_overflow();
295*4882a593Smuzhiyun 		return;
296*4882a593Smuzhiyun 	}
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	if (st0_tag == TAG_Valid) {
299*4882a593Smuzhiyun 		if (exponent(st0_ptr) > -40) {
300*4882a593Smuzhiyun 			if ((q = trig_arg(st0_ptr, 0)) == -1) {
301*4882a593Smuzhiyun 				/* Operand is out of range */
302*4882a593Smuzhiyun 				return;
303*4882a593Smuzhiyun 			}
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 			poly_tan(st0_ptr);
306*4882a593Smuzhiyun 			setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
307*4882a593Smuzhiyun 			set_precision_flag_up();	/* We do not really know if up or down */
308*4882a593Smuzhiyun 		} else {
309*4882a593Smuzhiyun 			/* For a small arg, the result == the argument */
310*4882a593Smuzhiyun 			/* Underflow may happen */
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 		      denormal_arg:
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 			FPU_to_exp16(st0_ptr, st0_ptr);
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 			st0_tag =
317*4882a593Smuzhiyun 			    FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
318*4882a593Smuzhiyun 			FPU_settag0(st0_tag);
319*4882a593Smuzhiyun 		}
320*4882a593Smuzhiyun 		push();
321*4882a593Smuzhiyun 		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
322*4882a593Smuzhiyun 		return;
323*4882a593Smuzhiyun 	}
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	if (st0_tag == TAG_Zero) {
326*4882a593Smuzhiyun 		push();
327*4882a593Smuzhiyun 		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
328*4882a593Smuzhiyun 		setcc(0);
329*4882a593Smuzhiyun 		return;
330*4882a593Smuzhiyun 	}
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	if (st0_tag == TAG_Special)
333*4882a593Smuzhiyun 		st0_tag = FPU_Special(st0_ptr);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (st0_tag == TW_Denormal) {
336*4882a593Smuzhiyun 		if (denormal_operand() < 0)
337*4882a593Smuzhiyun 			return;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 		goto denormal_arg;
340*4882a593Smuzhiyun 	}
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	if (st0_tag == TW_Infinity) {
343*4882a593Smuzhiyun 		/* The 80486 treats infinity as an invalid operand */
344*4882a593Smuzhiyun 		if (arith_invalid(0) >= 0) {
345*4882a593Smuzhiyun 			st_new_ptr = &st(-1);
346*4882a593Smuzhiyun 			push();
347*4882a593Smuzhiyun 			arith_invalid(0);
348*4882a593Smuzhiyun 		}
349*4882a593Smuzhiyun 		return;
350*4882a593Smuzhiyun 	}
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	single_arg_2_error(st0_ptr, st0_tag);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun 
fxtract(FPU_REG * st0_ptr,u_char st0_tag)355*4882a593Smuzhiyun static void fxtract(FPU_REG *st0_ptr, u_char st0_tag)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	FPU_REG *st_new_ptr;
358*4882a593Smuzhiyun 	u_char sign;
359*4882a593Smuzhiyun 	register FPU_REG *st1_ptr = st0_ptr;	/* anticipate */
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	if (STACK_OVERFLOW) {
362*4882a593Smuzhiyun 		FPU_stack_overflow();
363*4882a593Smuzhiyun 		return;
364*4882a593Smuzhiyun 	}
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	clear_C1();
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	if (st0_tag == TAG_Valid) {
369*4882a593Smuzhiyun 		long e;
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 		push();
372*4882a593Smuzhiyun 		sign = getsign(st1_ptr);
373*4882a593Smuzhiyun 		reg_copy(st1_ptr, st_new_ptr);
374*4882a593Smuzhiyun 		setexponent16(st_new_ptr, exponent(st_new_ptr));
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	      denormal_arg:
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 		e = exponent16(st_new_ptr);
379*4882a593Smuzhiyun 		convert_l2reg(&e, 1);
380*4882a593Smuzhiyun 		setexponentpos(st_new_ptr, 0);
381*4882a593Smuzhiyun 		setsign(st_new_ptr, sign);
382*4882a593Smuzhiyun 		FPU_settag0(TAG_Valid);	/* Needed if arg was a denormal */
383*4882a593Smuzhiyun 		return;
384*4882a593Smuzhiyun 	} else if (st0_tag == TAG_Zero) {
385*4882a593Smuzhiyun 		sign = getsign(st0_ptr);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 		if (FPU_divide_by_zero(0, SIGN_NEG) < 0)
388*4882a593Smuzhiyun 			return;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 		push();
391*4882a593Smuzhiyun 		FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
392*4882a593Smuzhiyun 		setsign(st_new_ptr, sign);
393*4882a593Smuzhiyun 		return;
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	if (st0_tag == TAG_Special)
397*4882a593Smuzhiyun 		st0_tag = FPU_Special(st0_ptr);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	if (st0_tag == TW_Denormal) {
400*4882a593Smuzhiyun 		if (denormal_operand() < 0)
401*4882a593Smuzhiyun 			return;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 		push();
404*4882a593Smuzhiyun 		sign = getsign(st1_ptr);
405*4882a593Smuzhiyun 		FPU_to_exp16(st1_ptr, st_new_ptr);
406*4882a593Smuzhiyun 		goto denormal_arg;
407*4882a593Smuzhiyun 	} else if (st0_tag == TW_Infinity) {
408*4882a593Smuzhiyun 		sign = getsign(st0_ptr);
409*4882a593Smuzhiyun 		setpositive(st0_ptr);
410*4882a593Smuzhiyun 		push();
411*4882a593Smuzhiyun 		FPU_copy_to_reg0(&CONST_INF, TAG_Special);
412*4882a593Smuzhiyun 		setsign(st_new_ptr, sign);
413*4882a593Smuzhiyun 		return;
414*4882a593Smuzhiyun 	} else if (st0_tag == TW_NaN) {
415*4882a593Smuzhiyun 		if (real_1op_NaN(st0_ptr) < 0)
416*4882a593Smuzhiyun 			return;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 		push();
419*4882a593Smuzhiyun 		FPU_copy_to_reg0(st0_ptr, TAG_Special);
420*4882a593Smuzhiyun 		return;
421*4882a593Smuzhiyun 	} else if (st0_tag == TAG_Empty) {
422*4882a593Smuzhiyun 		/* Is this the correct behaviour? */
423*4882a593Smuzhiyun 		if (control_word & EX_Invalid) {
424*4882a593Smuzhiyun 			FPU_stack_underflow();
425*4882a593Smuzhiyun 			push();
426*4882a593Smuzhiyun 			FPU_stack_underflow();
427*4882a593Smuzhiyun 		} else
428*4882a593Smuzhiyun 			EXCEPTION(EX_StackUnder);
429*4882a593Smuzhiyun 	}
430*4882a593Smuzhiyun #ifdef PARANOID
431*4882a593Smuzhiyun 	else
432*4882a593Smuzhiyun 		EXCEPTION(EX_INTERNAL | 0x119);
433*4882a593Smuzhiyun #endif /* PARANOID */
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
fdecstp(void)436*4882a593Smuzhiyun static void fdecstp(void)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	clear_C1();
439*4882a593Smuzhiyun 	top--;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
fincstp(void)442*4882a593Smuzhiyun static void fincstp(void)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	clear_C1();
445*4882a593Smuzhiyun 	top++;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun 
fsqrt_(FPU_REG * st0_ptr,u_char st0_tag)448*4882a593Smuzhiyun static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	int expon;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	clear_C1();
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	if (st0_tag == TAG_Valid) {
455*4882a593Smuzhiyun 		u_char tag;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 		if (signnegative(st0_ptr)) {
458*4882a593Smuzhiyun 			arith_invalid(0);	/* sqrt(negative) is invalid */
459*4882a593Smuzhiyun 			return;
460*4882a593Smuzhiyun 		}
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 		/* make st(0) in  [1.0 .. 4.0) */
463*4882a593Smuzhiyun 		expon = exponent(st0_ptr);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	      denormal_arg:
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 		setexponent16(st0_ptr, (expon & 1));
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 		/* Do the computation, the sign of the result will be positive. */
470*4882a593Smuzhiyun 		tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
471*4882a593Smuzhiyun 		addexponent(st0_ptr, expon >> 1);
472*4882a593Smuzhiyun 		FPU_settag0(tag);
473*4882a593Smuzhiyun 		return;
474*4882a593Smuzhiyun 	}
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	if (st0_tag == TAG_Zero)
477*4882a593Smuzhiyun 		return;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	if (st0_tag == TAG_Special)
480*4882a593Smuzhiyun 		st0_tag = FPU_Special(st0_ptr);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	if (st0_tag == TW_Infinity) {
483*4882a593Smuzhiyun 		if (signnegative(st0_ptr))
484*4882a593Smuzhiyun 			arith_invalid(0);	/* sqrt(-Infinity) is invalid */
485*4882a593Smuzhiyun 		return;
486*4882a593Smuzhiyun 	} else if (st0_tag == TW_Denormal) {
487*4882a593Smuzhiyun 		if (signnegative(st0_ptr)) {
488*4882a593Smuzhiyun 			arith_invalid(0);	/* sqrt(negative) is invalid */
489*4882a593Smuzhiyun 			return;
490*4882a593Smuzhiyun 		}
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 		if (denormal_operand() < 0)
493*4882a593Smuzhiyun 			return;
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 		FPU_to_exp16(st0_ptr, st0_ptr);
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 		expon = exponent16(st0_ptr);
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 		goto denormal_arg;
500*4882a593Smuzhiyun 	}
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	single_arg_error(st0_ptr, st0_tag);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun 
frndint_(FPU_REG * st0_ptr,u_char st0_tag)506*4882a593Smuzhiyun static void frndint_(FPU_REG *st0_ptr, u_char st0_tag)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun 	int flags, tag;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	if (st0_tag == TAG_Valid) {
511*4882a593Smuzhiyun 		u_char sign;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	      denormal_arg:
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 		sign = getsign(st0_ptr);
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 		if (exponent(st0_ptr) > 63)
518*4882a593Smuzhiyun 			return;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 		if (st0_tag == TW_Denormal) {
521*4882a593Smuzhiyun 			if (denormal_operand() < 0)
522*4882a593Smuzhiyun 				return;
523*4882a593Smuzhiyun 		}
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 		/* Fortunately, this can't overflow to 2^64 */
526*4882a593Smuzhiyun 		if ((flags = FPU_round_to_int(st0_ptr, st0_tag)))
527*4882a593Smuzhiyun 			set_precision_flag(flags);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 		setexponent16(st0_ptr, 63);
530*4882a593Smuzhiyun 		tag = FPU_normalize(st0_ptr);
531*4882a593Smuzhiyun 		setsign(st0_ptr, sign);
532*4882a593Smuzhiyun 		FPU_settag0(tag);
533*4882a593Smuzhiyun 		return;
534*4882a593Smuzhiyun 	}
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	if (st0_tag == TAG_Zero)
537*4882a593Smuzhiyun 		return;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	if (st0_tag == TAG_Special)
540*4882a593Smuzhiyun 		st0_tag = FPU_Special(st0_ptr);
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	if (st0_tag == TW_Denormal)
543*4882a593Smuzhiyun 		goto denormal_arg;
544*4882a593Smuzhiyun 	else if (st0_tag == TW_Infinity)
545*4882a593Smuzhiyun 		return;
546*4882a593Smuzhiyun 	else
547*4882a593Smuzhiyun 		single_arg_error(st0_ptr, st0_tag);
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
fsin(FPU_REG * st0_ptr,u_char tag)550*4882a593Smuzhiyun static int fsin(FPU_REG *st0_ptr, u_char tag)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun 	u_char arg_sign = getsign(st0_ptr);
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	if (tag == TAG_Valid) {
555*4882a593Smuzhiyun 		int q;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 		if (exponent(st0_ptr) > -40) {
558*4882a593Smuzhiyun 			if ((q = trig_arg(st0_ptr, 0)) == -1) {
559*4882a593Smuzhiyun 				/* Operand is out of range */
560*4882a593Smuzhiyun 				return 1;
561*4882a593Smuzhiyun 			}
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 			poly_sine(st0_ptr);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 			if (q & 2)
566*4882a593Smuzhiyun 				changesign(st0_ptr);
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 			setsign(st0_ptr, getsign(st0_ptr) ^ arg_sign);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 			/* We do not really know if up or down */
571*4882a593Smuzhiyun 			set_precision_flag_up();
572*4882a593Smuzhiyun 			return 0;
573*4882a593Smuzhiyun 		} else {
574*4882a593Smuzhiyun 			/* For a small arg, the result == the argument */
575*4882a593Smuzhiyun 			set_precision_flag_up();	/* Must be up. */
576*4882a593Smuzhiyun 			return 0;
577*4882a593Smuzhiyun 		}
578*4882a593Smuzhiyun 	}
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	if (tag == TAG_Zero) {
581*4882a593Smuzhiyun 		setcc(0);
582*4882a593Smuzhiyun 		return 0;
583*4882a593Smuzhiyun 	}
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	if (tag == TAG_Special)
586*4882a593Smuzhiyun 		tag = FPU_Special(st0_ptr);
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	if (tag == TW_Denormal) {
589*4882a593Smuzhiyun 		if (denormal_operand() < 0)
590*4882a593Smuzhiyun 			return 1;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 		/* For a small arg, the result == the argument */
593*4882a593Smuzhiyun 		/* Underflow may happen */
594*4882a593Smuzhiyun 		FPU_to_exp16(st0_ptr, st0_ptr);
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 		tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 		FPU_settag0(tag);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 		return 0;
601*4882a593Smuzhiyun 	} else if (tag == TW_Infinity) {
602*4882a593Smuzhiyun 		/* The 80486 treats infinity as an invalid operand */
603*4882a593Smuzhiyun 		arith_invalid(0);
604*4882a593Smuzhiyun 		return 1;
605*4882a593Smuzhiyun 	} else {
606*4882a593Smuzhiyun 		single_arg_error(st0_ptr, tag);
607*4882a593Smuzhiyun 		return 1;
608*4882a593Smuzhiyun 	}
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun 
f_cos(FPU_REG * st0_ptr,u_char tag)611*4882a593Smuzhiyun static int f_cos(FPU_REG *st0_ptr, u_char tag)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun 	u_char st0_sign;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	st0_sign = getsign(st0_ptr);
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	if (tag == TAG_Valid) {
618*4882a593Smuzhiyun 		int q;
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 		if (exponent(st0_ptr) > -40) {
621*4882a593Smuzhiyun 			if ((exponent(st0_ptr) < 0)
622*4882a593Smuzhiyun 			    || ((exponent(st0_ptr) == 0)
623*4882a593Smuzhiyun 				&& (significand(st0_ptr) <=
624*4882a593Smuzhiyun 				    0xc90fdaa22168c234LL))) {
625*4882a593Smuzhiyun 				poly_cos(st0_ptr);
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 				/* We do not really know if up or down */
628*4882a593Smuzhiyun 				set_precision_flag_down();
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 				return 0;
631*4882a593Smuzhiyun 			} else if ((q = trig_arg(st0_ptr, FCOS)) != -1) {
632*4882a593Smuzhiyun 				poly_sine(st0_ptr);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 				if ((q + 1) & 2)
635*4882a593Smuzhiyun 					changesign(st0_ptr);
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 				/* We do not really know if up or down */
638*4882a593Smuzhiyun 				set_precision_flag_down();
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 				return 0;
641*4882a593Smuzhiyun 			} else {
642*4882a593Smuzhiyun 				/* Operand is out of range */
643*4882a593Smuzhiyun 				return 1;
644*4882a593Smuzhiyun 			}
645*4882a593Smuzhiyun 		} else {
646*4882a593Smuzhiyun 		      denormal_arg:
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 			setcc(0);
649*4882a593Smuzhiyun 			FPU_copy_to_reg0(&CONST_1, TAG_Valid);
650*4882a593Smuzhiyun #ifdef PECULIAR_486
651*4882a593Smuzhiyun 			set_precision_flag_down();	/* 80486 appears to do this. */
652*4882a593Smuzhiyun #else
653*4882a593Smuzhiyun 			set_precision_flag_up();	/* Must be up. */
654*4882a593Smuzhiyun #endif /* PECULIAR_486 */
655*4882a593Smuzhiyun 			return 0;
656*4882a593Smuzhiyun 		}
657*4882a593Smuzhiyun 	} else if (tag == TAG_Zero) {
658*4882a593Smuzhiyun 		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
659*4882a593Smuzhiyun 		setcc(0);
660*4882a593Smuzhiyun 		return 0;
661*4882a593Smuzhiyun 	}
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	if (tag == TAG_Special)
664*4882a593Smuzhiyun 		tag = FPU_Special(st0_ptr);
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	if (tag == TW_Denormal) {
667*4882a593Smuzhiyun 		if (denormal_operand() < 0)
668*4882a593Smuzhiyun 			return 1;
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 		goto denormal_arg;
671*4882a593Smuzhiyun 	} else if (tag == TW_Infinity) {
672*4882a593Smuzhiyun 		/* The 80486 treats infinity as an invalid operand */
673*4882a593Smuzhiyun 		arith_invalid(0);
674*4882a593Smuzhiyun 		return 1;
675*4882a593Smuzhiyun 	} else {
676*4882a593Smuzhiyun 		single_arg_error(st0_ptr, tag);	/* requires st0_ptr == &st(0) */
677*4882a593Smuzhiyun 		return 1;
678*4882a593Smuzhiyun 	}
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun 
fcos(FPU_REG * st0_ptr,u_char st0_tag)681*4882a593Smuzhiyun static void fcos(FPU_REG *st0_ptr, u_char st0_tag)
682*4882a593Smuzhiyun {
683*4882a593Smuzhiyun 	f_cos(st0_ptr, st0_tag);
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun 
fsincos(FPU_REG * st0_ptr,u_char st0_tag)686*4882a593Smuzhiyun static void fsincos(FPU_REG *st0_ptr, u_char st0_tag)
687*4882a593Smuzhiyun {
688*4882a593Smuzhiyun 	FPU_REG *st_new_ptr;
689*4882a593Smuzhiyun 	FPU_REG arg;
690*4882a593Smuzhiyun 	u_char tag;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	/* Stack underflow has higher priority */
693*4882a593Smuzhiyun 	if (st0_tag == TAG_Empty) {
694*4882a593Smuzhiyun 		FPU_stack_underflow();	/* Puts a QNaN in st(0) */
695*4882a593Smuzhiyun 		if (control_word & CW_Invalid) {
696*4882a593Smuzhiyun 			st_new_ptr = &st(-1);
697*4882a593Smuzhiyun 			push();
698*4882a593Smuzhiyun 			FPU_stack_underflow();	/* Puts a QNaN in the new st(0) */
699*4882a593Smuzhiyun 		}
700*4882a593Smuzhiyun 		return;
701*4882a593Smuzhiyun 	}
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	if (STACK_OVERFLOW) {
704*4882a593Smuzhiyun 		FPU_stack_overflow();
705*4882a593Smuzhiyun 		return;
706*4882a593Smuzhiyun 	}
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	if (st0_tag == TAG_Special)
709*4882a593Smuzhiyun 		tag = FPU_Special(st0_ptr);
710*4882a593Smuzhiyun 	else
711*4882a593Smuzhiyun 		tag = st0_tag;
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	if (tag == TW_NaN) {
714*4882a593Smuzhiyun 		single_arg_2_error(st0_ptr, TW_NaN);
715*4882a593Smuzhiyun 		return;
716*4882a593Smuzhiyun 	} else if (tag == TW_Infinity) {
717*4882a593Smuzhiyun 		/* The 80486 treats infinity as an invalid operand */
718*4882a593Smuzhiyun 		if (arith_invalid(0) >= 0) {
719*4882a593Smuzhiyun 			/* Masked response */
720*4882a593Smuzhiyun 			push();
721*4882a593Smuzhiyun 			arith_invalid(0);
722*4882a593Smuzhiyun 		}
723*4882a593Smuzhiyun 		return;
724*4882a593Smuzhiyun 	}
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	reg_copy(st0_ptr, &arg);
727*4882a593Smuzhiyun 	if (!fsin(st0_ptr, st0_tag)) {
728*4882a593Smuzhiyun 		push();
729*4882a593Smuzhiyun 		FPU_copy_to_reg0(&arg, st0_tag);
730*4882a593Smuzhiyun 		f_cos(&st(0), st0_tag);
731*4882a593Smuzhiyun 	} else {
732*4882a593Smuzhiyun 		/* An error, so restore st(0) */
733*4882a593Smuzhiyun 		FPU_copy_to_reg0(&arg, st0_tag);
734*4882a593Smuzhiyun 	}
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun /*---------------------------------------------------------------------------*/
738*4882a593Smuzhiyun /* The following all require two arguments: st(0) and st(1) */
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun /* A lean, mean kernel for the fprem instructions. This relies upon
741*4882a593Smuzhiyun    the division and rounding to an integer in do_fprem giving an
742*4882a593Smuzhiyun    exact result. Because of this, rem_kernel() needs to deal only with
743*4882a593Smuzhiyun    the least significant 64 bits, the more significant bits of the
744*4882a593Smuzhiyun    result must be zero.
745*4882a593Smuzhiyun  */
rem_kernel(unsigned long long st0,unsigned long long * y,unsigned long long st1,unsigned long long q,int n)746*4882a593Smuzhiyun static void rem_kernel(unsigned long long st0, unsigned long long *y,
747*4882a593Smuzhiyun 		       unsigned long long st1, unsigned long long q, int n)
748*4882a593Smuzhiyun {
749*4882a593Smuzhiyun 	int dummy;
750*4882a593Smuzhiyun 	unsigned long long x;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	x = st0 << n;
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	/* Do the required multiplication and subtraction in the one operation */
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	/* lsw x -= lsw st1 * lsw q */
757*4882a593Smuzhiyun 	asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1":"=m"
758*4882a593Smuzhiyun 		      (((unsigned *)&x)[0]), "=m"(((unsigned *)&x)[1]),
759*4882a593Smuzhiyun 		      "=a"(dummy)
760*4882a593Smuzhiyun 		      :"2"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[0])
761*4882a593Smuzhiyun 		      :"%dx");
762*4882a593Smuzhiyun 	/* msw x -= msw st1 * lsw q */
763*4882a593Smuzhiyun 	asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
764*4882a593Smuzhiyun 		      "=a"(dummy)
765*4882a593Smuzhiyun 		      :"1"(((unsigned *)&st1)[1]), "m"(((unsigned *)&q)[0])
766*4882a593Smuzhiyun 		      :"%dx");
767*4882a593Smuzhiyun 	/* msw x -= lsw st1 * msw q */
768*4882a593Smuzhiyun 	asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
769*4882a593Smuzhiyun 		      "=a"(dummy)
770*4882a593Smuzhiyun 		      :"1"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[1])
771*4882a593Smuzhiyun 		      :"%dx");
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	*y = x;
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun /* Remainder of st(0) / st(1) */
777*4882a593Smuzhiyun /* This routine produces exact results, i.e. there is never any
778*4882a593Smuzhiyun    rounding or truncation, etc of the result. */
do_fprem(FPU_REG * st0_ptr,u_char st0_tag,int round)779*4882a593Smuzhiyun static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round)
780*4882a593Smuzhiyun {
781*4882a593Smuzhiyun 	FPU_REG *st1_ptr = &st(1);
782*4882a593Smuzhiyun 	u_char st1_tag = FPU_gettagi(1);
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
785*4882a593Smuzhiyun 		FPU_REG tmp, st0, st1;
786*4882a593Smuzhiyun 		u_char st0_sign, st1_sign;
787*4882a593Smuzhiyun 		u_char tmptag;
788*4882a593Smuzhiyun 		int tag;
789*4882a593Smuzhiyun 		int old_cw;
790*4882a593Smuzhiyun 		int expdif;
791*4882a593Smuzhiyun 		long long q;
792*4882a593Smuzhiyun 		unsigned short saved_status;
793*4882a593Smuzhiyun 		int cc;
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	      fprem_valid:
796*4882a593Smuzhiyun 		/* Convert registers for internal use. */
797*4882a593Smuzhiyun 		st0_sign = FPU_to_exp16(st0_ptr, &st0);
798*4882a593Smuzhiyun 		st1_sign = FPU_to_exp16(st1_ptr, &st1);
799*4882a593Smuzhiyun 		expdif = exponent16(&st0) - exponent16(&st1);
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 		old_cw = control_word;
802*4882a593Smuzhiyun 		cc = 0;
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 		/* We want the status following the denorm tests, but don't want
805*4882a593Smuzhiyun 		   the status changed by the arithmetic operations. */
806*4882a593Smuzhiyun 		saved_status = partial_status;
807*4882a593Smuzhiyun 		control_word &= ~CW_RC;
808*4882a593Smuzhiyun 		control_word |= RC_CHOP;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 		if (expdif < 64) {
811*4882a593Smuzhiyun 			/* This should be the most common case */
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun 			if (expdif > -2) {
814*4882a593Smuzhiyun 				u_char sign = st0_sign ^ st1_sign;
815*4882a593Smuzhiyun 				tag = FPU_u_div(&st0, &st1, &tmp,
816*4882a593Smuzhiyun 						PR_64_BITS | RC_CHOP | 0x3f,
817*4882a593Smuzhiyun 						sign);
818*4882a593Smuzhiyun 				setsign(&tmp, sign);
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 				if (exponent(&tmp) >= 0) {
821*4882a593Smuzhiyun 					FPU_round_to_int(&tmp, tag);	/* Fortunately, this can't
822*4882a593Smuzhiyun 									   overflow to 2^64 */
823*4882a593Smuzhiyun 					q = significand(&tmp);
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 					rem_kernel(significand(&st0),
826*4882a593Smuzhiyun 						   &significand(&tmp),
827*4882a593Smuzhiyun 						   significand(&st1),
828*4882a593Smuzhiyun 						   q, expdif);
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 					setexponent16(&tmp, exponent16(&st1));
831*4882a593Smuzhiyun 				} else {
832*4882a593Smuzhiyun 					reg_copy(&st0, &tmp);
833*4882a593Smuzhiyun 					q = 0;
834*4882a593Smuzhiyun 				}
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 				if ((round == RC_RND)
837*4882a593Smuzhiyun 				    && (tmp.sigh & 0xc0000000)) {
838*4882a593Smuzhiyun 					/* We may need to subtract st(1) once more,
839*4882a593Smuzhiyun 					   to get a result <= 1/2 of st(1). */
840*4882a593Smuzhiyun 					unsigned long long x;
841*4882a593Smuzhiyun 					expdif =
842*4882a593Smuzhiyun 					    exponent16(&st1) - exponent16(&tmp);
843*4882a593Smuzhiyun 					if (expdif <= 1) {
844*4882a593Smuzhiyun 						if (expdif == 0)
845*4882a593Smuzhiyun 							x = significand(&st1) -
846*4882a593Smuzhiyun 							    significand(&tmp);
847*4882a593Smuzhiyun 						else	/* expdif is 1 */
848*4882a593Smuzhiyun 							x = (significand(&st1)
849*4882a593Smuzhiyun 							     << 1) -
850*4882a593Smuzhiyun 							    significand(&tmp);
851*4882a593Smuzhiyun 						if ((x < significand(&tmp)) ||
852*4882a593Smuzhiyun 						    /* or equi-distant (from 0 & st(1)) and q is odd */
853*4882a593Smuzhiyun 						    ((x == significand(&tmp))
854*4882a593Smuzhiyun 						     && (q & 1))) {
855*4882a593Smuzhiyun 							st0_sign = !st0_sign;
856*4882a593Smuzhiyun 							significand(&tmp) = x;
857*4882a593Smuzhiyun 							q++;
858*4882a593Smuzhiyun 						}
859*4882a593Smuzhiyun 					}
860*4882a593Smuzhiyun 				}
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun 				if (q & 4)
863*4882a593Smuzhiyun 					cc |= SW_C0;
864*4882a593Smuzhiyun 				if (q & 2)
865*4882a593Smuzhiyun 					cc |= SW_C3;
866*4882a593Smuzhiyun 				if (q & 1)
867*4882a593Smuzhiyun 					cc |= SW_C1;
868*4882a593Smuzhiyun 			} else {
869*4882a593Smuzhiyun 				control_word = old_cw;
870*4882a593Smuzhiyun 				setcc(0);
871*4882a593Smuzhiyun 				return;
872*4882a593Smuzhiyun 			}
873*4882a593Smuzhiyun 		} else {
874*4882a593Smuzhiyun 			/* There is a large exponent difference ( >= 64 ) */
875*4882a593Smuzhiyun 			/* To make much sense, the code in this section should
876*4882a593Smuzhiyun 			   be done at high precision. */
877*4882a593Smuzhiyun 			int exp_1, N;
878*4882a593Smuzhiyun 			u_char sign;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 			/* prevent overflow here */
881*4882a593Smuzhiyun 			/* N is 'a number between 32 and 63' (p26-113) */
882*4882a593Smuzhiyun 			reg_copy(&st0, &tmp);
883*4882a593Smuzhiyun 			tmptag = st0_tag;
884*4882a593Smuzhiyun 			N = (expdif & 0x0000001f) + 32;	/* This choice gives results
885*4882a593Smuzhiyun 							   identical to an AMD 486 */
886*4882a593Smuzhiyun 			setexponent16(&tmp, N);
887*4882a593Smuzhiyun 			exp_1 = exponent16(&st1);
888*4882a593Smuzhiyun 			setexponent16(&st1, 0);
889*4882a593Smuzhiyun 			expdif -= N;
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun 			sign = getsign(&tmp) ^ st1_sign;
892*4882a593Smuzhiyun 			tag =
893*4882a593Smuzhiyun 			    FPU_u_div(&tmp, &st1, &tmp,
894*4882a593Smuzhiyun 				      PR_64_BITS | RC_CHOP | 0x3f, sign);
895*4882a593Smuzhiyun 			setsign(&tmp, sign);
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 			FPU_round_to_int(&tmp, tag);	/* Fortunately, this can't
898*4882a593Smuzhiyun 							   overflow to 2^64 */
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 			rem_kernel(significand(&st0),
901*4882a593Smuzhiyun 				   &significand(&tmp),
902*4882a593Smuzhiyun 				   significand(&st1),
903*4882a593Smuzhiyun 				   significand(&tmp), exponent(&tmp)
904*4882a593Smuzhiyun 			    );
905*4882a593Smuzhiyun 			setexponent16(&tmp, exp_1 + expdif);
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 			/* It is possible for the operation to be complete here.
908*4882a593Smuzhiyun 			   What does the IEEE standard say? The Intel 80486 manual
909*4882a593Smuzhiyun 			   implies that the operation will never be completed at this
910*4882a593Smuzhiyun 			   point, and the behaviour of a real 80486 confirms this.
911*4882a593Smuzhiyun 			 */
912*4882a593Smuzhiyun 			if (!(tmp.sigh | tmp.sigl)) {
913*4882a593Smuzhiyun 				/* The result is zero */
914*4882a593Smuzhiyun 				control_word = old_cw;
915*4882a593Smuzhiyun 				partial_status = saved_status;
916*4882a593Smuzhiyun 				FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
917*4882a593Smuzhiyun 				setsign(&st0, st0_sign);
918*4882a593Smuzhiyun #ifdef PECULIAR_486
919*4882a593Smuzhiyun 				setcc(SW_C2);
920*4882a593Smuzhiyun #else
921*4882a593Smuzhiyun 				setcc(0);
922*4882a593Smuzhiyun #endif /* PECULIAR_486 */
923*4882a593Smuzhiyun 				return;
924*4882a593Smuzhiyun 			}
925*4882a593Smuzhiyun 			cc = SW_C2;
926*4882a593Smuzhiyun 		}
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 		control_word = old_cw;
929*4882a593Smuzhiyun 		partial_status = saved_status;
930*4882a593Smuzhiyun 		tag = FPU_normalize_nuo(&tmp);
931*4882a593Smuzhiyun 		reg_copy(&tmp, st0_ptr);
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 		/* The only condition to be looked for is underflow,
934*4882a593Smuzhiyun 		   and it can occur here only if underflow is unmasked. */
935*4882a593Smuzhiyun 		if ((exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero)
936*4882a593Smuzhiyun 		    && !(control_word & CW_Underflow)) {
937*4882a593Smuzhiyun 			setcc(cc);
938*4882a593Smuzhiyun 			tag = arith_underflow(st0_ptr);
939*4882a593Smuzhiyun 			setsign(st0_ptr, st0_sign);
940*4882a593Smuzhiyun 			FPU_settag0(tag);
941*4882a593Smuzhiyun 			return;
942*4882a593Smuzhiyun 		} else if ((exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero)) {
943*4882a593Smuzhiyun 			stdexp(st0_ptr);
944*4882a593Smuzhiyun 			setsign(st0_ptr, st0_sign);
945*4882a593Smuzhiyun 		} else {
946*4882a593Smuzhiyun 			tag =
947*4882a593Smuzhiyun 			    FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign);
948*4882a593Smuzhiyun 		}
949*4882a593Smuzhiyun 		FPU_settag0(tag);
950*4882a593Smuzhiyun 		setcc(cc);
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 		return;
953*4882a593Smuzhiyun 	}
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	if (st0_tag == TAG_Special)
956*4882a593Smuzhiyun 		st0_tag = FPU_Special(st0_ptr);
957*4882a593Smuzhiyun 	if (st1_tag == TAG_Special)
958*4882a593Smuzhiyun 		st1_tag = FPU_Special(st1_ptr);
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
961*4882a593Smuzhiyun 	    || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
962*4882a593Smuzhiyun 	    || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
963*4882a593Smuzhiyun 		if (denormal_operand() < 0)
964*4882a593Smuzhiyun 			return;
965*4882a593Smuzhiyun 		goto fprem_valid;
966*4882a593Smuzhiyun 	} else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
967*4882a593Smuzhiyun 		FPU_stack_underflow();
968*4882a593Smuzhiyun 		return;
969*4882a593Smuzhiyun 	} else if (st0_tag == TAG_Zero) {
970*4882a593Smuzhiyun 		if (st1_tag == TAG_Valid) {
971*4882a593Smuzhiyun 			setcc(0);
972*4882a593Smuzhiyun 			return;
973*4882a593Smuzhiyun 		} else if (st1_tag == TW_Denormal) {
974*4882a593Smuzhiyun 			if (denormal_operand() < 0)
975*4882a593Smuzhiyun 				return;
976*4882a593Smuzhiyun 			setcc(0);
977*4882a593Smuzhiyun 			return;
978*4882a593Smuzhiyun 		} else if (st1_tag == TAG_Zero) {
979*4882a593Smuzhiyun 			arith_invalid(0);
980*4882a593Smuzhiyun 			return;
981*4882a593Smuzhiyun 		} /* fprem(?,0) always invalid */
982*4882a593Smuzhiyun 		else if (st1_tag == TW_Infinity) {
983*4882a593Smuzhiyun 			setcc(0);
984*4882a593Smuzhiyun 			return;
985*4882a593Smuzhiyun 		}
986*4882a593Smuzhiyun 	} else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
987*4882a593Smuzhiyun 		if (st1_tag == TAG_Zero) {
988*4882a593Smuzhiyun 			arith_invalid(0);	/* fprem(Valid,Zero) is invalid */
989*4882a593Smuzhiyun 			return;
990*4882a593Smuzhiyun 		} else if (st1_tag != TW_NaN) {
991*4882a593Smuzhiyun 			if (((st0_tag == TW_Denormal)
992*4882a593Smuzhiyun 			     || (st1_tag == TW_Denormal))
993*4882a593Smuzhiyun 			    && (denormal_operand() < 0))
994*4882a593Smuzhiyun 				return;
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 			if (st1_tag == TW_Infinity) {
997*4882a593Smuzhiyun 				/* fprem(Valid,Infinity) is o.k. */
998*4882a593Smuzhiyun 				setcc(0);
999*4882a593Smuzhiyun 				return;
1000*4882a593Smuzhiyun 			}
1001*4882a593Smuzhiyun 		}
1002*4882a593Smuzhiyun 	} else if (st0_tag == TW_Infinity) {
1003*4882a593Smuzhiyun 		if (st1_tag != TW_NaN) {
1004*4882a593Smuzhiyun 			arith_invalid(0);	/* fprem(Infinity,?) is invalid */
1005*4882a593Smuzhiyun 			return;
1006*4882a593Smuzhiyun 		}
1007*4882a593Smuzhiyun 	}
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 	/* One of the registers must contain a NaN if we got here. */
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun #ifdef PARANOID
1012*4882a593Smuzhiyun 	if ((st0_tag != TW_NaN) && (st1_tag != TW_NaN))
1013*4882a593Smuzhiyun 		EXCEPTION(EX_INTERNAL | 0x118);
1014*4882a593Smuzhiyun #endif /* PARANOID */
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr);
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun /* ST(1) <- ST(1) * log ST;  pop ST */
fyl2x(FPU_REG * st0_ptr,u_char st0_tag)1021*4882a593Smuzhiyun static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag)
1022*4882a593Smuzhiyun {
1023*4882a593Smuzhiyun 	FPU_REG *st1_ptr = &st(1), exponent;
1024*4882a593Smuzhiyun 	u_char st1_tag = FPU_gettagi(1);
1025*4882a593Smuzhiyun 	u_char sign;
1026*4882a593Smuzhiyun 	int e, tag;
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	clear_C1();
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 	if ((st0_tag == TAG_Valid) && (st1_tag == TAG_Valid)) {
1031*4882a593Smuzhiyun 	      both_valid:
1032*4882a593Smuzhiyun 		/* Both regs are Valid or Denormal */
1033*4882a593Smuzhiyun 		if (signpositive(st0_ptr)) {
1034*4882a593Smuzhiyun 			if (st0_tag == TW_Denormal)
1035*4882a593Smuzhiyun 				FPU_to_exp16(st0_ptr, st0_ptr);
1036*4882a593Smuzhiyun 			else
1037*4882a593Smuzhiyun 				/* Convert st(0) for internal use. */
1038*4882a593Smuzhiyun 				setexponent16(st0_ptr, exponent(st0_ptr));
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun 			if ((st0_ptr->sigh == 0x80000000)
1041*4882a593Smuzhiyun 			    && (st0_ptr->sigl == 0)) {
1042*4882a593Smuzhiyun 				/* Special case. The result can be precise. */
1043*4882a593Smuzhiyun 				u_char esign;
1044*4882a593Smuzhiyun 				e = exponent16(st0_ptr);
1045*4882a593Smuzhiyun 				if (e >= 0) {
1046*4882a593Smuzhiyun 					exponent.sigh = e;
1047*4882a593Smuzhiyun 					esign = SIGN_POS;
1048*4882a593Smuzhiyun 				} else {
1049*4882a593Smuzhiyun 					exponent.sigh = -e;
1050*4882a593Smuzhiyun 					esign = SIGN_NEG;
1051*4882a593Smuzhiyun 				}
1052*4882a593Smuzhiyun 				exponent.sigl = 0;
1053*4882a593Smuzhiyun 				setexponent16(&exponent, 31);
1054*4882a593Smuzhiyun 				tag = FPU_normalize_nuo(&exponent);
1055*4882a593Smuzhiyun 				stdexp(&exponent);
1056*4882a593Smuzhiyun 				setsign(&exponent, esign);
1057*4882a593Smuzhiyun 				tag =
1058*4882a593Smuzhiyun 				    FPU_mul(&exponent, tag, 1, FULL_PRECISION);
1059*4882a593Smuzhiyun 				if (tag >= 0)
1060*4882a593Smuzhiyun 					FPU_settagi(1, tag);
1061*4882a593Smuzhiyun 			} else {
1062*4882a593Smuzhiyun 				/* The usual case */
1063*4882a593Smuzhiyun 				sign = getsign(st1_ptr);
1064*4882a593Smuzhiyun 				if (st1_tag == TW_Denormal)
1065*4882a593Smuzhiyun 					FPU_to_exp16(st1_ptr, st1_ptr);
1066*4882a593Smuzhiyun 				else
1067*4882a593Smuzhiyun 					/* Convert st(1) for internal use. */
1068*4882a593Smuzhiyun 					setexponent16(st1_ptr,
1069*4882a593Smuzhiyun 						      exponent(st1_ptr));
1070*4882a593Smuzhiyun 				poly_l2(st0_ptr, st1_ptr, sign);
1071*4882a593Smuzhiyun 			}
1072*4882a593Smuzhiyun 		} else {
1073*4882a593Smuzhiyun 			/* negative */
1074*4882a593Smuzhiyun 			if (arith_invalid(1) < 0)
1075*4882a593Smuzhiyun 				return;
1076*4882a593Smuzhiyun 		}
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 		FPU_pop();
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun 		return;
1081*4882a593Smuzhiyun 	}
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	if (st0_tag == TAG_Special)
1084*4882a593Smuzhiyun 		st0_tag = FPU_Special(st0_ptr);
1085*4882a593Smuzhiyun 	if (st1_tag == TAG_Special)
1086*4882a593Smuzhiyun 		st1_tag = FPU_Special(st1_ptr);
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun 	if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
1089*4882a593Smuzhiyun 		FPU_stack_underflow_pop(1);
1090*4882a593Smuzhiyun 		return;
1091*4882a593Smuzhiyun 	} else if ((st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal)) {
1092*4882a593Smuzhiyun 		if (st0_tag == TAG_Zero) {
1093*4882a593Smuzhiyun 			if (st1_tag == TAG_Zero) {
1094*4882a593Smuzhiyun 				/* Both args zero is invalid */
1095*4882a593Smuzhiyun 				if (arith_invalid(1) < 0)
1096*4882a593Smuzhiyun 					return;
1097*4882a593Smuzhiyun 			} else {
1098*4882a593Smuzhiyun 				u_char sign;
1099*4882a593Smuzhiyun 				sign = getsign(st1_ptr) ^ SIGN_NEG;
1100*4882a593Smuzhiyun 				if (FPU_divide_by_zero(1, sign) < 0)
1101*4882a593Smuzhiyun 					return;
1102*4882a593Smuzhiyun 
1103*4882a593Smuzhiyun 				setsign(st1_ptr, sign);
1104*4882a593Smuzhiyun 			}
1105*4882a593Smuzhiyun 		} else if (st1_tag == TAG_Zero) {
1106*4882a593Smuzhiyun 			/* st(1) contains zero, st(0) valid <> 0 */
1107*4882a593Smuzhiyun 			/* Zero is the valid answer */
1108*4882a593Smuzhiyun 			sign = getsign(st1_ptr);
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun 			if (signnegative(st0_ptr)) {
1111*4882a593Smuzhiyun 				/* log(negative) */
1112*4882a593Smuzhiyun 				if (arith_invalid(1) < 0)
1113*4882a593Smuzhiyun 					return;
1114*4882a593Smuzhiyun 			} else if ((st0_tag == TW_Denormal)
1115*4882a593Smuzhiyun 				   && (denormal_operand() < 0))
1116*4882a593Smuzhiyun 				return;
1117*4882a593Smuzhiyun 			else {
1118*4882a593Smuzhiyun 				if (exponent(st0_ptr) < 0)
1119*4882a593Smuzhiyun 					sign ^= SIGN_NEG;
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun 				FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1122*4882a593Smuzhiyun 				setsign(st1_ptr, sign);
1123*4882a593Smuzhiyun 			}
1124*4882a593Smuzhiyun 		} else {
1125*4882a593Smuzhiyun 			/* One or both operands are denormals. */
1126*4882a593Smuzhiyun 			if (denormal_operand() < 0)
1127*4882a593Smuzhiyun 				return;
1128*4882a593Smuzhiyun 			goto both_valid;
1129*4882a593Smuzhiyun 		}
1130*4882a593Smuzhiyun 	} else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
1131*4882a593Smuzhiyun 		if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1132*4882a593Smuzhiyun 			return;
1133*4882a593Smuzhiyun 	}
1134*4882a593Smuzhiyun 	/* One or both arg must be an infinity */
1135*4882a593Smuzhiyun 	else if (st0_tag == TW_Infinity) {
1136*4882a593Smuzhiyun 		if ((signnegative(st0_ptr)) || (st1_tag == TAG_Zero)) {
1137*4882a593Smuzhiyun 			/* log(-infinity) or 0*log(infinity) */
1138*4882a593Smuzhiyun 			if (arith_invalid(1) < 0)
1139*4882a593Smuzhiyun 				return;
1140*4882a593Smuzhiyun 		} else {
1141*4882a593Smuzhiyun 			u_char sign = getsign(st1_ptr);
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun 			if ((st1_tag == TW_Denormal)
1144*4882a593Smuzhiyun 			    && (denormal_operand() < 0))
1145*4882a593Smuzhiyun 				return;
1146*4882a593Smuzhiyun 
1147*4882a593Smuzhiyun 			FPU_copy_to_reg1(&CONST_INF, TAG_Special);
1148*4882a593Smuzhiyun 			setsign(st1_ptr, sign);
1149*4882a593Smuzhiyun 		}
1150*4882a593Smuzhiyun 	}
1151*4882a593Smuzhiyun 	/* st(1) must be infinity here */
1152*4882a593Smuzhiyun 	else if (((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal))
1153*4882a593Smuzhiyun 		 && (signpositive(st0_ptr))) {
1154*4882a593Smuzhiyun 		if (exponent(st0_ptr) >= 0) {
1155*4882a593Smuzhiyun 			if ((exponent(st0_ptr) == 0) &&
1156*4882a593Smuzhiyun 			    (st0_ptr->sigh == 0x80000000) &&
1157*4882a593Smuzhiyun 			    (st0_ptr->sigl == 0)) {
1158*4882a593Smuzhiyun 				/* st(0) holds 1.0 */
1159*4882a593Smuzhiyun 				/* infinity*log(1) */
1160*4882a593Smuzhiyun 				if (arith_invalid(1) < 0)
1161*4882a593Smuzhiyun 					return;
1162*4882a593Smuzhiyun 			}
1163*4882a593Smuzhiyun 			/* else st(0) is positive and > 1.0 */
1164*4882a593Smuzhiyun 		} else {
1165*4882a593Smuzhiyun 			/* st(0) is positive and < 1.0 */
1166*4882a593Smuzhiyun 
1167*4882a593Smuzhiyun 			if ((st0_tag == TW_Denormal)
1168*4882a593Smuzhiyun 			    && (denormal_operand() < 0))
1169*4882a593Smuzhiyun 				return;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 			changesign(st1_ptr);
1172*4882a593Smuzhiyun 		}
1173*4882a593Smuzhiyun 	} else {
1174*4882a593Smuzhiyun 		/* st(0) must be zero or negative */
1175*4882a593Smuzhiyun 		if (st0_tag == TAG_Zero) {
1176*4882a593Smuzhiyun 			/* This should be invalid, but a real 80486 is happy with it. */
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun #ifndef PECULIAR_486
1179*4882a593Smuzhiyun 			sign = getsign(st1_ptr);
1180*4882a593Smuzhiyun 			if (FPU_divide_by_zero(1, sign) < 0)
1181*4882a593Smuzhiyun 				return;
1182*4882a593Smuzhiyun #endif /* PECULIAR_486 */
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 			changesign(st1_ptr);
1185*4882a593Smuzhiyun 		} else if (arith_invalid(1) < 0)	/* log(negative) */
1186*4882a593Smuzhiyun 			return;
1187*4882a593Smuzhiyun 	}
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 	FPU_pop();
1190*4882a593Smuzhiyun }
1191*4882a593Smuzhiyun 
fpatan(FPU_REG * st0_ptr,u_char st0_tag)1192*4882a593Smuzhiyun static void fpatan(FPU_REG *st0_ptr, u_char st0_tag)
1193*4882a593Smuzhiyun {
1194*4882a593Smuzhiyun 	FPU_REG *st1_ptr = &st(1);
1195*4882a593Smuzhiyun 	u_char st1_tag = FPU_gettagi(1);
1196*4882a593Smuzhiyun 	int tag;
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	clear_C1();
1199*4882a593Smuzhiyun 	if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1200*4882a593Smuzhiyun 	      valid_atan:
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 		poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag);
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 		FPU_pop();
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 		return;
1207*4882a593Smuzhiyun 	}
1208*4882a593Smuzhiyun 
1209*4882a593Smuzhiyun 	if (st0_tag == TAG_Special)
1210*4882a593Smuzhiyun 		st0_tag = FPU_Special(st0_ptr);
1211*4882a593Smuzhiyun 	if (st1_tag == TAG_Special)
1212*4882a593Smuzhiyun 		st1_tag = FPU_Special(st1_ptr);
1213*4882a593Smuzhiyun 
1214*4882a593Smuzhiyun 	if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
1215*4882a593Smuzhiyun 	    || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
1216*4882a593Smuzhiyun 	    || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
1217*4882a593Smuzhiyun 		if (denormal_operand() < 0)
1218*4882a593Smuzhiyun 			return;
1219*4882a593Smuzhiyun 
1220*4882a593Smuzhiyun 		goto valid_atan;
1221*4882a593Smuzhiyun 	} else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
1222*4882a593Smuzhiyun 		FPU_stack_underflow_pop(1);
1223*4882a593Smuzhiyun 		return;
1224*4882a593Smuzhiyun 	} else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
1225*4882a593Smuzhiyun 		if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0)
1226*4882a593Smuzhiyun 			FPU_pop();
1227*4882a593Smuzhiyun 		return;
1228*4882a593Smuzhiyun 	} else if ((st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) {
1229*4882a593Smuzhiyun 		u_char sign = getsign(st1_ptr);
1230*4882a593Smuzhiyun 		if (st0_tag == TW_Infinity) {
1231*4882a593Smuzhiyun 			if (st1_tag == TW_Infinity) {
1232*4882a593Smuzhiyun 				if (signpositive(st0_ptr)) {
1233*4882a593Smuzhiyun 					FPU_copy_to_reg1(&CONST_PI4, TAG_Valid);
1234*4882a593Smuzhiyun 				} else {
1235*4882a593Smuzhiyun 					setpositive(st1_ptr);
1236*4882a593Smuzhiyun 					tag =
1237*4882a593Smuzhiyun 					    FPU_u_add(&CONST_PI4, &CONST_PI2,
1238*4882a593Smuzhiyun 						      st1_ptr, FULL_PRECISION,
1239*4882a593Smuzhiyun 						      SIGN_POS,
1240*4882a593Smuzhiyun 						      exponent(&CONST_PI4),
1241*4882a593Smuzhiyun 						      exponent(&CONST_PI2));
1242*4882a593Smuzhiyun 					if (tag >= 0)
1243*4882a593Smuzhiyun 						FPU_settagi(1, tag);
1244*4882a593Smuzhiyun 				}
1245*4882a593Smuzhiyun 			} else {
1246*4882a593Smuzhiyun 				if ((st1_tag == TW_Denormal)
1247*4882a593Smuzhiyun 				    && (denormal_operand() < 0))
1248*4882a593Smuzhiyun 					return;
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun 				if (signpositive(st0_ptr)) {
1251*4882a593Smuzhiyun 					FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1252*4882a593Smuzhiyun 					setsign(st1_ptr, sign);	/* An 80486 preserves the sign */
1253*4882a593Smuzhiyun 					FPU_pop();
1254*4882a593Smuzhiyun 					return;
1255*4882a593Smuzhiyun 				} else {
1256*4882a593Smuzhiyun 					FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
1257*4882a593Smuzhiyun 				}
1258*4882a593Smuzhiyun 			}
1259*4882a593Smuzhiyun 		} else {
1260*4882a593Smuzhiyun 			/* st(1) is infinity, st(0) not infinity */
1261*4882a593Smuzhiyun 			if ((st0_tag == TW_Denormal)
1262*4882a593Smuzhiyun 			    && (denormal_operand() < 0))
1263*4882a593Smuzhiyun 				return;
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun 			FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
1266*4882a593Smuzhiyun 		}
1267*4882a593Smuzhiyun 		setsign(st1_ptr, sign);
1268*4882a593Smuzhiyun 	} else if (st1_tag == TAG_Zero) {
1269*4882a593Smuzhiyun 		/* st(0) must be valid or zero */
1270*4882a593Smuzhiyun 		u_char sign = getsign(st1_ptr);
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun 		if ((st0_tag == TW_Denormal) && (denormal_operand() < 0))
1273*4882a593Smuzhiyun 			return;
1274*4882a593Smuzhiyun 
1275*4882a593Smuzhiyun 		if (signpositive(st0_ptr)) {
1276*4882a593Smuzhiyun 			/* An 80486 preserves the sign */
1277*4882a593Smuzhiyun 			FPU_pop();
1278*4882a593Smuzhiyun 			return;
1279*4882a593Smuzhiyun 		}
1280*4882a593Smuzhiyun 
1281*4882a593Smuzhiyun 		FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
1282*4882a593Smuzhiyun 		setsign(st1_ptr, sign);
1283*4882a593Smuzhiyun 	} else if (st0_tag == TAG_Zero) {
1284*4882a593Smuzhiyun 		/* st(1) must be TAG_Valid here */
1285*4882a593Smuzhiyun 		u_char sign = getsign(st1_ptr);
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 		if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
1288*4882a593Smuzhiyun 			return;
1289*4882a593Smuzhiyun 
1290*4882a593Smuzhiyun 		FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
1291*4882a593Smuzhiyun 		setsign(st1_ptr, sign);
1292*4882a593Smuzhiyun 	}
1293*4882a593Smuzhiyun #ifdef PARANOID
1294*4882a593Smuzhiyun 	else
1295*4882a593Smuzhiyun 		EXCEPTION(EX_INTERNAL | 0x125);
1296*4882a593Smuzhiyun #endif /* PARANOID */
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 	FPU_pop();
1299*4882a593Smuzhiyun 	set_precision_flag_up();	/* We do not really know if up or down */
1300*4882a593Smuzhiyun }
1301*4882a593Smuzhiyun 
fprem(FPU_REG * st0_ptr,u_char st0_tag)1302*4882a593Smuzhiyun static void fprem(FPU_REG *st0_ptr, u_char st0_tag)
1303*4882a593Smuzhiyun {
1304*4882a593Smuzhiyun 	do_fprem(st0_ptr, st0_tag, RC_CHOP);
1305*4882a593Smuzhiyun }
1306*4882a593Smuzhiyun 
fprem1(FPU_REG * st0_ptr,u_char st0_tag)1307*4882a593Smuzhiyun static void fprem1(FPU_REG *st0_ptr, u_char st0_tag)
1308*4882a593Smuzhiyun {
1309*4882a593Smuzhiyun 	do_fprem(st0_ptr, st0_tag, RC_RND);
1310*4882a593Smuzhiyun }
1311*4882a593Smuzhiyun 
fyl2xp1(FPU_REG * st0_ptr,u_char st0_tag)1312*4882a593Smuzhiyun static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag)
1313*4882a593Smuzhiyun {
1314*4882a593Smuzhiyun 	u_char sign, sign1;
1315*4882a593Smuzhiyun 	FPU_REG *st1_ptr = &st(1), a, b;
1316*4882a593Smuzhiyun 	u_char st1_tag = FPU_gettagi(1);
1317*4882a593Smuzhiyun 
1318*4882a593Smuzhiyun 	clear_C1();
1319*4882a593Smuzhiyun 	if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1320*4882a593Smuzhiyun 	      valid_yl2xp1:
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun 		sign = getsign(st0_ptr);
1323*4882a593Smuzhiyun 		sign1 = getsign(st1_ptr);
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 		FPU_to_exp16(st0_ptr, &a);
1326*4882a593Smuzhiyun 		FPU_to_exp16(st1_ptr, &b);
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun 		if (poly_l2p1(sign, sign1, &a, &b, st1_ptr))
1329*4882a593Smuzhiyun 			return;
1330*4882a593Smuzhiyun 
1331*4882a593Smuzhiyun 		FPU_pop();
1332*4882a593Smuzhiyun 		return;
1333*4882a593Smuzhiyun 	}
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun 	if (st0_tag == TAG_Special)
1336*4882a593Smuzhiyun 		st0_tag = FPU_Special(st0_ptr);
1337*4882a593Smuzhiyun 	if (st1_tag == TAG_Special)
1338*4882a593Smuzhiyun 		st1_tag = FPU_Special(st1_ptr);
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun 	if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
1341*4882a593Smuzhiyun 	    || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
1342*4882a593Smuzhiyun 	    || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
1343*4882a593Smuzhiyun 		if (denormal_operand() < 0)
1344*4882a593Smuzhiyun 			return;
1345*4882a593Smuzhiyun 
1346*4882a593Smuzhiyun 		goto valid_yl2xp1;
1347*4882a593Smuzhiyun 	} else if ((st0_tag == TAG_Empty) | (st1_tag == TAG_Empty)) {
1348*4882a593Smuzhiyun 		FPU_stack_underflow_pop(1);
1349*4882a593Smuzhiyun 		return;
1350*4882a593Smuzhiyun 	} else if (st0_tag == TAG_Zero) {
1351*4882a593Smuzhiyun 		switch (st1_tag) {
1352*4882a593Smuzhiyun 		case TW_Denormal:
1353*4882a593Smuzhiyun 			if (denormal_operand() < 0)
1354*4882a593Smuzhiyun 				return;
1355*4882a593Smuzhiyun 			fallthrough;
1356*4882a593Smuzhiyun 		case TAG_Zero:
1357*4882a593Smuzhiyun 		case TAG_Valid:
1358*4882a593Smuzhiyun 			setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
1359*4882a593Smuzhiyun 			FPU_copy_to_reg1(st0_ptr, st0_tag);
1360*4882a593Smuzhiyun 			break;
1361*4882a593Smuzhiyun 
1362*4882a593Smuzhiyun 		case TW_Infinity:
1363*4882a593Smuzhiyun 			/* Infinity*log(1) */
1364*4882a593Smuzhiyun 			if (arith_invalid(1) < 0)
1365*4882a593Smuzhiyun 				return;
1366*4882a593Smuzhiyun 			break;
1367*4882a593Smuzhiyun 
1368*4882a593Smuzhiyun 		case TW_NaN:
1369*4882a593Smuzhiyun 			if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1370*4882a593Smuzhiyun 				return;
1371*4882a593Smuzhiyun 			break;
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 		default:
1374*4882a593Smuzhiyun #ifdef PARANOID
1375*4882a593Smuzhiyun 			EXCEPTION(EX_INTERNAL | 0x116);
1376*4882a593Smuzhiyun 			return;
1377*4882a593Smuzhiyun #endif /* PARANOID */
1378*4882a593Smuzhiyun 			break;
1379*4882a593Smuzhiyun 		}
1380*4882a593Smuzhiyun 	} else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
1381*4882a593Smuzhiyun 		switch (st1_tag) {
1382*4882a593Smuzhiyun 		case TAG_Zero:
1383*4882a593Smuzhiyun 			if (signnegative(st0_ptr)) {
1384*4882a593Smuzhiyun 				if (exponent(st0_ptr) >= 0) {
1385*4882a593Smuzhiyun 					/* st(0) holds <= -1.0 */
1386*4882a593Smuzhiyun #ifdef PECULIAR_486		/* Stupid 80486 doesn't worry about log(negative). */
1387*4882a593Smuzhiyun 					changesign(st1_ptr);
1388*4882a593Smuzhiyun #else
1389*4882a593Smuzhiyun 					if (arith_invalid(1) < 0)
1390*4882a593Smuzhiyun 						return;
1391*4882a593Smuzhiyun #endif /* PECULIAR_486 */
1392*4882a593Smuzhiyun 				} else if ((st0_tag == TW_Denormal)
1393*4882a593Smuzhiyun 					   && (denormal_operand() < 0))
1394*4882a593Smuzhiyun 					return;
1395*4882a593Smuzhiyun 				else
1396*4882a593Smuzhiyun 					changesign(st1_ptr);
1397*4882a593Smuzhiyun 			} else if ((st0_tag == TW_Denormal)
1398*4882a593Smuzhiyun 				   && (denormal_operand() < 0))
1399*4882a593Smuzhiyun 				return;
1400*4882a593Smuzhiyun 			break;
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun 		case TW_Infinity:
1403*4882a593Smuzhiyun 			if (signnegative(st0_ptr)) {
1404*4882a593Smuzhiyun 				if ((exponent(st0_ptr) >= 0) &&
1405*4882a593Smuzhiyun 				    !((st0_ptr->sigh == 0x80000000) &&
1406*4882a593Smuzhiyun 				      (st0_ptr->sigl == 0))) {
1407*4882a593Smuzhiyun 					/* st(0) holds < -1.0 */
1408*4882a593Smuzhiyun #ifdef PECULIAR_486		/* Stupid 80486 doesn't worry about log(negative). */
1409*4882a593Smuzhiyun 					changesign(st1_ptr);
1410*4882a593Smuzhiyun #else
1411*4882a593Smuzhiyun 					if (arith_invalid(1) < 0)
1412*4882a593Smuzhiyun 						return;
1413*4882a593Smuzhiyun #endif /* PECULIAR_486 */
1414*4882a593Smuzhiyun 				} else if ((st0_tag == TW_Denormal)
1415*4882a593Smuzhiyun 					   && (denormal_operand() < 0))
1416*4882a593Smuzhiyun 					return;
1417*4882a593Smuzhiyun 				else
1418*4882a593Smuzhiyun 					changesign(st1_ptr);
1419*4882a593Smuzhiyun 			} else if ((st0_tag == TW_Denormal)
1420*4882a593Smuzhiyun 				   && (denormal_operand() < 0))
1421*4882a593Smuzhiyun 				return;
1422*4882a593Smuzhiyun 			break;
1423*4882a593Smuzhiyun 
1424*4882a593Smuzhiyun 		case TW_NaN:
1425*4882a593Smuzhiyun 			if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1426*4882a593Smuzhiyun 				return;
1427*4882a593Smuzhiyun 		}
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun 	} else if (st0_tag == TW_NaN) {
1430*4882a593Smuzhiyun 		if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1431*4882a593Smuzhiyun 			return;
1432*4882a593Smuzhiyun 	} else if (st0_tag == TW_Infinity) {
1433*4882a593Smuzhiyun 		if (st1_tag == TW_NaN) {
1434*4882a593Smuzhiyun 			if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1435*4882a593Smuzhiyun 				return;
1436*4882a593Smuzhiyun 		} else if (signnegative(st0_ptr)) {
1437*4882a593Smuzhiyun #ifndef PECULIAR_486
1438*4882a593Smuzhiyun 			/* This should have higher priority than denormals, but... */
1439*4882a593Smuzhiyun 			if (arith_invalid(1) < 0)	/* log(-infinity) */
1440*4882a593Smuzhiyun 				return;
1441*4882a593Smuzhiyun #endif /* PECULIAR_486 */
1442*4882a593Smuzhiyun 			if ((st1_tag == TW_Denormal)
1443*4882a593Smuzhiyun 			    && (denormal_operand() < 0))
1444*4882a593Smuzhiyun 				return;
1445*4882a593Smuzhiyun #ifdef PECULIAR_486
1446*4882a593Smuzhiyun 			/* Denormal operands actually get higher priority */
1447*4882a593Smuzhiyun 			if (arith_invalid(1) < 0)	/* log(-infinity) */
1448*4882a593Smuzhiyun 				return;
1449*4882a593Smuzhiyun #endif /* PECULIAR_486 */
1450*4882a593Smuzhiyun 		} else if (st1_tag == TAG_Zero) {
1451*4882a593Smuzhiyun 			/* log(infinity) */
1452*4882a593Smuzhiyun 			if (arith_invalid(1) < 0)
1453*4882a593Smuzhiyun 				return;
1454*4882a593Smuzhiyun 		}
1455*4882a593Smuzhiyun 
1456*4882a593Smuzhiyun 		/* st(1) must be valid here. */
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 		else if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
1459*4882a593Smuzhiyun 			return;
1460*4882a593Smuzhiyun 
1461*4882a593Smuzhiyun 		/* The Manual says that log(Infinity) is invalid, but a real
1462*4882a593Smuzhiyun 		   80486 sensibly says that it is o.k. */
1463*4882a593Smuzhiyun 		else {
1464*4882a593Smuzhiyun 			u_char sign = getsign(st1_ptr);
1465*4882a593Smuzhiyun 			FPU_copy_to_reg1(&CONST_INF, TAG_Special);
1466*4882a593Smuzhiyun 			setsign(st1_ptr, sign);
1467*4882a593Smuzhiyun 		}
1468*4882a593Smuzhiyun 	}
1469*4882a593Smuzhiyun #ifdef PARANOID
1470*4882a593Smuzhiyun 	else {
1471*4882a593Smuzhiyun 		EXCEPTION(EX_INTERNAL | 0x117);
1472*4882a593Smuzhiyun 		return;
1473*4882a593Smuzhiyun 	}
1474*4882a593Smuzhiyun #endif /* PARANOID */
1475*4882a593Smuzhiyun 
1476*4882a593Smuzhiyun 	FPU_pop();
1477*4882a593Smuzhiyun 	return;
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun }
1480*4882a593Smuzhiyun 
fscale(FPU_REG * st0_ptr,u_char st0_tag)1481*4882a593Smuzhiyun static void fscale(FPU_REG *st0_ptr, u_char st0_tag)
1482*4882a593Smuzhiyun {
1483*4882a593Smuzhiyun 	FPU_REG *st1_ptr = &st(1);
1484*4882a593Smuzhiyun 	u_char st1_tag = FPU_gettagi(1);
1485*4882a593Smuzhiyun 	int old_cw = control_word;
1486*4882a593Smuzhiyun 	u_char sign = getsign(st0_ptr);
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun 	clear_C1();
1489*4882a593Smuzhiyun 	if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1490*4882a593Smuzhiyun 		long scale;
1491*4882a593Smuzhiyun 		FPU_REG tmp;
1492*4882a593Smuzhiyun 
1493*4882a593Smuzhiyun 		/* Convert register for internal use. */
1494*4882a593Smuzhiyun 		setexponent16(st0_ptr, exponent(st0_ptr));
1495*4882a593Smuzhiyun 
1496*4882a593Smuzhiyun 	      valid_scale:
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun 		if (exponent(st1_ptr) > 30) {
1499*4882a593Smuzhiyun 			/* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun 			if (signpositive(st1_ptr)) {
1502*4882a593Smuzhiyun 				EXCEPTION(EX_Overflow);
1503*4882a593Smuzhiyun 				FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1504*4882a593Smuzhiyun 			} else {
1505*4882a593Smuzhiyun 				EXCEPTION(EX_Underflow);
1506*4882a593Smuzhiyun 				FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1507*4882a593Smuzhiyun 			}
1508*4882a593Smuzhiyun 			setsign(st0_ptr, sign);
1509*4882a593Smuzhiyun 			return;
1510*4882a593Smuzhiyun 		}
1511*4882a593Smuzhiyun 
1512*4882a593Smuzhiyun 		control_word &= ~CW_RC;
1513*4882a593Smuzhiyun 		control_word |= RC_CHOP;
1514*4882a593Smuzhiyun 		reg_copy(st1_ptr, &tmp);
1515*4882a593Smuzhiyun 		FPU_round_to_int(&tmp, st1_tag);	/* This can never overflow here */
1516*4882a593Smuzhiyun 		control_word = old_cw;
1517*4882a593Smuzhiyun 		scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl;
1518*4882a593Smuzhiyun 		scale += exponent16(st0_ptr);
1519*4882a593Smuzhiyun 
1520*4882a593Smuzhiyun 		setexponent16(st0_ptr, scale);
1521*4882a593Smuzhiyun 
1522*4882a593Smuzhiyun 		/* Use FPU_round() to properly detect under/overflow etc */
1523*4882a593Smuzhiyun 		FPU_round(st0_ptr, 0, 0, control_word, sign);
1524*4882a593Smuzhiyun 
1525*4882a593Smuzhiyun 		return;
1526*4882a593Smuzhiyun 	}
1527*4882a593Smuzhiyun 
1528*4882a593Smuzhiyun 	if (st0_tag == TAG_Special)
1529*4882a593Smuzhiyun 		st0_tag = FPU_Special(st0_ptr);
1530*4882a593Smuzhiyun 	if (st1_tag == TAG_Special)
1531*4882a593Smuzhiyun 		st1_tag = FPU_Special(st1_ptr);
1532*4882a593Smuzhiyun 
1533*4882a593Smuzhiyun 	if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
1534*4882a593Smuzhiyun 		switch (st1_tag) {
1535*4882a593Smuzhiyun 		case TAG_Valid:
1536*4882a593Smuzhiyun 			/* st(0) must be a denormal */
1537*4882a593Smuzhiyun 			if ((st0_tag == TW_Denormal)
1538*4882a593Smuzhiyun 			    && (denormal_operand() < 0))
1539*4882a593Smuzhiyun 				return;
1540*4882a593Smuzhiyun 
1541*4882a593Smuzhiyun 			FPU_to_exp16(st0_ptr, st0_ptr);	/* Will not be left on stack */
1542*4882a593Smuzhiyun 			goto valid_scale;
1543*4882a593Smuzhiyun 
1544*4882a593Smuzhiyun 		case TAG_Zero:
1545*4882a593Smuzhiyun 			if (st0_tag == TW_Denormal)
1546*4882a593Smuzhiyun 				denormal_operand();
1547*4882a593Smuzhiyun 			return;
1548*4882a593Smuzhiyun 
1549*4882a593Smuzhiyun 		case TW_Denormal:
1550*4882a593Smuzhiyun 			denormal_operand();
1551*4882a593Smuzhiyun 			return;
1552*4882a593Smuzhiyun 
1553*4882a593Smuzhiyun 		case TW_Infinity:
1554*4882a593Smuzhiyun 			if ((st0_tag == TW_Denormal)
1555*4882a593Smuzhiyun 			    && (denormal_operand() < 0))
1556*4882a593Smuzhiyun 				return;
1557*4882a593Smuzhiyun 
1558*4882a593Smuzhiyun 			if (signpositive(st1_ptr))
1559*4882a593Smuzhiyun 				FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1560*4882a593Smuzhiyun 			else
1561*4882a593Smuzhiyun 				FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1562*4882a593Smuzhiyun 			setsign(st0_ptr, sign);
1563*4882a593Smuzhiyun 			return;
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun 		case TW_NaN:
1566*4882a593Smuzhiyun 			real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1567*4882a593Smuzhiyun 			return;
1568*4882a593Smuzhiyun 		}
1569*4882a593Smuzhiyun 	} else if (st0_tag == TAG_Zero) {
1570*4882a593Smuzhiyun 		switch (st1_tag) {
1571*4882a593Smuzhiyun 		case TAG_Valid:
1572*4882a593Smuzhiyun 		case TAG_Zero:
1573*4882a593Smuzhiyun 			return;
1574*4882a593Smuzhiyun 
1575*4882a593Smuzhiyun 		case TW_Denormal:
1576*4882a593Smuzhiyun 			denormal_operand();
1577*4882a593Smuzhiyun 			return;
1578*4882a593Smuzhiyun 
1579*4882a593Smuzhiyun 		case TW_Infinity:
1580*4882a593Smuzhiyun 			if (signpositive(st1_ptr))
1581*4882a593Smuzhiyun 				arith_invalid(0);	/* Zero scaled by +Infinity */
1582*4882a593Smuzhiyun 			return;
1583*4882a593Smuzhiyun 
1584*4882a593Smuzhiyun 		case TW_NaN:
1585*4882a593Smuzhiyun 			real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1586*4882a593Smuzhiyun 			return;
1587*4882a593Smuzhiyun 		}
1588*4882a593Smuzhiyun 	} else if (st0_tag == TW_Infinity) {
1589*4882a593Smuzhiyun 		switch (st1_tag) {
1590*4882a593Smuzhiyun 		case TAG_Valid:
1591*4882a593Smuzhiyun 		case TAG_Zero:
1592*4882a593Smuzhiyun 			return;
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun 		case TW_Denormal:
1595*4882a593Smuzhiyun 			denormal_operand();
1596*4882a593Smuzhiyun 			return;
1597*4882a593Smuzhiyun 
1598*4882a593Smuzhiyun 		case TW_Infinity:
1599*4882a593Smuzhiyun 			if (signnegative(st1_ptr))
1600*4882a593Smuzhiyun 				arith_invalid(0);	/* Infinity scaled by -Infinity */
1601*4882a593Smuzhiyun 			return;
1602*4882a593Smuzhiyun 
1603*4882a593Smuzhiyun 		case TW_NaN:
1604*4882a593Smuzhiyun 			real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1605*4882a593Smuzhiyun 			return;
1606*4882a593Smuzhiyun 		}
1607*4882a593Smuzhiyun 	} else if (st0_tag == TW_NaN) {
1608*4882a593Smuzhiyun 		if (st1_tag != TAG_Empty) {
1609*4882a593Smuzhiyun 			real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1610*4882a593Smuzhiyun 			return;
1611*4882a593Smuzhiyun 		}
1612*4882a593Smuzhiyun 	}
1613*4882a593Smuzhiyun #ifdef PARANOID
1614*4882a593Smuzhiyun 	if (!((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty))) {
1615*4882a593Smuzhiyun 		EXCEPTION(EX_INTERNAL | 0x115);
1616*4882a593Smuzhiyun 		return;
1617*4882a593Smuzhiyun 	}
1618*4882a593Smuzhiyun #endif
1619*4882a593Smuzhiyun 
1620*4882a593Smuzhiyun 	/* At least one of st(0), st(1) must be empty */
1621*4882a593Smuzhiyun 	FPU_stack_underflow();
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun }
1624*4882a593Smuzhiyun 
1625*4882a593Smuzhiyun /*---------------------------------------------------------------------------*/
1626*4882a593Smuzhiyun 
1627*4882a593Smuzhiyun static FUNC_ST0 const trig_table_a[] = {
1628*4882a593Smuzhiyun 	f2xm1, fyl2x, fptan, fpatan,
1629*4882a593Smuzhiyun 	fxtract, fprem1, (FUNC_ST0) fdecstp, (FUNC_ST0) fincstp
1630*4882a593Smuzhiyun };
1631*4882a593Smuzhiyun 
FPU_triga(void)1632*4882a593Smuzhiyun void FPU_triga(void)
1633*4882a593Smuzhiyun {
1634*4882a593Smuzhiyun 	(trig_table_a[FPU_rm]) (&st(0), FPU_gettag0());
1635*4882a593Smuzhiyun }
1636*4882a593Smuzhiyun 
1637*4882a593Smuzhiyun static FUNC_ST0 const trig_table_b[] = {
1638*4882a593Smuzhiyun 	fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0) fsin, fcos
1639*4882a593Smuzhiyun };
1640*4882a593Smuzhiyun 
FPU_trigb(void)1641*4882a593Smuzhiyun void FPU_trigb(void)
1642*4882a593Smuzhiyun {
1643*4882a593Smuzhiyun 	(trig_table_b[FPU_rm]) (&st(0), FPU_gettag0());
1644*4882a593Smuzhiyun }
1645