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