xref: /linux/arch/x86/math-emu/fpu_trig.c (revision 621cde16e49b3ecf7d59a8106a20aaebfb4a59a9)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2da957e11SThomas Gleixner /*---------------------------------------------------------------------------+
3da957e11SThomas Gleixner  |  fpu_trig.c                                                               |
4da957e11SThomas Gleixner  |                                                                           |
5da957e11SThomas Gleixner  | Implementation of the FPU "transcendental" functions.                     |
6da957e11SThomas Gleixner  |                                                                           |
7da957e11SThomas Gleixner  | Copyright (C) 1992,1993,1994,1997,1999                                    |
8da957e11SThomas Gleixner  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
9da957e11SThomas Gleixner  |                       Australia.  E-mail   billm@melbpc.org.au            |
10da957e11SThomas Gleixner  |                                                                           |
11da957e11SThomas Gleixner  |                                                                           |
12da957e11SThomas Gleixner  +---------------------------------------------------------------------------*/
13da957e11SThomas Gleixner 
14da957e11SThomas Gleixner #include "fpu_system.h"
15da957e11SThomas Gleixner #include "exception.h"
16da957e11SThomas Gleixner #include "fpu_emu.h"
17da957e11SThomas Gleixner #include "status_w.h"
18da957e11SThomas Gleixner #include "control_w.h"
19da957e11SThomas Gleixner #include "reg_constant.h"
20da957e11SThomas Gleixner 
21da957e11SThomas Gleixner static void rem_kernel(unsigned long long st0, unsigned long long *y,
223d0d14f9SIngo Molnar 		       unsigned long long st1, unsigned long long q, int n);
23da957e11SThomas Gleixner 
24da957e11SThomas Gleixner #define BETTER_THAN_486
25da957e11SThomas Gleixner 
26da957e11SThomas Gleixner #define FCOS  4
27da957e11SThomas Gleixner 
28da957e11SThomas Gleixner /* Used only by fptan, fsin, fcos, and fsincos. */
29da957e11SThomas Gleixner /* This routine produces very accurate results, similar to
30da957e11SThomas Gleixner    using a value of pi with more than 128 bits precision. */
31da957e11SThomas Gleixner /* Limited measurements show no results worse than 64 bit precision
32da957e11SThomas Gleixner    except for the results for arguments close to 2^63, where the
33da957e11SThomas Gleixner    precision of the result sometimes degrades to about 63.9 bits */
trig_arg(FPU_REG * st0_ptr,int even)34da957e11SThomas Gleixner static int trig_arg(FPU_REG *st0_ptr, int even)
35da957e11SThomas Gleixner {
36da957e11SThomas Gleixner 	FPU_REG tmp;
37da957e11SThomas Gleixner 	u_char tmptag;
38da957e11SThomas Gleixner 	unsigned long long q;
39da957e11SThomas Gleixner 	int old_cw = control_word, saved_status = partial_status;
40da957e11SThomas Gleixner 	int tag, st0_tag = TAG_Valid;
41da957e11SThomas Gleixner 
423d0d14f9SIngo Molnar 	if (exponent(st0_ptr) >= 63) {
43da957e11SThomas Gleixner 		partial_status |= SW_C2;	/* Reduction incomplete. */
44da957e11SThomas Gleixner 		return -1;
45da957e11SThomas Gleixner 	}
46da957e11SThomas Gleixner 
47da957e11SThomas Gleixner 	control_word &= ~CW_RC;
48da957e11SThomas Gleixner 	control_word |= RC_CHOP;
49da957e11SThomas Gleixner 
50da957e11SThomas Gleixner 	setpositive(st0_ptr);
51da957e11SThomas Gleixner 	tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
52da957e11SThomas Gleixner 			SIGN_POS);
53da957e11SThomas Gleixner 
54da957e11SThomas Gleixner 	FPU_round_to_int(&tmp, tag);	/* Fortunately, this can't overflow
55da957e11SThomas Gleixner 					   to 2^64 */
56da957e11SThomas Gleixner 	q = significand(&tmp);
573d0d14f9SIngo Molnar 	if (q) {
58da957e11SThomas Gleixner 		rem_kernel(significand(st0_ptr),
59da957e11SThomas Gleixner 			   &significand(&tmp),
60da957e11SThomas Gleixner 			   significand(&CONST_PI2),
61da957e11SThomas Gleixner 			   q, exponent(st0_ptr) - exponent(&CONST_PI2));
62da957e11SThomas Gleixner 		setexponent16(&tmp, exponent(&CONST_PI2));
63da957e11SThomas Gleixner 		st0_tag = FPU_normalize(&tmp);
64da957e11SThomas Gleixner 		FPU_copy_to_reg0(&tmp, st0_tag);
65da957e11SThomas Gleixner 	}
66da957e11SThomas Gleixner 
673d0d14f9SIngo Molnar 	if ((even && !(q & 1)) || (!even && (q & 1))) {
683d0d14f9SIngo Molnar 		st0_tag =
693d0d14f9SIngo Molnar 		    FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
703d0d14f9SIngo Molnar 			    FULL_PRECISION);
71da957e11SThomas Gleixner 
72da957e11SThomas Gleixner #ifdef BETTER_THAN_486
73da957e11SThomas Gleixner 		/* So far, the results are exact but based upon a 64 bit
74da957e11SThomas Gleixner 		   precision approximation to pi/2. The technique used
75da957e11SThomas Gleixner 		   now is equivalent to using an approximation to pi/2 which
76da957e11SThomas Gleixner 		   is accurate to about 128 bits. */
773d0d14f9SIngo Molnar 		if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)
783d0d14f9SIngo Molnar 		    || (q > 1)) {
79da957e11SThomas Gleixner 			/* This code gives the effect of having pi/2 to better than
80da957e11SThomas Gleixner 			   128 bits precision. */
81da957e11SThomas Gleixner 
82da957e11SThomas Gleixner 			significand(&tmp) = q + 1;
83da957e11SThomas Gleixner 			setexponent16(&tmp, 63);
84da957e11SThomas Gleixner 			FPU_normalize(&tmp);
85da957e11SThomas Gleixner 			tmptag =
863d0d14f9SIngo Molnar 			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
873d0d14f9SIngo Molnar 				      FULL_PRECISION, SIGN_POS,
883d0d14f9SIngo Molnar 				      exponent(&CONST_PI2extra) +
893d0d14f9SIngo Molnar 				      exponent(&tmp));
90da957e11SThomas Gleixner 			setsign(&tmp, getsign(&CONST_PI2extra));
91da957e11SThomas Gleixner 			st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
923d0d14f9SIngo Molnar 			if (signnegative(st0_ptr)) {
93da957e11SThomas Gleixner 				/* CONST_PI2extra is negative, so the result of the addition
94da957e11SThomas Gleixner 				   can be negative. This means that the argument is actually
95da957e11SThomas Gleixner 				   in a different quadrant. The correction is always < pi/2,
96da957e11SThomas Gleixner 				   so it can't overflow into yet another quadrant. */
97da957e11SThomas Gleixner 				setpositive(st0_ptr);
98da957e11SThomas Gleixner 				q++;
99da957e11SThomas Gleixner 			}
100da957e11SThomas Gleixner 		}
101da957e11SThomas Gleixner #endif /* BETTER_THAN_486 */
102da957e11SThomas Gleixner 	}
103da957e11SThomas Gleixner #ifdef BETTER_THAN_486
1043d0d14f9SIngo Molnar 	else {
105da957e11SThomas Gleixner 		/* So far, the results are exact but based upon a 64 bit
106da957e11SThomas Gleixner 		   precision approximation to pi/2. The technique used
107da957e11SThomas Gleixner 		   now is equivalent to using an approximation to pi/2 which
108da957e11SThomas Gleixner 		   is accurate to about 128 bits. */
1093d0d14f9SIngo Molnar 		if (((q > 0)
1103d0d14f9SIngo Molnar 		     && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
1113d0d14f9SIngo Molnar 		    || (q > 1)) {
112da957e11SThomas Gleixner 			/* This code gives the effect of having p/2 to better than
113da957e11SThomas Gleixner 			   128 bits precision. */
114da957e11SThomas Gleixner 
115da957e11SThomas Gleixner 			significand(&tmp) = q;
116da957e11SThomas Gleixner 			setexponent16(&tmp, 63);
117da957e11SThomas Gleixner 			FPU_normalize(&tmp);	/* This must return TAG_Valid */
1183d0d14f9SIngo Molnar 			tmptag =
1193d0d14f9SIngo Molnar 			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
1203d0d14f9SIngo Molnar 				      FULL_PRECISION, SIGN_POS,
1213d0d14f9SIngo Molnar 				      exponent(&CONST_PI2extra) +
1223d0d14f9SIngo Molnar 				      exponent(&tmp));
123da957e11SThomas Gleixner 			setsign(&tmp, getsign(&CONST_PI2extra));
124da957e11SThomas Gleixner 			st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp,
125da957e11SThomas Gleixner 					  FULL_PRECISION);
126da957e11SThomas Gleixner 			if ((exponent(st0_ptr) == exponent(&CONST_PI2)) &&
127da957e11SThomas Gleixner 			    ((st0_ptr->sigh > CONST_PI2.sigh)
128da957e11SThomas Gleixner 			     || ((st0_ptr->sigh == CONST_PI2.sigh)
1293d0d14f9SIngo Molnar 				 && (st0_ptr->sigl > CONST_PI2.sigl)))) {
130da957e11SThomas Gleixner 				/* CONST_PI2extra is negative, so the result of the
131da957e11SThomas Gleixner 				   subtraction can be larger than pi/2. This means
132da957e11SThomas Gleixner 				   that the argument is actually in a different quadrant.
133da957e11SThomas Gleixner 				   The correction is always < pi/2, so it can't overflow
134da957e11SThomas Gleixner 				   into yet another quadrant. */
1353d0d14f9SIngo Molnar 				st0_tag =
1363d0d14f9SIngo Molnar 				    FPU_sub(REV | LOADED | TAG_Valid,
1373d0d14f9SIngo Molnar 					    (int)&CONST_PI2, FULL_PRECISION);
138da957e11SThomas Gleixner 				q++;
139da957e11SThomas Gleixner 			}
140da957e11SThomas Gleixner 		}
141da957e11SThomas Gleixner 	}
142da957e11SThomas Gleixner #endif /* BETTER_THAN_486 */
143da957e11SThomas Gleixner 
144da957e11SThomas Gleixner 	FPU_settag0(st0_tag);
145da957e11SThomas Gleixner 	control_word = old_cw;
146da957e11SThomas Gleixner 	partial_status = saved_status & ~SW_C2;	/* Reduction complete. */
147da957e11SThomas Gleixner 
148da957e11SThomas Gleixner 	return (q & 3) | even;
149da957e11SThomas Gleixner }
150da957e11SThomas Gleixner 
151da957e11SThomas Gleixner /* Convert a long to register */
convert_l2reg(long const * arg,int deststnr)152da957e11SThomas Gleixner static void convert_l2reg(long const *arg, int deststnr)
153da957e11SThomas Gleixner {
154da957e11SThomas Gleixner 	int tag;
155da957e11SThomas Gleixner 	long num = *arg;
156da957e11SThomas Gleixner 	u_char sign;
157da957e11SThomas Gleixner 	FPU_REG *dest = &st(deststnr);
158da957e11SThomas Gleixner 
1593d0d14f9SIngo Molnar 	if (num == 0) {
160da957e11SThomas Gleixner 		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
161da957e11SThomas Gleixner 		return;
162da957e11SThomas Gleixner 	}
163da957e11SThomas Gleixner 
1643d0d14f9SIngo Molnar 	if (num > 0) {
1653d0d14f9SIngo Molnar 		sign = SIGN_POS;
1663d0d14f9SIngo Molnar 	} else {
1673d0d14f9SIngo Molnar 		num = -num;
1683d0d14f9SIngo Molnar 		sign = SIGN_NEG;
1693d0d14f9SIngo Molnar 	}
170da957e11SThomas Gleixner 
171da957e11SThomas Gleixner 	dest->sigh = num;
172da957e11SThomas Gleixner 	dest->sigl = 0;
173da957e11SThomas Gleixner 	setexponent16(dest, 31);
174da957e11SThomas Gleixner 	tag = FPU_normalize(dest);
175da957e11SThomas Gleixner 	FPU_settagi(deststnr, tag);
176da957e11SThomas Gleixner 	setsign(dest, sign);
177da957e11SThomas Gleixner 	return;
178da957e11SThomas Gleixner }
179da957e11SThomas Gleixner 
single_arg_error(FPU_REG * st0_ptr,u_char st0_tag)180da957e11SThomas Gleixner static void single_arg_error(FPU_REG *st0_ptr, u_char st0_tag)
181da957e11SThomas Gleixner {
182da957e11SThomas Gleixner 	if (st0_tag == TAG_Empty)
183da957e11SThomas Gleixner 		FPU_stack_underflow();	/* Puts a QNaN in st(0) */
184da957e11SThomas Gleixner 	else if (st0_tag == TW_NaN)
185da957e11SThomas Gleixner 		real_1op_NaN(st0_ptr);	/* return with a NaN in st(0) */
186da957e11SThomas Gleixner #ifdef PARANOID
187da957e11SThomas Gleixner 	else
188da957e11SThomas Gleixner 		EXCEPTION(EX_INTERNAL | 0x0112);
189da957e11SThomas Gleixner #endif /* PARANOID */
190da957e11SThomas Gleixner }
191da957e11SThomas Gleixner 
single_arg_2_error(FPU_REG * st0_ptr,u_char st0_tag)192da957e11SThomas Gleixner static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag)
193da957e11SThomas Gleixner {
194da957e11SThomas Gleixner 	int isNaN;
195da957e11SThomas Gleixner 
1963d0d14f9SIngo Molnar 	switch (st0_tag) {
197da957e11SThomas Gleixner 	case TW_NaN:
1983d0d14f9SIngo Molnar 		isNaN = (exponent(st0_ptr) == EXP_OVER)
1993d0d14f9SIngo Molnar 		    && (st0_ptr->sigh & 0x80000000);
2003d0d14f9SIngo Molnar 		if (isNaN && !(st0_ptr->sigh & 0x40000000)) {	/* Signaling ? */
201da957e11SThomas Gleixner 			EXCEPTION(EX_Invalid);
2023d0d14f9SIngo Molnar 			if (control_word & CW_Invalid) {
203da957e11SThomas Gleixner 				/* The masked response */
204da957e11SThomas Gleixner 				/* Convert to a QNaN */
205da957e11SThomas Gleixner 				st0_ptr->sigh |= 0x40000000;
206da957e11SThomas Gleixner 				push();
207da957e11SThomas Gleixner 				FPU_copy_to_reg0(st0_ptr, TAG_Special);
208da957e11SThomas Gleixner 			}
2093d0d14f9SIngo Molnar 		} else if (isNaN) {
210da957e11SThomas Gleixner 			/* A QNaN */
211da957e11SThomas Gleixner 			push();
212da957e11SThomas Gleixner 			FPU_copy_to_reg0(st0_ptr, TAG_Special);
2133d0d14f9SIngo Molnar 		} else {
214da957e11SThomas Gleixner 			/* pseudoNaN or other unsupported */
215da957e11SThomas Gleixner 			EXCEPTION(EX_Invalid);
2163d0d14f9SIngo Molnar 			if (control_word & CW_Invalid) {
217da957e11SThomas Gleixner 				/* The masked response */
218da957e11SThomas Gleixner 				FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
219da957e11SThomas Gleixner 				push();
220da957e11SThomas Gleixner 				FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
221da957e11SThomas Gleixner 			}
222da957e11SThomas Gleixner 		}
223da957e11SThomas Gleixner 		break;		/* return with a NaN in st(0) */
224da957e11SThomas Gleixner #ifdef PARANOID
225da957e11SThomas Gleixner 	default:
226da957e11SThomas Gleixner 		EXCEPTION(EX_INTERNAL | 0x0112);
227da957e11SThomas Gleixner #endif /* PARANOID */
228da957e11SThomas Gleixner 	}
229da957e11SThomas Gleixner }
230da957e11SThomas Gleixner 
231da957e11SThomas Gleixner /*---------------------------------------------------------------------------*/
232da957e11SThomas Gleixner 
f2xm1(FPU_REG * st0_ptr,u_char tag)233da957e11SThomas Gleixner static void f2xm1(FPU_REG *st0_ptr, u_char tag)
234da957e11SThomas Gleixner {
235da957e11SThomas Gleixner 	FPU_REG a;
236da957e11SThomas Gleixner 
237da957e11SThomas Gleixner 	clear_C1();
238da957e11SThomas Gleixner 
2393d0d14f9SIngo Molnar 	if (tag == TAG_Valid) {
240da957e11SThomas Gleixner 		/* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */
2413d0d14f9SIngo Molnar 		if (exponent(st0_ptr) < 0) {
242da957e11SThomas Gleixner 		      denormal_arg:
243da957e11SThomas Gleixner 
244da957e11SThomas Gleixner 			FPU_to_exp16(st0_ptr, &a);
245da957e11SThomas Gleixner 
246da957e11SThomas Gleixner 			/* poly_2xm1(x) requires 0 < st(0) < 1. */
247da957e11SThomas Gleixner 			poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
248da957e11SThomas Gleixner 		}
249da957e11SThomas Gleixner 		set_precision_flag_up();	/* 80486 appears to always do this */
250da957e11SThomas Gleixner 		return;
251da957e11SThomas Gleixner 	}
252da957e11SThomas Gleixner 
253da957e11SThomas Gleixner 	if (tag == TAG_Zero)
254da957e11SThomas Gleixner 		return;
255da957e11SThomas Gleixner 
256da957e11SThomas Gleixner 	if (tag == TAG_Special)
257da957e11SThomas Gleixner 		tag = FPU_Special(st0_ptr);
258da957e11SThomas Gleixner 
2593d0d14f9SIngo Molnar 	switch (tag) {
260da957e11SThomas Gleixner 	case TW_Denormal:
261da957e11SThomas Gleixner 		if (denormal_operand() < 0)
262da957e11SThomas Gleixner 			return;
263da957e11SThomas Gleixner 		goto denormal_arg;
264da957e11SThomas Gleixner 	case TW_Infinity:
2653d0d14f9SIngo Molnar 		if (signnegative(st0_ptr)) {
266da957e11SThomas Gleixner 			/* -infinity gives -1 (p16-10) */
267da957e11SThomas Gleixner 			FPU_copy_to_reg0(&CONST_1, TAG_Valid);
268da957e11SThomas Gleixner 			setnegative(st0_ptr);
269da957e11SThomas Gleixner 		}
270da957e11SThomas Gleixner 		return;
271da957e11SThomas Gleixner 	default:
272da957e11SThomas Gleixner 		single_arg_error(st0_ptr, tag);
273da957e11SThomas Gleixner 	}
274da957e11SThomas Gleixner }
275da957e11SThomas Gleixner 
fptan(FPU_REG * st0_ptr,u_char st0_tag)276da957e11SThomas Gleixner static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
277da957e11SThomas Gleixner {
278da957e11SThomas Gleixner 	FPU_REG *st_new_ptr;
279da957e11SThomas Gleixner 	int q;
280da957e11SThomas Gleixner 	u_char arg_sign = getsign(st0_ptr);
281da957e11SThomas Gleixner 
282da957e11SThomas Gleixner 	/* Stack underflow has higher priority */
2833d0d14f9SIngo Molnar 	if (st0_tag == TAG_Empty) {
284da957e11SThomas Gleixner 		FPU_stack_underflow();	/* Puts a QNaN in st(0) */
2853d0d14f9SIngo Molnar 		if (control_word & CW_Invalid) {
286da957e11SThomas Gleixner 			st_new_ptr = &st(-1);
287da957e11SThomas Gleixner 			push();
288da957e11SThomas Gleixner 			FPU_stack_underflow();	/* Puts a QNaN in the new st(0) */
289da957e11SThomas Gleixner 		}
290da957e11SThomas Gleixner 		return;
291da957e11SThomas Gleixner 	}
292da957e11SThomas Gleixner 
2933d0d14f9SIngo Molnar 	if (STACK_OVERFLOW) {
2943d0d14f9SIngo Molnar 		FPU_stack_overflow();
2953d0d14f9SIngo Molnar 		return;
2963d0d14f9SIngo Molnar 	}
297da957e11SThomas Gleixner 
2983d0d14f9SIngo Molnar 	if (st0_tag == TAG_Valid) {
2993d0d14f9SIngo Molnar 		if (exponent(st0_ptr) > -40) {
3003d0d14f9SIngo Molnar 			if ((q = trig_arg(st0_ptr, 0)) == -1) {
301da957e11SThomas Gleixner 				/* Operand is out of range */
302da957e11SThomas Gleixner 				return;
303da957e11SThomas Gleixner 			}
304da957e11SThomas Gleixner 
305da957e11SThomas Gleixner 			poly_tan(st0_ptr);
306da957e11SThomas Gleixner 			setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
307da957e11SThomas Gleixner 			set_precision_flag_up();	/* We do not really know if up or down */
3083d0d14f9SIngo Molnar 		} else {
309da957e11SThomas Gleixner 			/* For a small arg, the result == the argument */
310da957e11SThomas Gleixner 			/* Underflow may happen */
311da957e11SThomas Gleixner 
312da957e11SThomas Gleixner 		      denormal_arg:
313da957e11SThomas Gleixner 
314da957e11SThomas Gleixner 			FPU_to_exp16(st0_ptr, st0_ptr);
315da957e11SThomas Gleixner 
3163d0d14f9SIngo Molnar 			st0_tag =
3173d0d14f9SIngo Molnar 			    FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
318da957e11SThomas Gleixner 			FPU_settag0(st0_tag);
319da957e11SThomas Gleixner 		}
320da957e11SThomas Gleixner 		push();
321da957e11SThomas Gleixner 		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
322da957e11SThomas Gleixner 		return;
323da957e11SThomas Gleixner 	}
324da957e11SThomas Gleixner 
3253d0d14f9SIngo Molnar 	if (st0_tag == TAG_Zero) {
326da957e11SThomas Gleixner 		push();
327da957e11SThomas Gleixner 		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
328da957e11SThomas Gleixner 		setcc(0);
329da957e11SThomas Gleixner 		return;
330da957e11SThomas Gleixner 	}
331da957e11SThomas Gleixner 
332da957e11SThomas Gleixner 	if (st0_tag == TAG_Special)
333da957e11SThomas Gleixner 		st0_tag = FPU_Special(st0_ptr);
334da957e11SThomas Gleixner 
3353d0d14f9SIngo Molnar 	if (st0_tag == TW_Denormal) {
336da957e11SThomas Gleixner 		if (denormal_operand() < 0)
337da957e11SThomas Gleixner 			return;
338da957e11SThomas Gleixner 
339da957e11SThomas Gleixner 		goto denormal_arg;
340da957e11SThomas Gleixner 	}
341da957e11SThomas Gleixner 
3423d0d14f9SIngo Molnar 	if (st0_tag == TW_Infinity) {
343da957e11SThomas Gleixner 		/* The 80486 treats infinity as an invalid operand */
3443d0d14f9SIngo Molnar 		if (arith_invalid(0) >= 0) {
345da957e11SThomas Gleixner 			st_new_ptr = &st(-1);
346da957e11SThomas Gleixner 			push();
347da957e11SThomas Gleixner 			arith_invalid(0);
348da957e11SThomas Gleixner 		}
349da957e11SThomas Gleixner 		return;
350da957e11SThomas Gleixner 	}
351da957e11SThomas Gleixner 
352da957e11SThomas Gleixner 	single_arg_2_error(st0_ptr, st0_tag);
353da957e11SThomas Gleixner }
354da957e11SThomas Gleixner 
fxtract(FPU_REG * st0_ptr,u_char st0_tag)355da957e11SThomas Gleixner static void fxtract(FPU_REG *st0_ptr, u_char st0_tag)
356da957e11SThomas Gleixner {
357da957e11SThomas Gleixner 	FPU_REG *st_new_ptr;
358da957e11SThomas Gleixner 	u_char sign;
359da957e11SThomas Gleixner 	register FPU_REG *st1_ptr = st0_ptr;	/* anticipate */
360da957e11SThomas Gleixner 
3613d0d14f9SIngo Molnar 	if (STACK_OVERFLOW) {
3623d0d14f9SIngo Molnar 		FPU_stack_overflow();
3633d0d14f9SIngo Molnar 		return;
3643d0d14f9SIngo Molnar 	}
365da957e11SThomas Gleixner 
366da957e11SThomas Gleixner 	clear_C1();
367da957e11SThomas Gleixner 
3683d0d14f9SIngo Molnar 	if (st0_tag == TAG_Valid) {
369da957e11SThomas Gleixner 		long e;
370da957e11SThomas Gleixner 
371da957e11SThomas Gleixner 		push();
372da957e11SThomas Gleixner 		sign = getsign(st1_ptr);
373da957e11SThomas Gleixner 		reg_copy(st1_ptr, st_new_ptr);
374da957e11SThomas Gleixner 		setexponent16(st_new_ptr, exponent(st_new_ptr));
375da957e11SThomas Gleixner 
376da957e11SThomas Gleixner 	      denormal_arg:
377da957e11SThomas Gleixner 
378da957e11SThomas Gleixner 		e = exponent16(st_new_ptr);
379da957e11SThomas Gleixner 		convert_l2reg(&e, 1);
380da957e11SThomas Gleixner 		setexponentpos(st_new_ptr, 0);
381da957e11SThomas Gleixner 		setsign(st_new_ptr, sign);
382da957e11SThomas Gleixner 		FPU_settag0(TAG_Valid);	/* Needed if arg was a denormal */
383da957e11SThomas Gleixner 		return;
3843d0d14f9SIngo Molnar 	} else if (st0_tag == TAG_Zero) {
385da957e11SThomas Gleixner 		sign = getsign(st0_ptr);
386da957e11SThomas Gleixner 
387da957e11SThomas Gleixner 		if (FPU_divide_by_zero(0, SIGN_NEG) < 0)
388da957e11SThomas Gleixner 			return;
389da957e11SThomas Gleixner 
390da957e11SThomas Gleixner 		push();
391da957e11SThomas Gleixner 		FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
392da957e11SThomas Gleixner 		setsign(st_new_ptr, sign);
393da957e11SThomas Gleixner 		return;
394da957e11SThomas Gleixner 	}
395da957e11SThomas Gleixner 
396da957e11SThomas Gleixner 	if (st0_tag == TAG_Special)
397da957e11SThomas Gleixner 		st0_tag = FPU_Special(st0_ptr);
398da957e11SThomas Gleixner 
3993d0d14f9SIngo Molnar 	if (st0_tag == TW_Denormal) {
400da957e11SThomas Gleixner 		if (denormal_operand() < 0)
401da957e11SThomas Gleixner 			return;
402da957e11SThomas Gleixner 
403da957e11SThomas Gleixner 		push();
404da957e11SThomas Gleixner 		sign = getsign(st1_ptr);
405da957e11SThomas Gleixner 		FPU_to_exp16(st1_ptr, st_new_ptr);
406da957e11SThomas Gleixner 		goto denormal_arg;
4073d0d14f9SIngo Molnar 	} else if (st0_tag == TW_Infinity) {
408da957e11SThomas Gleixner 		sign = getsign(st0_ptr);
409da957e11SThomas Gleixner 		setpositive(st0_ptr);
410da957e11SThomas Gleixner 		push();
411da957e11SThomas Gleixner 		FPU_copy_to_reg0(&CONST_INF, TAG_Special);
412da957e11SThomas Gleixner 		setsign(st_new_ptr, sign);
413da957e11SThomas Gleixner 		return;
4143d0d14f9SIngo Molnar 	} else if (st0_tag == TW_NaN) {
415da957e11SThomas Gleixner 		if (real_1op_NaN(st0_ptr) < 0)
416da957e11SThomas Gleixner 			return;
417da957e11SThomas Gleixner 
418da957e11SThomas Gleixner 		push();
419da957e11SThomas Gleixner 		FPU_copy_to_reg0(st0_ptr, TAG_Special);
420da957e11SThomas Gleixner 		return;
4213d0d14f9SIngo Molnar 	} else if (st0_tag == TAG_Empty) {
422da957e11SThomas Gleixner 		/* Is this the correct behaviour? */
4233d0d14f9SIngo Molnar 		if (control_word & EX_Invalid) {
424da957e11SThomas Gleixner 			FPU_stack_underflow();
425da957e11SThomas Gleixner 			push();
426da957e11SThomas Gleixner 			FPU_stack_underflow();
4273d0d14f9SIngo Molnar 		} else
428da957e11SThomas Gleixner 			EXCEPTION(EX_StackUnder);
429da957e11SThomas Gleixner 	}
430da957e11SThomas Gleixner #ifdef PARANOID
431da957e11SThomas Gleixner 	else
432da957e11SThomas Gleixner 		EXCEPTION(EX_INTERNAL | 0x119);
433da957e11SThomas Gleixner #endif /* PARANOID */
434da957e11SThomas Gleixner }
435da957e11SThomas Gleixner 
fdecstp(FPU_REG * st0_ptr,u_char st0_tag)436*e0ca9353SArnd Bergmann static void fdecstp(FPU_REG *st0_ptr, u_char st0_tag)
437da957e11SThomas Gleixner {
438da957e11SThomas Gleixner 	clear_C1();
439da957e11SThomas Gleixner 	top--;
440da957e11SThomas Gleixner }
441da957e11SThomas Gleixner 
fincstp(FPU_REG * st0_ptr,u_char st0_tag)442*e0ca9353SArnd Bergmann static void fincstp(FPU_REG *st0_ptr, u_char st0_tag)
443da957e11SThomas Gleixner {
444da957e11SThomas Gleixner 	clear_C1();
445da957e11SThomas Gleixner 	top++;
446da957e11SThomas Gleixner }
447da957e11SThomas Gleixner 
fsqrt_(FPU_REG * st0_ptr,u_char st0_tag)448da957e11SThomas Gleixner static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
449da957e11SThomas Gleixner {
450da957e11SThomas Gleixner 	int expon;
451da957e11SThomas Gleixner 
452da957e11SThomas Gleixner 	clear_C1();
453da957e11SThomas Gleixner 
4543d0d14f9SIngo Molnar 	if (st0_tag == TAG_Valid) {
455da957e11SThomas Gleixner 		u_char tag;
456da957e11SThomas Gleixner 
4573d0d14f9SIngo Molnar 		if (signnegative(st0_ptr)) {
458da957e11SThomas Gleixner 			arith_invalid(0);	/* sqrt(negative) is invalid */
459da957e11SThomas Gleixner 			return;
460da957e11SThomas Gleixner 		}
461da957e11SThomas Gleixner 
462da957e11SThomas Gleixner 		/* make st(0) in  [1.0 .. 4.0) */
463da957e11SThomas Gleixner 		expon = exponent(st0_ptr);
464da957e11SThomas Gleixner 
465da957e11SThomas Gleixner 	      denormal_arg:
466da957e11SThomas Gleixner 
467da957e11SThomas Gleixner 		setexponent16(st0_ptr, (expon & 1));
468da957e11SThomas Gleixner 
469da957e11SThomas Gleixner 		/* Do the computation, the sign of the result will be positive. */
470da957e11SThomas Gleixner 		tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
471da957e11SThomas Gleixner 		addexponent(st0_ptr, expon >> 1);
472da957e11SThomas Gleixner 		FPU_settag0(tag);
473da957e11SThomas Gleixner 		return;
474da957e11SThomas Gleixner 	}
475da957e11SThomas Gleixner 
476da957e11SThomas Gleixner 	if (st0_tag == TAG_Zero)
477da957e11SThomas Gleixner 		return;
478da957e11SThomas Gleixner 
479da957e11SThomas Gleixner 	if (st0_tag == TAG_Special)
480da957e11SThomas Gleixner 		st0_tag = FPU_Special(st0_ptr);
481da957e11SThomas Gleixner 
4823d0d14f9SIngo Molnar 	if (st0_tag == TW_Infinity) {
483da957e11SThomas Gleixner 		if (signnegative(st0_ptr))
484da957e11SThomas Gleixner 			arith_invalid(0);	/* sqrt(-Infinity) is invalid */
485da957e11SThomas Gleixner 		return;
4863d0d14f9SIngo Molnar 	} else if (st0_tag == TW_Denormal) {
4873d0d14f9SIngo Molnar 		if (signnegative(st0_ptr)) {
488da957e11SThomas Gleixner 			arith_invalid(0);	/* sqrt(negative) is invalid */
489da957e11SThomas Gleixner 			return;
490da957e11SThomas Gleixner 		}
491da957e11SThomas Gleixner 
492da957e11SThomas Gleixner 		if (denormal_operand() < 0)
493da957e11SThomas Gleixner 			return;
494da957e11SThomas Gleixner 
495da957e11SThomas Gleixner 		FPU_to_exp16(st0_ptr, st0_ptr);
496da957e11SThomas Gleixner 
497da957e11SThomas Gleixner 		expon = exponent16(st0_ptr);
498da957e11SThomas Gleixner 
499da957e11SThomas Gleixner 		goto denormal_arg;
500da957e11SThomas Gleixner 	}
501da957e11SThomas Gleixner 
502da957e11SThomas Gleixner 	single_arg_error(st0_ptr, st0_tag);
503da957e11SThomas Gleixner 
504da957e11SThomas Gleixner }
505da957e11SThomas Gleixner 
frndint_(FPU_REG * st0_ptr,u_char st0_tag)506da957e11SThomas Gleixner static void frndint_(FPU_REG *st0_ptr, u_char st0_tag)
507da957e11SThomas Gleixner {
508da957e11SThomas Gleixner 	int flags, tag;
509da957e11SThomas Gleixner 
5103d0d14f9SIngo Molnar 	if (st0_tag == TAG_Valid) {
511da957e11SThomas Gleixner 		u_char sign;
512da957e11SThomas Gleixner 
513da957e11SThomas Gleixner 	      denormal_arg:
514da957e11SThomas Gleixner 
515da957e11SThomas Gleixner 		sign = getsign(st0_ptr);
516da957e11SThomas Gleixner 
517da957e11SThomas Gleixner 		if (exponent(st0_ptr) > 63)
518da957e11SThomas Gleixner 			return;
519da957e11SThomas Gleixner 
5203d0d14f9SIngo Molnar 		if (st0_tag == TW_Denormal) {
521da957e11SThomas Gleixner 			if (denormal_operand() < 0)
522da957e11SThomas Gleixner 				return;
523da957e11SThomas Gleixner 		}
524da957e11SThomas Gleixner 
525da957e11SThomas Gleixner 		/* Fortunately, this can't overflow to 2^64 */
526da957e11SThomas Gleixner 		if ((flags = FPU_round_to_int(st0_ptr, st0_tag)))
527da957e11SThomas Gleixner 			set_precision_flag(flags);
528da957e11SThomas Gleixner 
529da957e11SThomas Gleixner 		setexponent16(st0_ptr, 63);
530da957e11SThomas Gleixner 		tag = FPU_normalize(st0_ptr);
531da957e11SThomas Gleixner 		setsign(st0_ptr, sign);
532da957e11SThomas Gleixner 		FPU_settag0(tag);
533da957e11SThomas Gleixner 		return;
534da957e11SThomas Gleixner 	}
535da957e11SThomas Gleixner 
536da957e11SThomas Gleixner 	if (st0_tag == TAG_Zero)
537da957e11SThomas Gleixner 		return;
538da957e11SThomas Gleixner 
539da957e11SThomas Gleixner 	if (st0_tag == TAG_Special)
540da957e11SThomas Gleixner 		st0_tag = FPU_Special(st0_ptr);
541da957e11SThomas Gleixner 
542da957e11SThomas Gleixner 	if (st0_tag == TW_Denormal)
543da957e11SThomas Gleixner 		goto denormal_arg;
544da957e11SThomas Gleixner 	else if (st0_tag == TW_Infinity)
545da957e11SThomas Gleixner 		return;
546da957e11SThomas Gleixner 	else
547da957e11SThomas Gleixner 		single_arg_error(st0_ptr, st0_tag);
548da957e11SThomas Gleixner }
549da957e11SThomas Gleixner 
f_sin(FPU_REG * st0_ptr,u_char tag)550279d56abSArnd Bergmann static int f_sin(FPU_REG *st0_ptr, u_char tag)
551da957e11SThomas Gleixner {
552da957e11SThomas Gleixner 	u_char arg_sign = getsign(st0_ptr);
553da957e11SThomas Gleixner 
5543d0d14f9SIngo Molnar 	if (tag == TAG_Valid) {
555da957e11SThomas Gleixner 		int q;
556da957e11SThomas Gleixner 
5573d0d14f9SIngo Molnar 		if (exponent(st0_ptr) > -40) {
5583d0d14f9SIngo Molnar 			if ((q = trig_arg(st0_ptr, 0)) == -1) {
559da957e11SThomas Gleixner 				/* Operand is out of range */
560da957e11SThomas Gleixner 				return 1;
561da957e11SThomas Gleixner 			}
562da957e11SThomas Gleixner 
563da957e11SThomas Gleixner 			poly_sine(st0_ptr);
564da957e11SThomas Gleixner 
565da957e11SThomas Gleixner 			if (q & 2)
566da957e11SThomas Gleixner 				changesign(st0_ptr);
567da957e11SThomas Gleixner 
568da957e11SThomas Gleixner 			setsign(st0_ptr, getsign(st0_ptr) ^ arg_sign);
569da957e11SThomas Gleixner 
570da957e11SThomas Gleixner 			/* We do not really know if up or down */
571da957e11SThomas Gleixner 			set_precision_flag_up();
572da957e11SThomas Gleixner 			return 0;
5733d0d14f9SIngo Molnar 		} else {
574da957e11SThomas Gleixner 			/* For a small arg, the result == the argument */
575da957e11SThomas Gleixner 			set_precision_flag_up();	/* Must be up. */
576da957e11SThomas Gleixner 			return 0;
577da957e11SThomas Gleixner 		}
578da957e11SThomas Gleixner 	}
579da957e11SThomas Gleixner 
5803d0d14f9SIngo Molnar 	if (tag == TAG_Zero) {
581da957e11SThomas Gleixner 		setcc(0);
582da957e11SThomas Gleixner 		return 0;
583da957e11SThomas Gleixner 	}
584da957e11SThomas Gleixner 
585da957e11SThomas Gleixner 	if (tag == TAG_Special)
586da957e11SThomas Gleixner 		tag = FPU_Special(st0_ptr);
587da957e11SThomas Gleixner 
5883d0d14f9SIngo Molnar 	if (tag == TW_Denormal) {
589da957e11SThomas Gleixner 		if (denormal_operand() < 0)
590da957e11SThomas Gleixner 			return 1;
591da957e11SThomas Gleixner 
592da957e11SThomas Gleixner 		/* For a small arg, the result == the argument */
593da957e11SThomas Gleixner 		/* Underflow may happen */
594da957e11SThomas Gleixner 		FPU_to_exp16(st0_ptr, st0_ptr);
595da957e11SThomas Gleixner 
596da957e11SThomas Gleixner 		tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
597da957e11SThomas Gleixner 
598da957e11SThomas Gleixner 		FPU_settag0(tag);
599da957e11SThomas Gleixner 
600da957e11SThomas Gleixner 		return 0;
6013d0d14f9SIngo Molnar 	} else if (tag == TW_Infinity) {
602da957e11SThomas Gleixner 		/* The 80486 treats infinity as an invalid operand */
603da957e11SThomas Gleixner 		arith_invalid(0);
604da957e11SThomas Gleixner 		return 1;
6053d0d14f9SIngo Molnar 	} else {
606da957e11SThomas Gleixner 		single_arg_error(st0_ptr, tag);
607da957e11SThomas Gleixner 		return 1;
608da957e11SThomas Gleixner 	}
609da957e11SThomas Gleixner }
610da957e11SThomas Gleixner 
fsin(FPU_REG * st0_ptr,u_char tag)611279d56abSArnd Bergmann static void fsin(FPU_REG *st0_ptr, u_char tag)
612279d56abSArnd Bergmann {
613279d56abSArnd Bergmann 	f_sin(st0_ptr, tag);
614279d56abSArnd Bergmann }
615279d56abSArnd Bergmann 
f_cos(FPU_REG * st0_ptr,u_char tag)616da957e11SThomas Gleixner static int f_cos(FPU_REG *st0_ptr, u_char tag)
617da957e11SThomas Gleixner {
618da957e11SThomas Gleixner 	u_char st0_sign;
619da957e11SThomas Gleixner 
620da957e11SThomas Gleixner 	st0_sign = getsign(st0_ptr);
621da957e11SThomas Gleixner 
6223d0d14f9SIngo Molnar 	if (tag == TAG_Valid) {
623da957e11SThomas Gleixner 		int q;
624da957e11SThomas Gleixner 
6253d0d14f9SIngo Molnar 		if (exponent(st0_ptr) > -40) {
626da957e11SThomas Gleixner 			if ((exponent(st0_ptr) < 0)
627da957e11SThomas Gleixner 			    || ((exponent(st0_ptr) == 0)
6283d0d14f9SIngo Molnar 				&& (significand(st0_ptr) <=
6293d0d14f9SIngo Molnar 				    0xc90fdaa22168c234LL))) {
630da957e11SThomas Gleixner 				poly_cos(st0_ptr);
631da957e11SThomas Gleixner 
632da957e11SThomas Gleixner 				/* We do not really know if up or down */
633da957e11SThomas Gleixner 				set_precision_flag_down();
634da957e11SThomas Gleixner 
635da957e11SThomas Gleixner 				return 0;
6363d0d14f9SIngo Molnar 			} else if ((q = trig_arg(st0_ptr, FCOS)) != -1) {
637da957e11SThomas Gleixner 				poly_sine(st0_ptr);
638da957e11SThomas Gleixner 
639da957e11SThomas Gleixner 				if ((q + 1) & 2)
640da957e11SThomas Gleixner 					changesign(st0_ptr);
641da957e11SThomas Gleixner 
642da957e11SThomas Gleixner 				/* We do not really know if up or down */
643da957e11SThomas Gleixner 				set_precision_flag_down();
644da957e11SThomas Gleixner 
645da957e11SThomas Gleixner 				return 0;
6463d0d14f9SIngo Molnar 			} else {
647da957e11SThomas Gleixner 				/* Operand is out of range */
648da957e11SThomas Gleixner 				return 1;
649da957e11SThomas Gleixner 			}
6503d0d14f9SIngo Molnar 		} else {
651da957e11SThomas Gleixner 		      denormal_arg:
652da957e11SThomas Gleixner 
653da957e11SThomas Gleixner 			setcc(0);
654da957e11SThomas Gleixner 			FPU_copy_to_reg0(&CONST_1, TAG_Valid);
655da957e11SThomas Gleixner #ifdef PECULIAR_486
656da957e11SThomas Gleixner 			set_precision_flag_down();	/* 80486 appears to do this. */
657da957e11SThomas Gleixner #else
658da957e11SThomas Gleixner 			set_precision_flag_up();	/* Must be up. */
659da957e11SThomas Gleixner #endif /* PECULIAR_486 */
660da957e11SThomas Gleixner 			return 0;
661da957e11SThomas Gleixner 		}
6623d0d14f9SIngo Molnar 	} else if (tag == TAG_Zero) {
663da957e11SThomas Gleixner 		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
664da957e11SThomas Gleixner 		setcc(0);
665da957e11SThomas Gleixner 		return 0;
666da957e11SThomas Gleixner 	}
667da957e11SThomas Gleixner 
668da957e11SThomas Gleixner 	if (tag == TAG_Special)
669da957e11SThomas Gleixner 		tag = FPU_Special(st0_ptr);
670da957e11SThomas Gleixner 
6713d0d14f9SIngo Molnar 	if (tag == TW_Denormal) {
672da957e11SThomas Gleixner 		if (denormal_operand() < 0)
673da957e11SThomas Gleixner 			return 1;
674da957e11SThomas Gleixner 
675da957e11SThomas Gleixner 		goto denormal_arg;
6763d0d14f9SIngo Molnar 	} else if (tag == TW_Infinity) {
677da957e11SThomas Gleixner 		/* The 80486 treats infinity as an invalid operand */
678da957e11SThomas Gleixner 		arith_invalid(0);
679da957e11SThomas Gleixner 		return 1;
6803d0d14f9SIngo Molnar 	} else {
681da957e11SThomas Gleixner 		single_arg_error(st0_ptr, tag);	/* requires st0_ptr == &st(0) */
682da957e11SThomas Gleixner 		return 1;
683da957e11SThomas Gleixner 	}
684da957e11SThomas Gleixner }
685da957e11SThomas Gleixner 
fcos(FPU_REG * st0_ptr,u_char st0_tag)686da957e11SThomas Gleixner static void fcos(FPU_REG *st0_ptr, u_char st0_tag)
687da957e11SThomas Gleixner {
688da957e11SThomas Gleixner 	f_cos(st0_ptr, st0_tag);
689da957e11SThomas Gleixner }
690da957e11SThomas Gleixner 
fsincos(FPU_REG * st0_ptr,u_char st0_tag)691da957e11SThomas Gleixner static void fsincos(FPU_REG *st0_ptr, u_char st0_tag)
692da957e11SThomas Gleixner {
693da957e11SThomas Gleixner 	FPU_REG *st_new_ptr;
694da957e11SThomas Gleixner 	FPU_REG arg;
695da957e11SThomas Gleixner 	u_char tag;
696da957e11SThomas Gleixner 
697da957e11SThomas Gleixner 	/* Stack underflow has higher priority */
6983d0d14f9SIngo Molnar 	if (st0_tag == TAG_Empty) {
699da957e11SThomas Gleixner 		FPU_stack_underflow();	/* Puts a QNaN in st(0) */
7003d0d14f9SIngo Molnar 		if (control_word & CW_Invalid) {
701da957e11SThomas Gleixner 			st_new_ptr = &st(-1);
702da957e11SThomas Gleixner 			push();
703da957e11SThomas Gleixner 			FPU_stack_underflow();	/* Puts a QNaN in the new st(0) */
704da957e11SThomas Gleixner 		}
705da957e11SThomas Gleixner 		return;
706da957e11SThomas Gleixner 	}
707da957e11SThomas Gleixner 
7083d0d14f9SIngo Molnar 	if (STACK_OVERFLOW) {
7093d0d14f9SIngo Molnar 		FPU_stack_overflow();
7103d0d14f9SIngo Molnar 		return;
7113d0d14f9SIngo Molnar 	}
712da957e11SThomas Gleixner 
713da957e11SThomas Gleixner 	if (st0_tag == TAG_Special)
714da957e11SThomas Gleixner 		tag = FPU_Special(st0_ptr);
715da957e11SThomas Gleixner 	else
716da957e11SThomas Gleixner 		tag = st0_tag;
717da957e11SThomas Gleixner 
7183d0d14f9SIngo Molnar 	if (tag == TW_NaN) {
719da957e11SThomas Gleixner 		single_arg_2_error(st0_ptr, TW_NaN);
720da957e11SThomas Gleixner 		return;
7213d0d14f9SIngo Molnar 	} else if (tag == TW_Infinity) {
722da957e11SThomas Gleixner 		/* The 80486 treats infinity as an invalid operand */
7233d0d14f9SIngo Molnar 		if (arith_invalid(0) >= 0) {
724da957e11SThomas Gleixner 			/* Masked response */
725da957e11SThomas Gleixner 			push();
726da957e11SThomas Gleixner 			arith_invalid(0);
727da957e11SThomas Gleixner 		}
728da957e11SThomas Gleixner 		return;
729da957e11SThomas Gleixner 	}
730da957e11SThomas Gleixner 
731da957e11SThomas Gleixner 	reg_copy(st0_ptr, &arg);
732279d56abSArnd Bergmann 	if (!f_sin(st0_ptr, st0_tag)) {
733da957e11SThomas Gleixner 		push();
734da957e11SThomas Gleixner 		FPU_copy_to_reg0(&arg, st0_tag);
735da957e11SThomas Gleixner 		f_cos(&st(0), st0_tag);
7363d0d14f9SIngo Molnar 	} else {
737da957e11SThomas Gleixner 		/* An error, so restore st(0) */
738da957e11SThomas Gleixner 		FPU_copy_to_reg0(&arg, st0_tag);
739da957e11SThomas Gleixner 	}
740da957e11SThomas Gleixner }
741da957e11SThomas Gleixner 
742da957e11SThomas Gleixner /*---------------------------------------------------------------------------*/
743da957e11SThomas Gleixner /* The following all require two arguments: st(0) and st(1) */
744da957e11SThomas Gleixner 
745da957e11SThomas Gleixner /* A lean, mean kernel for the fprem instructions. This relies upon
746da957e11SThomas Gleixner    the division and rounding to an integer in do_fprem giving an
747da957e11SThomas Gleixner    exact result. Because of this, rem_kernel() needs to deal only with
748da957e11SThomas Gleixner    the least significant 64 bits, the more significant bits of the
749da957e11SThomas Gleixner    result must be zero.
750da957e11SThomas Gleixner  */
rem_kernel(unsigned long long st0,unsigned long long * y,unsigned long long st1,unsigned long long q,int n)751da957e11SThomas Gleixner static void rem_kernel(unsigned long long st0, unsigned long long *y,
7523d0d14f9SIngo Molnar 		       unsigned long long st1, unsigned long long q, int n)
753da957e11SThomas Gleixner {
754da957e11SThomas Gleixner 	int dummy;
755da957e11SThomas Gleixner 	unsigned long long x;
756da957e11SThomas Gleixner 
757da957e11SThomas Gleixner 	x = st0 << n;
758da957e11SThomas Gleixner 
759da957e11SThomas Gleixner 	/* Do the required multiplication and subtraction in the one operation */
760da957e11SThomas Gleixner 
761da957e11SThomas Gleixner 	/* lsw x -= lsw st1 * lsw q */
7623d0d14f9SIngo Molnar 	asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1":"=m"
7633d0d14f9SIngo Molnar 		      (((unsigned *)&x)[0]), "=m"(((unsigned *)&x)[1]),
764da957e11SThomas Gleixner 		      "=a"(dummy)
765da957e11SThomas Gleixner 		      :"2"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[0])
766da957e11SThomas Gleixner 		      :"%dx");
767da957e11SThomas Gleixner 	/* msw x -= msw st1 * lsw q */
7683d0d14f9SIngo Molnar 	asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
7693d0d14f9SIngo Molnar 		      "=a"(dummy)
770da957e11SThomas Gleixner 		      :"1"(((unsigned *)&st1)[1]), "m"(((unsigned *)&q)[0])
771da957e11SThomas Gleixner 		      :"%dx");
772da957e11SThomas Gleixner 	/* msw x -= lsw st1 * msw q */
7733d0d14f9SIngo Molnar 	asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
7743d0d14f9SIngo Molnar 		      "=a"(dummy)
775da957e11SThomas Gleixner 		      :"1"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[1])
776da957e11SThomas Gleixner 		      :"%dx");
777da957e11SThomas Gleixner 
778da957e11SThomas Gleixner 	*y = x;
779da957e11SThomas Gleixner }
780da957e11SThomas Gleixner 
781da957e11SThomas Gleixner /* Remainder of st(0) / st(1) */
782da957e11SThomas Gleixner /* This routine produces exact results, i.e. there is never any
783da957e11SThomas Gleixner    rounding or truncation, etc of the result. */
do_fprem(FPU_REG * st0_ptr,u_char st0_tag,int round)784da957e11SThomas Gleixner static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round)
785da957e11SThomas Gleixner {
786da957e11SThomas Gleixner 	FPU_REG *st1_ptr = &st(1);
787da957e11SThomas Gleixner 	u_char st1_tag = FPU_gettagi(1);
788da957e11SThomas Gleixner 
7893d0d14f9SIngo Molnar 	if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
790da957e11SThomas Gleixner 		FPU_REG tmp, st0, st1;
791da957e11SThomas Gleixner 		u_char st0_sign, st1_sign;
792da957e11SThomas Gleixner 		u_char tmptag;
793da957e11SThomas Gleixner 		int tag;
794da957e11SThomas Gleixner 		int old_cw;
795da957e11SThomas Gleixner 		int expdif;
796da957e11SThomas Gleixner 		long long q;
797da957e11SThomas Gleixner 		unsigned short saved_status;
798da957e11SThomas Gleixner 		int cc;
799da957e11SThomas Gleixner 
800da957e11SThomas Gleixner 	      fprem_valid:
801da957e11SThomas Gleixner 		/* Convert registers for internal use. */
802da957e11SThomas Gleixner 		st0_sign = FPU_to_exp16(st0_ptr, &st0);
803da957e11SThomas Gleixner 		st1_sign = FPU_to_exp16(st1_ptr, &st1);
804da957e11SThomas Gleixner 		expdif = exponent16(&st0) - exponent16(&st1);
805da957e11SThomas Gleixner 
806da957e11SThomas Gleixner 		old_cw = control_word;
807da957e11SThomas Gleixner 		cc = 0;
808da957e11SThomas Gleixner 
809da957e11SThomas Gleixner 		/* We want the status following the denorm tests, but don't want
810da957e11SThomas Gleixner 		   the status changed by the arithmetic operations. */
811da957e11SThomas Gleixner 		saved_status = partial_status;
812da957e11SThomas Gleixner 		control_word &= ~CW_RC;
813da957e11SThomas Gleixner 		control_word |= RC_CHOP;
814da957e11SThomas Gleixner 
8153d0d14f9SIngo Molnar 		if (expdif < 64) {
816da957e11SThomas Gleixner 			/* This should be the most common case */
817da957e11SThomas Gleixner 
8183d0d14f9SIngo Molnar 			if (expdif > -2) {
819da957e11SThomas Gleixner 				u_char sign = st0_sign ^ st1_sign;
820da957e11SThomas Gleixner 				tag = FPU_u_div(&st0, &st1, &tmp,
821da957e11SThomas Gleixner 						PR_64_BITS | RC_CHOP | 0x3f,
822da957e11SThomas Gleixner 						sign);
823da957e11SThomas Gleixner 				setsign(&tmp, sign);
824da957e11SThomas Gleixner 
8253d0d14f9SIngo Molnar 				if (exponent(&tmp) >= 0) {
826da957e11SThomas Gleixner 					FPU_round_to_int(&tmp, tag);	/* Fortunately, this can't
827da957e11SThomas Gleixner 									   overflow to 2^64 */
828da957e11SThomas Gleixner 					q = significand(&tmp);
829da957e11SThomas Gleixner 
830da957e11SThomas Gleixner 					rem_kernel(significand(&st0),
831da957e11SThomas Gleixner 						   &significand(&tmp),
832da957e11SThomas Gleixner 						   significand(&st1),
833da957e11SThomas Gleixner 						   q, expdif);
834da957e11SThomas Gleixner 
835da957e11SThomas Gleixner 					setexponent16(&tmp, exponent16(&st1));
8363d0d14f9SIngo Molnar 				} else {
837da957e11SThomas Gleixner 					reg_copy(&st0, &tmp);
838da957e11SThomas Gleixner 					q = 0;
839da957e11SThomas Gleixner 				}
840da957e11SThomas Gleixner 
8413d0d14f9SIngo Molnar 				if ((round == RC_RND)
8423d0d14f9SIngo Molnar 				    && (tmp.sigh & 0xc0000000)) {
843da957e11SThomas Gleixner 					/* We may need to subtract st(1) once more,
844da957e11SThomas Gleixner 					   to get a result <= 1/2 of st(1). */
845da957e11SThomas Gleixner 					unsigned long long x;
8463d0d14f9SIngo Molnar 					expdif =
8473d0d14f9SIngo Molnar 					    exponent16(&st1) - exponent16(&tmp);
8483d0d14f9SIngo Molnar 					if (expdif <= 1) {
849da957e11SThomas Gleixner 						if (expdif == 0)
8503d0d14f9SIngo Molnar 							x = significand(&st1) -
8513d0d14f9SIngo Molnar 							    significand(&tmp);
852da957e11SThomas Gleixner 						else	/* expdif is 1 */
8533d0d14f9SIngo Molnar 							x = (significand(&st1)
8543d0d14f9SIngo Molnar 							     << 1) -
8553d0d14f9SIngo Molnar 							    significand(&tmp);
856da957e11SThomas Gleixner 						if ((x < significand(&tmp)) ||
857da957e11SThomas Gleixner 						    /* or equi-distant (from 0 & st(1)) and q is odd */
8583d0d14f9SIngo Molnar 						    ((x == significand(&tmp))
8593d0d14f9SIngo Molnar 						     && (q & 1))) {
860da957e11SThomas Gleixner 							st0_sign = !st0_sign;
861da957e11SThomas Gleixner 							significand(&tmp) = x;
862da957e11SThomas Gleixner 							q++;
863da957e11SThomas Gleixner 						}
864da957e11SThomas Gleixner 					}
865da957e11SThomas Gleixner 				}
866da957e11SThomas Gleixner 
8673d0d14f9SIngo Molnar 				if (q & 4)
8683d0d14f9SIngo Molnar 					cc |= SW_C0;
8693d0d14f9SIngo Molnar 				if (q & 2)
8703d0d14f9SIngo Molnar 					cc |= SW_C3;
8713d0d14f9SIngo Molnar 				if (q & 1)
8723d0d14f9SIngo Molnar 					cc |= SW_C1;
8733d0d14f9SIngo Molnar 			} else {
874da957e11SThomas Gleixner 				control_word = old_cw;
875da957e11SThomas Gleixner 				setcc(0);
876da957e11SThomas Gleixner 				return;
877da957e11SThomas Gleixner 			}
8783d0d14f9SIngo Molnar 		} else {
879da957e11SThomas Gleixner 			/* There is a large exponent difference ( >= 64 ) */
880da957e11SThomas Gleixner 			/* To make much sense, the code in this section should
881da957e11SThomas Gleixner 			   be done at high precision. */
882da957e11SThomas Gleixner 			int exp_1, N;
883da957e11SThomas Gleixner 			u_char sign;
884da957e11SThomas Gleixner 
885da957e11SThomas Gleixner 			/* prevent overflow here */
886da957e11SThomas Gleixner 			/* N is 'a number between 32 and 63' (p26-113) */
887da957e11SThomas Gleixner 			reg_copy(&st0, &tmp);
888da957e11SThomas Gleixner 			tmptag = st0_tag;
889da957e11SThomas Gleixner 			N = (expdif & 0x0000001f) + 32;	/* This choice gives results
890da957e11SThomas Gleixner 							   identical to an AMD 486 */
891da957e11SThomas Gleixner 			setexponent16(&tmp, N);
892da957e11SThomas Gleixner 			exp_1 = exponent16(&st1);
893da957e11SThomas Gleixner 			setexponent16(&st1, 0);
894da957e11SThomas Gleixner 			expdif -= N;
895da957e11SThomas Gleixner 
896da957e11SThomas Gleixner 			sign = getsign(&tmp) ^ st1_sign;
8973d0d14f9SIngo Molnar 			tag =
8983d0d14f9SIngo Molnar 			    FPU_u_div(&tmp, &st1, &tmp,
8993d0d14f9SIngo Molnar 				      PR_64_BITS | RC_CHOP | 0x3f, sign);
900da957e11SThomas Gleixner 			setsign(&tmp, sign);
901da957e11SThomas Gleixner 
902da957e11SThomas Gleixner 			FPU_round_to_int(&tmp, tag);	/* Fortunately, this can't
903da957e11SThomas Gleixner 							   overflow to 2^64 */
904da957e11SThomas Gleixner 
905da957e11SThomas Gleixner 			rem_kernel(significand(&st0),
906da957e11SThomas Gleixner 				   &significand(&tmp),
907da957e11SThomas Gleixner 				   significand(&st1),
9083d0d14f9SIngo Molnar 				   significand(&tmp), exponent(&tmp)
909da957e11SThomas Gleixner 			    );
910da957e11SThomas Gleixner 			setexponent16(&tmp, exp_1 + expdif);
911da957e11SThomas Gleixner 
912da957e11SThomas Gleixner 			/* It is possible for the operation to be complete here.
913da957e11SThomas Gleixner 			   What does the IEEE standard say? The Intel 80486 manual
914da957e11SThomas Gleixner 			   implies that the operation will never be completed at this
915da957e11SThomas Gleixner 			   point, and the behaviour of a real 80486 confirms this.
916da957e11SThomas Gleixner 			 */
9173d0d14f9SIngo Molnar 			if (!(tmp.sigh | tmp.sigl)) {
918da957e11SThomas Gleixner 				/* The result is zero */
919da957e11SThomas Gleixner 				control_word = old_cw;
920da957e11SThomas Gleixner 				partial_status = saved_status;
921da957e11SThomas Gleixner 				FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
922da957e11SThomas Gleixner 				setsign(&st0, st0_sign);
923da957e11SThomas Gleixner #ifdef PECULIAR_486
924da957e11SThomas Gleixner 				setcc(SW_C2);
925da957e11SThomas Gleixner #else
926da957e11SThomas Gleixner 				setcc(0);
927da957e11SThomas Gleixner #endif /* PECULIAR_486 */
928da957e11SThomas Gleixner 				return;
929da957e11SThomas Gleixner 			}
930da957e11SThomas Gleixner 			cc = SW_C2;
931da957e11SThomas Gleixner 		}
932da957e11SThomas Gleixner 
933da957e11SThomas Gleixner 		control_word = old_cw;
934da957e11SThomas Gleixner 		partial_status = saved_status;
935da957e11SThomas Gleixner 		tag = FPU_normalize_nuo(&tmp);
936da957e11SThomas Gleixner 		reg_copy(&tmp, st0_ptr);
937da957e11SThomas Gleixner 
938da957e11SThomas Gleixner 		/* The only condition to be looked for is underflow,
939da957e11SThomas Gleixner 		   and it can occur here only if underflow is unmasked. */
940da957e11SThomas Gleixner 		if ((exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero)
9413d0d14f9SIngo Molnar 		    && !(control_word & CW_Underflow)) {
942da957e11SThomas Gleixner 			setcc(cc);
943da957e11SThomas Gleixner 			tag = arith_underflow(st0_ptr);
944da957e11SThomas Gleixner 			setsign(st0_ptr, st0_sign);
945da957e11SThomas Gleixner 			FPU_settag0(tag);
946da957e11SThomas Gleixner 			return;
9473d0d14f9SIngo Molnar 		} else if ((exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero)) {
948da957e11SThomas Gleixner 			stdexp(st0_ptr);
949da957e11SThomas Gleixner 			setsign(st0_ptr, st0_sign);
9503d0d14f9SIngo Molnar 		} else {
9513d0d14f9SIngo Molnar 			tag =
9523d0d14f9SIngo Molnar 			    FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign);
953da957e11SThomas Gleixner 		}
954da957e11SThomas Gleixner 		FPU_settag0(tag);
955da957e11SThomas Gleixner 		setcc(cc);
956da957e11SThomas Gleixner 
957da957e11SThomas Gleixner 		return;
958da957e11SThomas Gleixner 	}
959da957e11SThomas Gleixner 
960da957e11SThomas Gleixner 	if (st0_tag == TAG_Special)
961da957e11SThomas Gleixner 		st0_tag = FPU_Special(st0_ptr);
962da957e11SThomas Gleixner 	if (st1_tag == TAG_Special)
963da957e11SThomas Gleixner 		st1_tag = FPU_Special(st1_ptr);
964da957e11SThomas Gleixner 
965da957e11SThomas Gleixner 	if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
966da957e11SThomas Gleixner 	    || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
9673d0d14f9SIngo Molnar 	    || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
968da957e11SThomas Gleixner 		if (denormal_operand() < 0)
969da957e11SThomas Gleixner 			return;
970da957e11SThomas Gleixner 		goto fprem_valid;
9713d0d14f9SIngo Molnar 	} else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
972da957e11SThomas Gleixner 		FPU_stack_underflow();
973da957e11SThomas Gleixner 		return;
9743d0d14f9SIngo Molnar 	} else if (st0_tag == TAG_Zero) {
9753d0d14f9SIngo Molnar 		if (st1_tag == TAG_Valid) {
9763d0d14f9SIngo Molnar 			setcc(0);
9773d0d14f9SIngo Molnar 			return;
9783d0d14f9SIngo Molnar 		} else if (st1_tag == TW_Denormal) {
979da957e11SThomas Gleixner 			if (denormal_operand() < 0)
980da957e11SThomas Gleixner 				return;
9813d0d14f9SIngo Molnar 			setcc(0);
9823d0d14f9SIngo Molnar 			return;
9833d0d14f9SIngo Molnar 		} else if (st1_tag == TAG_Zero) {
9843d0d14f9SIngo Molnar 			arith_invalid(0);
9853d0d14f9SIngo Molnar 			return;
9863d0d14f9SIngo Molnar 		} /* fprem(?,0) always invalid */
9873d0d14f9SIngo Molnar 		else if (st1_tag == TW_Infinity) {
9883d0d14f9SIngo Molnar 			setcc(0);
989da957e11SThomas Gleixner 			return;
990da957e11SThomas Gleixner 		}
9913d0d14f9SIngo Molnar 	} else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
9923d0d14f9SIngo Molnar 		if (st1_tag == TAG_Zero) {
9933d0d14f9SIngo Molnar 			arith_invalid(0);	/* fprem(Valid,Zero) is invalid */
9943d0d14f9SIngo Molnar 			return;
9953d0d14f9SIngo Molnar 		} else if (st1_tag != TW_NaN) {
9963d0d14f9SIngo Molnar 			if (((st0_tag == TW_Denormal)
9973d0d14f9SIngo Molnar 			     || (st1_tag == TW_Denormal))
998da957e11SThomas Gleixner 			    && (denormal_operand() < 0))
999da957e11SThomas Gleixner 				return;
1000da957e11SThomas Gleixner 
10013d0d14f9SIngo Molnar 			if (st1_tag == TW_Infinity) {
1002da957e11SThomas Gleixner 				/* fprem(Valid,Infinity) is o.k. */
10033d0d14f9SIngo Molnar 				setcc(0);
10043d0d14f9SIngo Molnar 				return;
1005da957e11SThomas Gleixner 			}
1006da957e11SThomas Gleixner 		}
10073d0d14f9SIngo Molnar 	} else if (st0_tag == TW_Infinity) {
10083d0d14f9SIngo Molnar 		if (st1_tag != TW_NaN) {
1009da957e11SThomas Gleixner 			arith_invalid(0);	/* fprem(Infinity,?) is invalid */
1010da957e11SThomas Gleixner 			return;
1011da957e11SThomas Gleixner 		}
1012da957e11SThomas Gleixner 	}
1013da957e11SThomas Gleixner 
1014da957e11SThomas Gleixner 	/* One of the registers must contain a NaN if we got here. */
1015da957e11SThomas Gleixner 
1016da957e11SThomas Gleixner #ifdef PARANOID
1017da957e11SThomas Gleixner 	if ((st0_tag != TW_NaN) && (st1_tag != TW_NaN))
1018da957e11SThomas Gleixner 		EXCEPTION(EX_INTERNAL | 0x118);
1019da957e11SThomas Gleixner #endif /* PARANOID */
1020da957e11SThomas Gleixner 
1021da957e11SThomas Gleixner 	real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr);
1022da957e11SThomas Gleixner 
1023da957e11SThomas Gleixner }
1024da957e11SThomas Gleixner 
1025da957e11SThomas Gleixner /* ST(1) <- ST(1) * log ST;  pop ST */
fyl2x(FPU_REG * st0_ptr,u_char st0_tag)1026da957e11SThomas Gleixner static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag)
1027da957e11SThomas Gleixner {
1028da957e11SThomas Gleixner 	FPU_REG *st1_ptr = &st(1), exponent;
1029da957e11SThomas Gleixner 	u_char st1_tag = FPU_gettagi(1);
1030da957e11SThomas Gleixner 	u_char sign;
1031da957e11SThomas Gleixner 	int e, tag;
1032da957e11SThomas Gleixner 
1033da957e11SThomas Gleixner 	clear_C1();
1034da957e11SThomas Gleixner 
10353d0d14f9SIngo Molnar 	if ((st0_tag == TAG_Valid) && (st1_tag == TAG_Valid)) {
1036da957e11SThomas Gleixner 	      both_valid:
1037da957e11SThomas Gleixner 		/* Both regs are Valid or Denormal */
10383d0d14f9SIngo Molnar 		if (signpositive(st0_ptr)) {
1039da957e11SThomas Gleixner 			if (st0_tag == TW_Denormal)
1040da957e11SThomas Gleixner 				FPU_to_exp16(st0_ptr, st0_ptr);
1041da957e11SThomas Gleixner 			else
1042da957e11SThomas Gleixner 				/* Convert st(0) for internal use. */
1043da957e11SThomas Gleixner 				setexponent16(st0_ptr, exponent(st0_ptr));
1044da957e11SThomas Gleixner 
10453d0d14f9SIngo Molnar 			if ((st0_ptr->sigh == 0x80000000)
10463d0d14f9SIngo Molnar 			    && (st0_ptr->sigl == 0)) {
1047da957e11SThomas Gleixner 				/* Special case. The result can be precise. */
1048da957e11SThomas Gleixner 				u_char esign;
1049da957e11SThomas Gleixner 				e = exponent16(st0_ptr);
10503d0d14f9SIngo Molnar 				if (e >= 0) {
1051da957e11SThomas Gleixner 					exponent.sigh = e;
1052da957e11SThomas Gleixner 					esign = SIGN_POS;
10533d0d14f9SIngo Molnar 				} else {
1054da957e11SThomas Gleixner 					exponent.sigh = -e;
1055da957e11SThomas Gleixner 					esign = SIGN_NEG;
1056da957e11SThomas Gleixner 				}
1057da957e11SThomas Gleixner 				exponent.sigl = 0;
1058da957e11SThomas Gleixner 				setexponent16(&exponent, 31);
1059da957e11SThomas Gleixner 				tag = FPU_normalize_nuo(&exponent);
1060da957e11SThomas Gleixner 				stdexp(&exponent);
1061da957e11SThomas Gleixner 				setsign(&exponent, esign);
10623d0d14f9SIngo Molnar 				tag =
10633d0d14f9SIngo Molnar 				    FPU_mul(&exponent, tag, 1, FULL_PRECISION);
1064da957e11SThomas Gleixner 				if (tag >= 0)
1065da957e11SThomas Gleixner 					FPU_settagi(1, tag);
10663d0d14f9SIngo Molnar 			} else {
1067da957e11SThomas Gleixner 				/* The usual case */
1068da957e11SThomas Gleixner 				sign = getsign(st1_ptr);
1069da957e11SThomas Gleixner 				if (st1_tag == TW_Denormal)
1070da957e11SThomas Gleixner 					FPU_to_exp16(st1_ptr, st1_ptr);
1071da957e11SThomas Gleixner 				else
1072da957e11SThomas Gleixner 					/* Convert st(1) for internal use. */
10733d0d14f9SIngo Molnar 					setexponent16(st1_ptr,
10743d0d14f9SIngo Molnar 						      exponent(st1_ptr));
1075da957e11SThomas Gleixner 				poly_l2(st0_ptr, st1_ptr, sign);
1076da957e11SThomas Gleixner 			}
10773d0d14f9SIngo Molnar 		} else {
1078da957e11SThomas Gleixner 			/* negative */
1079da957e11SThomas Gleixner 			if (arith_invalid(1) < 0)
1080da957e11SThomas Gleixner 				return;
1081da957e11SThomas Gleixner 		}
1082da957e11SThomas Gleixner 
1083da957e11SThomas Gleixner 		FPU_pop();
1084da957e11SThomas Gleixner 
1085da957e11SThomas Gleixner 		return;
1086da957e11SThomas Gleixner 	}
1087da957e11SThomas Gleixner 
1088da957e11SThomas Gleixner 	if (st0_tag == TAG_Special)
1089da957e11SThomas Gleixner 		st0_tag = FPU_Special(st0_ptr);
1090da957e11SThomas Gleixner 	if (st1_tag == TAG_Special)
1091da957e11SThomas Gleixner 		st1_tag = FPU_Special(st1_ptr);
1092da957e11SThomas Gleixner 
10933d0d14f9SIngo Molnar 	if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
1094da957e11SThomas Gleixner 		FPU_stack_underflow_pop(1);
1095da957e11SThomas Gleixner 		return;
10963d0d14f9SIngo Molnar 	} else if ((st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal)) {
10973d0d14f9SIngo Molnar 		if (st0_tag == TAG_Zero) {
10983d0d14f9SIngo Molnar 			if (st1_tag == TAG_Zero) {
1099da957e11SThomas Gleixner 				/* Both args zero is invalid */
1100da957e11SThomas Gleixner 				if (arith_invalid(1) < 0)
1101da957e11SThomas Gleixner 					return;
11023d0d14f9SIngo Molnar 			} else {
1103da957e11SThomas Gleixner 				u_char sign;
1104da957e11SThomas Gleixner 				sign = getsign(st1_ptr) ^ SIGN_NEG;
1105da957e11SThomas Gleixner 				if (FPU_divide_by_zero(1, sign) < 0)
1106da957e11SThomas Gleixner 					return;
1107da957e11SThomas Gleixner 
1108da957e11SThomas Gleixner 				setsign(st1_ptr, sign);
1109da957e11SThomas Gleixner 			}
11103d0d14f9SIngo Molnar 		} else if (st1_tag == TAG_Zero) {
1111da957e11SThomas Gleixner 			/* st(1) contains zero, st(0) valid <> 0 */
1112da957e11SThomas Gleixner 			/* Zero is the valid answer */
1113da957e11SThomas Gleixner 			sign = getsign(st1_ptr);
1114da957e11SThomas Gleixner 
11153d0d14f9SIngo Molnar 			if (signnegative(st0_ptr)) {
1116da957e11SThomas Gleixner 				/* log(negative) */
1117da957e11SThomas Gleixner 				if (arith_invalid(1) < 0)
1118da957e11SThomas Gleixner 					return;
11193d0d14f9SIngo Molnar 			} else if ((st0_tag == TW_Denormal)
11203d0d14f9SIngo Molnar 				   && (denormal_operand() < 0))
1121da957e11SThomas Gleixner 				return;
11223d0d14f9SIngo Molnar 			else {
1123da957e11SThomas Gleixner 				if (exponent(st0_ptr) < 0)
1124da957e11SThomas Gleixner 					sign ^= SIGN_NEG;
1125da957e11SThomas Gleixner 
1126da957e11SThomas Gleixner 				FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1127da957e11SThomas Gleixner 				setsign(st1_ptr, sign);
1128da957e11SThomas Gleixner 			}
11293d0d14f9SIngo Molnar 		} else {
1130da957e11SThomas Gleixner 			/* One or both operands are denormals. */
1131da957e11SThomas Gleixner 			if (denormal_operand() < 0)
1132da957e11SThomas Gleixner 				return;
1133da957e11SThomas Gleixner 			goto both_valid;
1134da957e11SThomas Gleixner 		}
11353d0d14f9SIngo Molnar 	} else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
1136da957e11SThomas Gleixner 		if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1137da957e11SThomas Gleixner 			return;
1138da957e11SThomas Gleixner 	}
1139da957e11SThomas Gleixner 	/* One or both arg must be an infinity */
11403d0d14f9SIngo Molnar 	else if (st0_tag == TW_Infinity) {
11413d0d14f9SIngo Molnar 		if ((signnegative(st0_ptr)) || (st1_tag == TAG_Zero)) {
1142da957e11SThomas Gleixner 			/* log(-infinity) or 0*log(infinity) */
1143da957e11SThomas Gleixner 			if (arith_invalid(1) < 0)
1144da957e11SThomas Gleixner 				return;
11453d0d14f9SIngo Molnar 		} else {
1146da957e11SThomas Gleixner 			u_char sign = getsign(st1_ptr);
1147da957e11SThomas Gleixner 
11483d0d14f9SIngo Molnar 			if ((st1_tag == TW_Denormal)
11493d0d14f9SIngo Molnar 			    && (denormal_operand() < 0))
1150da957e11SThomas Gleixner 				return;
1151da957e11SThomas Gleixner 
1152da957e11SThomas Gleixner 			FPU_copy_to_reg1(&CONST_INF, TAG_Special);
1153da957e11SThomas Gleixner 			setsign(st1_ptr, sign);
1154da957e11SThomas Gleixner 		}
1155da957e11SThomas Gleixner 	}
1156da957e11SThomas Gleixner 	/* st(1) must be infinity here */
1157da957e11SThomas Gleixner 	else if (((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal))
11583d0d14f9SIngo Molnar 		 && (signpositive(st0_ptr))) {
11593d0d14f9SIngo Molnar 		if (exponent(st0_ptr) >= 0) {
1160da957e11SThomas Gleixner 			if ((exponent(st0_ptr) == 0) &&
1161da957e11SThomas Gleixner 			    (st0_ptr->sigh == 0x80000000) &&
11623d0d14f9SIngo Molnar 			    (st0_ptr->sigl == 0)) {
1163da957e11SThomas Gleixner 				/* st(0) holds 1.0 */
1164da957e11SThomas Gleixner 				/* infinity*log(1) */
1165da957e11SThomas Gleixner 				if (arith_invalid(1) < 0)
1166da957e11SThomas Gleixner 					return;
1167da957e11SThomas Gleixner 			}
1168da957e11SThomas Gleixner 			/* else st(0) is positive and > 1.0 */
11693d0d14f9SIngo Molnar 		} else {
1170da957e11SThomas Gleixner 			/* st(0) is positive and < 1.0 */
1171da957e11SThomas Gleixner 
11723d0d14f9SIngo Molnar 			if ((st0_tag == TW_Denormal)
11733d0d14f9SIngo Molnar 			    && (denormal_operand() < 0))
1174da957e11SThomas Gleixner 				return;
1175da957e11SThomas Gleixner 
1176da957e11SThomas Gleixner 			changesign(st1_ptr);
1177da957e11SThomas Gleixner 		}
11783d0d14f9SIngo Molnar 	} else {
1179da957e11SThomas Gleixner 		/* st(0) must be zero or negative */
11803d0d14f9SIngo Molnar 		if (st0_tag == TAG_Zero) {
1181da957e11SThomas Gleixner 			/* This should be invalid, but a real 80486 is happy with it. */
1182da957e11SThomas Gleixner 
1183da957e11SThomas Gleixner #ifndef PECULIAR_486
1184da957e11SThomas Gleixner 			sign = getsign(st1_ptr);
1185da957e11SThomas Gleixner 			if (FPU_divide_by_zero(1, sign) < 0)
1186da957e11SThomas Gleixner 				return;
1187da957e11SThomas Gleixner #endif /* PECULIAR_486 */
1188da957e11SThomas Gleixner 
1189da957e11SThomas Gleixner 			changesign(st1_ptr);
11903d0d14f9SIngo Molnar 		} else if (arith_invalid(1) < 0)	/* log(negative) */
1191da957e11SThomas Gleixner 			return;
1192da957e11SThomas Gleixner 	}
1193da957e11SThomas Gleixner 
1194da957e11SThomas Gleixner 	FPU_pop();
1195da957e11SThomas Gleixner }
1196da957e11SThomas Gleixner 
fpatan(FPU_REG * st0_ptr,u_char st0_tag)1197da957e11SThomas Gleixner static void fpatan(FPU_REG *st0_ptr, u_char st0_tag)
1198da957e11SThomas Gleixner {
1199da957e11SThomas Gleixner 	FPU_REG *st1_ptr = &st(1);
1200da957e11SThomas Gleixner 	u_char st1_tag = FPU_gettagi(1);
1201da957e11SThomas Gleixner 	int tag;
1202da957e11SThomas Gleixner 
1203da957e11SThomas Gleixner 	clear_C1();
12043d0d14f9SIngo Molnar 	if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1205da957e11SThomas Gleixner 	      valid_atan:
1206da957e11SThomas Gleixner 
1207da957e11SThomas Gleixner 		poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag);
1208da957e11SThomas Gleixner 
1209da957e11SThomas Gleixner 		FPU_pop();
1210da957e11SThomas Gleixner 
1211da957e11SThomas Gleixner 		return;
1212da957e11SThomas Gleixner 	}
1213da957e11SThomas Gleixner 
1214da957e11SThomas Gleixner 	if (st0_tag == TAG_Special)
1215da957e11SThomas Gleixner 		st0_tag = FPU_Special(st0_ptr);
1216da957e11SThomas Gleixner 	if (st1_tag == TAG_Special)
1217da957e11SThomas Gleixner 		st1_tag = FPU_Special(st1_ptr);
1218da957e11SThomas Gleixner 
1219da957e11SThomas Gleixner 	if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
1220da957e11SThomas Gleixner 	    || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
12213d0d14f9SIngo Molnar 	    || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
1222da957e11SThomas Gleixner 		if (denormal_operand() < 0)
1223da957e11SThomas Gleixner 			return;
1224da957e11SThomas Gleixner 
1225da957e11SThomas Gleixner 		goto valid_atan;
12263d0d14f9SIngo Molnar 	} else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
1227da957e11SThomas Gleixner 		FPU_stack_underflow_pop(1);
1228da957e11SThomas Gleixner 		return;
12293d0d14f9SIngo Molnar 	} else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
1230da957e11SThomas Gleixner 		if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0)
1231da957e11SThomas Gleixner 			FPU_pop();
1232da957e11SThomas Gleixner 		return;
12333d0d14f9SIngo Molnar 	} else if ((st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) {
1234da957e11SThomas Gleixner 		u_char sign = getsign(st1_ptr);
12353d0d14f9SIngo Molnar 		if (st0_tag == TW_Infinity) {
12363d0d14f9SIngo Molnar 			if (st1_tag == TW_Infinity) {
12373d0d14f9SIngo Molnar 				if (signpositive(st0_ptr)) {
1238da957e11SThomas Gleixner 					FPU_copy_to_reg1(&CONST_PI4, TAG_Valid);
12393d0d14f9SIngo Molnar 				} else {
1240da957e11SThomas Gleixner 					setpositive(st1_ptr);
12413d0d14f9SIngo Molnar 					tag =
12423d0d14f9SIngo Molnar 					    FPU_u_add(&CONST_PI4, &CONST_PI2,
12433d0d14f9SIngo Molnar 						      st1_ptr, FULL_PRECISION,
12443d0d14f9SIngo Molnar 						      SIGN_POS,
12453d0d14f9SIngo Molnar 						      exponent(&CONST_PI4),
12463d0d14f9SIngo Molnar 						      exponent(&CONST_PI2));
1247da957e11SThomas Gleixner 					if (tag >= 0)
1248da957e11SThomas Gleixner 						FPU_settagi(1, tag);
1249da957e11SThomas Gleixner 				}
12503d0d14f9SIngo Molnar 			} else {
12513d0d14f9SIngo Molnar 				if ((st1_tag == TW_Denormal)
12523d0d14f9SIngo Molnar 				    && (denormal_operand() < 0))
1253da957e11SThomas Gleixner 					return;
1254da957e11SThomas Gleixner 
12553d0d14f9SIngo Molnar 				if (signpositive(st0_ptr)) {
1256da957e11SThomas Gleixner 					FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1257da957e11SThomas Gleixner 					setsign(st1_ptr, sign);	/* An 80486 preserves the sign */
1258da957e11SThomas Gleixner 					FPU_pop();
1259da957e11SThomas Gleixner 					return;
12603d0d14f9SIngo Molnar 				} else {
1261da957e11SThomas Gleixner 					FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
1262da957e11SThomas Gleixner 				}
1263da957e11SThomas Gleixner 			}
12643d0d14f9SIngo Molnar 		} else {
1265da957e11SThomas Gleixner 			/* st(1) is infinity, st(0) not infinity */
12663d0d14f9SIngo Molnar 			if ((st0_tag == TW_Denormal)
12673d0d14f9SIngo Molnar 			    && (denormal_operand() < 0))
1268da957e11SThomas Gleixner 				return;
1269da957e11SThomas Gleixner 
1270da957e11SThomas Gleixner 			FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
1271da957e11SThomas Gleixner 		}
1272da957e11SThomas Gleixner 		setsign(st1_ptr, sign);
12733d0d14f9SIngo Molnar 	} else if (st1_tag == TAG_Zero) {
1274da957e11SThomas Gleixner 		/* st(0) must be valid or zero */
1275da957e11SThomas Gleixner 		u_char sign = getsign(st1_ptr);
1276da957e11SThomas Gleixner 
1277da957e11SThomas Gleixner 		if ((st0_tag == TW_Denormal) && (denormal_operand() < 0))
1278da957e11SThomas Gleixner 			return;
1279da957e11SThomas Gleixner 
12803d0d14f9SIngo Molnar 		if (signpositive(st0_ptr)) {
1281da957e11SThomas Gleixner 			/* An 80486 preserves the sign */
1282da957e11SThomas Gleixner 			FPU_pop();
1283da957e11SThomas Gleixner 			return;
1284da957e11SThomas Gleixner 		}
1285da957e11SThomas Gleixner 
1286da957e11SThomas Gleixner 		FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
1287da957e11SThomas Gleixner 		setsign(st1_ptr, sign);
12883d0d14f9SIngo Molnar 	} else if (st0_tag == TAG_Zero) {
1289da957e11SThomas Gleixner 		/* st(1) must be TAG_Valid here */
1290da957e11SThomas Gleixner 		u_char sign = getsign(st1_ptr);
1291da957e11SThomas Gleixner 
1292da957e11SThomas Gleixner 		if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
1293da957e11SThomas Gleixner 			return;
1294da957e11SThomas Gleixner 
1295da957e11SThomas Gleixner 		FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
1296da957e11SThomas Gleixner 		setsign(st1_ptr, sign);
1297da957e11SThomas Gleixner 	}
1298da957e11SThomas Gleixner #ifdef PARANOID
1299da957e11SThomas Gleixner 	else
1300da957e11SThomas Gleixner 		EXCEPTION(EX_INTERNAL | 0x125);
1301da957e11SThomas Gleixner #endif /* PARANOID */
1302da957e11SThomas Gleixner 
1303da957e11SThomas Gleixner 	FPU_pop();
1304da957e11SThomas Gleixner 	set_precision_flag_up();	/* We do not really know if up or down */
1305da957e11SThomas Gleixner }
1306da957e11SThomas Gleixner 
fprem(FPU_REG * st0_ptr,u_char st0_tag)1307da957e11SThomas Gleixner static void fprem(FPU_REG *st0_ptr, u_char st0_tag)
1308da957e11SThomas Gleixner {
1309da957e11SThomas Gleixner 	do_fprem(st0_ptr, st0_tag, RC_CHOP);
1310da957e11SThomas Gleixner }
1311da957e11SThomas Gleixner 
fprem1(FPU_REG * st0_ptr,u_char st0_tag)1312da957e11SThomas Gleixner static void fprem1(FPU_REG *st0_ptr, u_char st0_tag)
1313da957e11SThomas Gleixner {
1314da957e11SThomas Gleixner 	do_fprem(st0_ptr, st0_tag, RC_RND);
1315da957e11SThomas Gleixner }
1316da957e11SThomas Gleixner 
fyl2xp1(FPU_REG * st0_ptr,u_char st0_tag)1317da957e11SThomas Gleixner static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag)
1318da957e11SThomas Gleixner {
1319da957e11SThomas Gleixner 	u_char sign, sign1;
1320da957e11SThomas Gleixner 	FPU_REG *st1_ptr = &st(1), a, b;
1321da957e11SThomas Gleixner 	u_char st1_tag = FPU_gettagi(1);
1322da957e11SThomas Gleixner 
1323da957e11SThomas Gleixner 	clear_C1();
13243d0d14f9SIngo Molnar 	if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1325da957e11SThomas Gleixner 	      valid_yl2xp1:
1326da957e11SThomas Gleixner 
1327da957e11SThomas Gleixner 		sign = getsign(st0_ptr);
1328da957e11SThomas Gleixner 		sign1 = getsign(st1_ptr);
1329da957e11SThomas Gleixner 
1330da957e11SThomas Gleixner 		FPU_to_exp16(st0_ptr, &a);
1331da957e11SThomas Gleixner 		FPU_to_exp16(st1_ptr, &b);
1332da957e11SThomas Gleixner 
1333da957e11SThomas Gleixner 		if (poly_l2p1(sign, sign1, &a, &b, st1_ptr))
1334da957e11SThomas Gleixner 			return;
1335da957e11SThomas Gleixner 
1336da957e11SThomas Gleixner 		FPU_pop();
1337da957e11SThomas Gleixner 		return;
1338da957e11SThomas Gleixner 	}
1339da957e11SThomas Gleixner 
1340da957e11SThomas Gleixner 	if (st0_tag == TAG_Special)
1341da957e11SThomas Gleixner 		st0_tag = FPU_Special(st0_ptr);
1342da957e11SThomas Gleixner 	if (st1_tag == TAG_Special)
1343da957e11SThomas Gleixner 		st1_tag = FPU_Special(st1_ptr);
1344da957e11SThomas Gleixner 
1345da957e11SThomas Gleixner 	if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
1346da957e11SThomas Gleixner 	    || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
13473d0d14f9SIngo Molnar 	    || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
1348da957e11SThomas Gleixner 		if (denormal_operand() < 0)
1349da957e11SThomas Gleixner 			return;
1350da957e11SThomas Gleixner 
1351da957e11SThomas Gleixner 		goto valid_yl2xp1;
13523d0d14f9SIngo Molnar 	} else if ((st0_tag == TAG_Empty) | (st1_tag == TAG_Empty)) {
1353da957e11SThomas Gleixner 		FPU_stack_underflow_pop(1);
1354da957e11SThomas Gleixner 		return;
13553d0d14f9SIngo Molnar 	} else if (st0_tag == TAG_Zero) {
13563d0d14f9SIngo Molnar 		switch (st1_tag) {
1357da957e11SThomas Gleixner 		case TW_Denormal:
1358da957e11SThomas Gleixner 			if (denormal_operand() < 0)
1359da957e11SThomas Gleixner 				return;
1360df561f66SGustavo A. R. Silva 			fallthrough;
1361da957e11SThomas Gleixner 		case TAG_Zero:
1362da957e11SThomas Gleixner 		case TAG_Valid:
1363da957e11SThomas Gleixner 			setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
1364da957e11SThomas Gleixner 			FPU_copy_to_reg1(st0_ptr, st0_tag);
1365da957e11SThomas Gleixner 			break;
1366da957e11SThomas Gleixner 
1367da957e11SThomas Gleixner 		case TW_Infinity:
1368da957e11SThomas Gleixner 			/* Infinity*log(1) */
1369da957e11SThomas Gleixner 			if (arith_invalid(1) < 0)
1370da957e11SThomas Gleixner 				return;
1371da957e11SThomas Gleixner 			break;
1372da957e11SThomas Gleixner 
1373da957e11SThomas Gleixner 		case TW_NaN:
1374da957e11SThomas Gleixner 			if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1375da957e11SThomas Gleixner 				return;
1376da957e11SThomas Gleixner 			break;
1377da957e11SThomas Gleixner 
1378da957e11SThomas Gleixner 		default:
1379da957e11SThomas Gleixner #ifdef PARANOID
1380da957e11SThomas Gleixner 			EXCEPTION(EX_INTERNAL | 0x116);
1381da957e11SThomas Gleixner 			return;
1382da957e11SThomas Gleixner #endif /* PARANOID */
1383da957e11SThomas Gleixner 			break;
1384da957e11SThomas Gleixner 		}
13853d0d14f9SIngo Molnar 	} else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
13863d0d14f9SIngo Molnar 		switch (st1_tag) {
1387da957e11SThomas Gleixner 		case TAG_Zero:
13883d0d14f9SIngo Molnar 			if (signnegative(st0_ptr)) {
13893d0d14f9SIngo Molnar 				if (exponent(st0_ptr) >= 0) {
1390da957e11SThomas Gleixner 					/* st(0) holds <= -1.0 */
1391da957e11SThomas Gleixner #ifdef PECULIAR_486		/* Stupid 80486 doesn't worry about log(negative). */
1392da957e11SThomas Gleixner 					changesign(st1_ptr);
1393da957e11SThomas Gleixner #else
1394da957e11SThomas Gleixner 					if (arith_invalid(1) < 0)
1395da957e11SThomas Gleixner 						return;
1396da957e11SThomas Gleixner #endif /* PECULIAR_486 */
13973d0d14f9SIngo Molnar 				} else if ((st0_tag == TW_Denormal)
13983d0d14f9SIngo Molnar 					   && (denormal_operand() < 0))
1399da957e11SThomas Gleixner 					return;
1400da957e11SThomas Gleixner 				else
1401da957e11SThomas Gleixner 					changesign(st1_ptr);
14023d0d14f9SIngo Molnar 			} else if ((st0_tag == TW_Denormal)
14033d0d14f9SIngo Molnar 				   && (denormal_operand() < 0))
1404da957e11SThomas Gleixner 				return;
1405da957e11SThomas Gleixner 			break;
1406da957e11SThomas Gleixner 
1407da957e11SThomas Gleixner 		case TW_Infinity:
14083d0d14f9SIngo Molnar 			if (signnegative(st0_ptr)) {
1409da957e11SThomas Gleixner 				if ((exponent(st0_ptr) >= 0) &&
1410da957e11SThomas Gleixner 				    !((st0_ptr->sigh == 0x80000000) &&
14113d0d14f9SIngo Molnar 				      (st0_ptr->sigl == 0))) {
1412da957e11SThomas Gleixner 					/* st(0) holds < -1.0 */
1413da957e11SThomas Gleixner #ifdef PECULIAR_486		/* Stupid 80486 doesn't worry about log(negative). */
1414da957e11SThomas Gleixner 					changesign(st1_ptr);
1415da957e11SThomas Gleixner #else
14163d0d14f9SIngo Molnar 					if (arith_invalid(1) < 0)
14173d0d14f9SIngo Molnar 						return;
1418da957e11SThomas Gleixner #endif /* PECULIAR_486 */
14193d0d14f9SIngo Molnar 				} else if ((st0_tag == TW_Denormal)
14203d0d14f9SIngo Molnar 					   && (denormal_operand() < 0))
1421da957e11SThomas Gleixner 					return;
1422da957e11SThomas Gleixner 				else
1423da957e11SThomas Gleixner 					changesign(st1_ptr);
14243d0d14f9SIngo Molnar 			} else if ((st0_tag == TW_Denormal)
14253d0d14f9SIngo Molnar 				   && (denormal_operand() < 0))
1426da957e11SThomas Gleixner 				return;
1427da957e11SThomas Gleixner 			break;
1428da957e11SThomas Gleixner 
1429da957e11SThomas Gleixner 		case TW_NaN:
1430da957e11SThomas Gleixner 			if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1431da957e11SThomas Gleixner 				return;
1432da957e11SThomas Gleixner 		}
1433da957e11SThomas Gleixner 
14343d0d14f9SIngo Molnar 	} else if (st0_tag == TW_NaN) {
1435da957e11SThomas Gleixner 		if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1436da957e11SThomas Gleixner 			return;
14373d0d14f9SIngo Molnar 	} else if (st0_tag == TW_Infinity) {
14383d0d14f9SIngo Molnar 		if (st1_tag == TW_NaN) {
1439da957e11SThomas Gleixner 			if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1440da957e11SThomas Gleixner 				return;
14413d0d14f9SIngo Molnar 		} else if (signnegative(st0_ptr)) {
1442da957e11SThomas Gleixner #ifndef PECULIAR_486
1443da957e11SThomas Gleixner 			/* This should have higher priority than denormals, but... */
1444da957e11SThomas Gleixner 			if (arith_invalid(1) < 0)	/* log(-infinity) */
1445da957e11SThomas Gleixner 				return;
1446da957e11SThomas Gleixner #endif /* PECULIAR_486 */
14473d0d14f9SIngo Molnar 			if ((st1_tag == TW_Denormal)
14483d0d14f9SIngo Molnar 			    && (denormal_operand() < 0))
1449da957e11SThomas Gleixner 				return;
1450da957e11SThomas Gleixner #ifdef PECULIAR_486
1451da957e11SThomas Gleixner 			/* Denormal operands actually get higher priority */
1452da957e11SThomas Gleixner 			if (arith_invalid(1) < 0)	/* log(-infinity) */
1453da957e11SThomas Gleixner 				return;
1454da957e11SThomas Gleixner #endif /* PECULIAR_486 */
14553d0d14f9SIngo Molnar 		} else if (st1_tag == TAG_Zero) {
1456da957e11SThomas Gleixner 			/* log(infinity) */
1457da957e11SThomas Gleixner 			if (arith_invalid(1) < 0)
1458da957e11SThomas Gleixner 				return;
1459da957e11SThomas Gleixner 		}
1460da957e11SThomas Gleixner 
1461da957e11SThomas Gleixner 		/* st(1) must be valid here. */
1462da957e11SThomas Gleixner 
1463da957e11SThomas Gleixner 		else if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
1464da957e11SThomas Gleixner 			return;
1465da957e11SThomas Gleixner 
1466da957e11SThomas Gleixner 		/* The Manual says that log(Infinity) is invalid, but a real
1467da957e11SThomas Gleixner 		   80486 sensibly says that it is o.k. */
14683d0d14f9SIngo Molnar 		else {
1469da957e11SThomas Gleixner 			u_char sign = getsign(st1_ptr);
1470da957e11SThomas Gleixner 			FPU_copy_to_reg1(&CONST_INF, TAG_Special);
1471da957e11SThomas Gleixner 			setsign(st1_ptr, sign);
1472da957e11SThomas Gleixner 		}
1473da957e11SThomas Gleixner 	}
1474da957e11SThomas Gleixner #ifdef PARANOID
14753d0d14f9SIngo Molnar 	else {
1476da957e11SThomas Gleixner 		EXCEPTION(EX_INTERNAL | 0x117);
1477da957e11SThomas Gleixner 		return;
1478da957e11SThomas Gleixner 	}
1479da957e11SThomas Gleixner #endif /* PARANOID */
1480da957e11SThomas Gleixner 
1481da957e11SThomas Gleixner 	FPU_pop();
1482da957e11SThomas Gleixner 	return;
1483da957e11SThomas Gleixner 
1484da957e11SThomas Gleixner }
1485da957e11SThomas Gleixner 
fscale(FPU_REG * st0_ptr,u_char st0_tag)1486da957e11SThomas Gleixner static void fscale(FPU_REG *st0_ptr, u_char st0_tag)
1487da957e11SThomas Gleixner {
1488da957e11SThomas Gleixner 	FPU_REG *st1_ptr = &st(1);
1489da957e11SThomas Gleixner 	u_char st1_tag = FPU_gettagi(1);
1490da957e11SThomas Gleixner 	int old_cw = control_word;
1491da957e11SThomas Gleixner 	u_char sign = getsign(st0_ptr);
1492da957e11SThomas Gleixner 
1493da957e11SThomas Gleixner 	clear_C1();
14943d0d14f9SIngo Molnar 	if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1495da957e11SThomas Gleixner 		long scale;
1496da957e11SThomas Gleixner 		FPU_REG tmp;
1497da957e11SThomas Gleixner 
1498da957e11SThomas Gleixner 		/* Convert register for internal use. */
1499da957e11SThomas Gleixner 		setexponent16(st0_ptr, exponent(st0_ptr));
1500da957e11SThomas Gleixner 
1501da957e11SThomas Gleixner 	      valid_scale:
1502da957e11SThomas Gleixner 
15033d0d14f9SIngo Molnar 		if (exponent(st1_ptr) > 30) {
1504da957e11SThomas Gleixner 			/* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
1505da957e11SThomas Gleixner 
15063d0d14f9SIngo Molnar 			if (signpositive(st1_ptr)) {
1507da957e11SThomas Gleixner 				EXCEPTION(EX_Overflow);
1508da957e11SThomas Gleixner 				FPU_copy_to_reg0(&CONST_INF, TAG_Special);
15093d0d14f9SIngo Molnar 			} else {
1510da957e11SThomas Gleixner 				EXCEPTION(EX_Underflow);
1511da957e11SThomas Gleixner 				FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1512da957e11SThomas Gleixner 			}
1513da957e11SThomas Gleixner 			setsign(st0_ptr, sign);
1514da957e11SThomas Gleixner 			return;
1515da957e11SThomas Gleixner 		}
1516da957e11SThomas Gleixner 
1517da957e11SThomas Gleixner 		control_word &= ~CW_RC;
1518da957e11SThomas Gleixner 		control_word |= RC_CHOP;
1519da957e11SThomas Gleixner 		reg_copy(st1_ptr, &tmp);
1520da957e11SThomas Gleixner 		FPU_round_to_int(&tmp, st1_tag);	/* This can never overflow here */
1521da957e11SThomas Gleixner 		control_word = old_cw;
1522da957e11SThomas Gleixner 		scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl;
1523da957e11SThomas Gleixner 		scale += exponent16(st0_ptr);
1524da957e11SThomas Gleixner 
1525da957e11SThomas Gleixner 		setexponent16(st0_ptr, scale);
1526da957e11SThomas Gleixner 
1527da957e11SThomas Gleixner 		/* Use FPU_round() to properly detect under/overflow etc */
1528da957e11SThomas Gleixner 		FPU_round(st0_ptr, 0, 0, control_word, sign);
1529da957e11SThomas Gleixner 
1530da957e11SThomas Gleixner 		return;
1531da957e11SThomas Gleixner 	}
1532da957e11SThomas Gleixner 
1533da957e11SThomas Gleixner 	if (st0_tag == TAG_Special)
1534da957e11SThomas Gleixner 		st0_tag = FPU_Special(st0_ptr);
1535da957e11SThomas Gleixner 	if (st1_tag == TAG_Special)
1536da957e11SThomas Gleixner 		st1_tag = FPU_Special(st1_ptr);
1537da957e11SThomas Gleixner 
15383d0d14f9SIngo Molnar 	if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
15393d0d14f9SIngo Molnar 		switch (st1_tag) {
1540da957e11SThomas Gleixner 		case TAG_Valid:
1541da957e11SThomas Gleixner 			/* st(0) must be a denormal */
15423d0d14f9SIngo Molnar 			if ((st0_tag == TW_Denormal)
15433d0d14f9SIngo Molnar 			    && (denormal_operand() < 0))
1544da957e11SThomas Gleixner 				return;
1545da957e11SThomas Gleixner 
1546da957e11SThomas Gleixner 			FPU_to_exp16(st0_ptr, st0_ptr);	/* Will not be left on stack */
1547da957e11SThomas Gleixner 			goto valid_scale;
1548da957e11SThomas Gleixner 
1549da957e11SThomas Gleixner 		case TAG_Zero:
1550da957e11SThomas Gleixner 			if (st0_tag == TW_Denormal)
1551da957e11SThomas Gleixner 				denormal_operand();
1552da957e11SThomas Gleixner 			return;
1553da957e11SThomas Gleixner 
1554da957e11SThomas Gleixner 		case TW_Denormal:
1555da957e11SThomas Gleixner 			denormal_operand();
1556da957e11SThomas Gleixner 			return;
1557da957e11SThomas Gleixner 
1558da957e11SThomas Gleixner 		case TW_Infinity:
15593d0d14f9SIngo Molnar 			if ((st0_tag == TW_Denormal)
15603d0d14f9SIngo Molnar 			    && (denormal_operand() < 0))
1561da957e11SThomas Gleixner 				return;
1562da957e11SThomas Gleixner 
1563da957e11SThomas Gleixner 			if (signpositive(st1_ptr))
1564da957e11SThomas Gleixner 				FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1565da957e11SThomas Gleixner 			else
1566da957e11SThomas Gleixner 				FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1567da957e11SThomas Gleixner 			setsign(st0_ptr, sign);
1568da957e11SThomas Gleixner 			return;
1569da957e11SThomas Gleixner 
1570da957e11SThomas Gleixner 		case TW_NaN:
1571da957e11SThomas Gleixner 			real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1572da957e11SThomas Gleixner 			return;
1573da957e11SThomas Gleixner 		}
15743d0d14f9SIngo Molnar 	} else if (st0_tag == TAG_Zero) {
15753d0d14f9SIngo Molnar 		switch (st1_tag) {
1576da957e11SThomas Gleixner 		case TAG_Valid:
1577da957e11SThomas Gleixner 		case TAG_Zero:
1578da957e11SThomas Gleixner 			return;
1579da957e11SThomas Gleixner 
1580da957e11SThomas Gleixner 		case TW_Denormal:
1581da957e11SThomas Gleixner 			denormal_operand();
1582da957e11SThomas Gleixner 			return;
1583da957e11SThomas Gleixner 
1584da957e11SThomas Gleixner 		case TW_Infinity:
1585da957e11SThomas Gleixner 			if (signpositive(st1_ptr))
1586da957e11SThomas Gleixner 				arith_invalid(0);	/* Zero scaled by +Infinity */
1587da957e11SThomas Gleixner 			return;
1588da957e11SThomas Gleixner 
1589da957e11SThomas Gleixner 		case TW_NaN:
1590da957e11SThomas Gleixner 			real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1591da957e11SThomas Gleixner 			return;
1592da957e11SThomas Gleixner 		}
15933d0d14f9SIngo Molnar 	} else if (st0_tag == TW_Infinity) {
15943d0d14f9SIngo Molnar 		switch (st1_tag) {
1595da957e11SThomas Gleixner 		case TAG_Valid:
1596da957e11SThomas Gleixner 		case TAG_Zero:
1597da957e11SThomas Gleixner 			return;
1598da957e11SThomas Gleixner 
1599da957e11SThomas Gleixner 		case TW_Denormal:
1600da957e11SThomas Gleixner 			denormal_operand();
1601da957e11SThomas Gleixner 			return;
1602da957e11SThomas Gleixner 
1603da957e11SThomas Gleixner 		case TW_Infinity:
1604da957e11SThomas Gleixner 			if (signnegative(st1_ptr))
1605da957e11SThomas Gleixner 				arith_invalid(0);	/* Infinity scaled by -Infinity */
1606da957e11SThomas Gleixner 			return;
1607da957e11SThomas Gleixner 
1608da957e11SThomas Gleixner 		case TW_NaN:
1609da957e11SThomas Gleixner 			real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1610da957e11SThomas Gleixner 			return;
1611da957e11SThomas Gleixner 		}
16123d0d14f9SIngo Molnar 	} else if (st0_tag == TW_NaN) {
16133d0d14f9SIngo Molnar 		if (st1_tag != TAG_Empty) {
16143d0d14f9SIngo Molnar 			real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
16153d0d14f9SIngo Molnar 			return;
1616da957e11SThomas Gleixner 		}
1617da957e11SThomas Gleixner 	}
1618da957e11SThomas Gleixner #ifdef PARANOID
16193d0d14f9SIngo Molnar 	if (!((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty))) {
1620da957e11SThomas Gleixner 		EXCEPTION(EX_INTERNAL | 0x115);
1621da957e11SThomas Gleixner 		return;
1622da957e11SThomas Gleixner 	}
1623da957e11SThomas Gleixner #endif
1624da957e11SThomas Gleixner 
1625da957e11SThomas Gleixner 	/* At least one of st(0), st(1) must be empty */
1626da957e11SThomas Gleixner 	FPU_stack_underflow();
1627da957e11SThomas Gleixner 
1628da957e11SThomas Gleixner }
1629da957e11SThomas Gleixner 
1630da957e11SThomas Gleixner /*---------------------------------------------------------------------------*/
1631da957e11SThomas Gleixner 
1632da957e11SThomas Gleixner static FUNC_ST0 const trig_table_a[] = {
1633da957e11SThomas Gleixner 	f2xm1, fyl2x, fptan, fpatan,
1634*e0ca9353SArnd Bergmann 	fxtract, fprem1, fdecstp, fincstp,
1635da957e11SThomas Gleixner };
1636da957e11SThomas Gleixner 
FPU_triga(void)1637da957e11SThomas Gleixner void FPU_triga(void)
1638da957e11SThomas Gleixner {
1639da957e11SThomas Gleixner 	(trig_table_a[FPU_rm]) (&st(0), FPU_gettag0());
1640da957e11SThomas Gleixner }
1641da957e11SThomas Gleixner 
16423d0d14f9SIngo Molnar static FUNC_ST0 const trig_table_b[] = {
1643279d56abSArnd Bergmann 	fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos
1644da957e11SThomas Gleixner };
1645da957e11SThomas Gleixner 
FPU_trigb(void)1646da957e11SThomas Gleixner void FPU_trigb(void)
1647da957e11SThomas Gleixner {
1648da957e11SThomas Gleixner 	(trig_table_b[FPU_rm]) (&st(0), FPU_gettag0());
1649da957e11SThomas Gleixner }
1650