1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2da957e11SThomas Gleixner /*---------------------------------------------------------------------------+
3da957e11SThomas Gleixner | poly_l2.c |
4da957e11SThomas Gleixner | |
5da957e11SThomas Gleixner | Compute the base 2 log of a FPU_REG, using a polynomial approximation. |
6da957e11SThomas Gleixner | |
7da957e11SThomas Gleixner | Copyright (C) 1992,1993,1994,1997 |
8da957e11SThomas Gleixner | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
9da957e11SThomas Gleixner | E-mail billm@suburbia.net |
10da957e11SThomas Gleixner | |
11da957e11SThomas Gleixner | |
12da957e11SThomas Gleixner +---------------------------------------------------------------------------*/
13da957e11SThomas Gleixner
14da957e11SThomas Gleixner #include "exception.h"
15da957e11SThomas Gleixner #include "reg_constant.h"
16da957e11SThomas Gleixner #include "fpu_emu.h"
17da957e11SThomas Gleixner #include "fpu_system.h"
18da957e11SThomas Gleixner #include "control_w.h"
19da957e11SThomas Gleixner #include "poly.h"
20da957e11SThomas Gleixner
21da957e11SThomas Gleixner static void log2_kernel(FPU_REG const *arg, u_char argsign,
22da957e11SThomas Gleixner Xsig * accum_result, long int *expon);
23da957e11SThomas Gleixner
24da957e11SThomas Gleixner /*--- poly_l2() -------------------------------------------------------------+
25da957e11SThomas Gleixner | Base 2 logarithm by a polynomial approximation. |
26da957e11SThomas Gleixner +---------------------------------------------------------------------------*/
poly_l2(FPU_REG * st0_ptr,FPU_REG * st1_ptr,u_char st1_sign)27da957e11SThomas Gleixner void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign)
28da957e11SThomas Gleixner {
29da957e11SThomas Gleixner long int exponent, expon, expon_expon;
30da957e11SThomas Gleixner Xsig accumulator, expon_accum, yaccum;
31da957e11SThomas Gleixner u_char sign, argsign;
32da957e11SThomas Gleixner FPU_REG x;
33da957e11SThomas Gleixner int tag;
34da957e11SThomas Gleixner
35da957e11SThomas Gleixner exponent = exponent16(st0_ptr);
36da957e11SThomas Gleixner
37da957e11SThomas Gleixner /* From st0_ptr, make a number > sqrt(2)/2 and < sqrt(2) */
383d0d14f9SIngo Molnar if (st0_ptr->sigh > (unsigned)0xb504f334) {
39da957e11SThomas Gleixner /* Treat as sqrt(2)/2 < st0_ptr < 1 */
40da957e11SThomas Gleixner significand(&x) = -significand(st0_ptr);
41da957e11SThomas Gleixner setexponent16(&x, -1);
42da957e11SThomas Gleixner exponent++;
43da957e11SThomas Gleixner argsign = SIGN_NEG;
443d0d14f9SIngo Molnar } else {
45da957e11SThomas Gleixner /* Treat as 1 <= st0_ptr < sqrt(2) */
46da957e11SThomas Gleixner x.sigh = st0_ptr->sigh - 0x80000000;
47da957e11SThomas Gleixner x.sigl = st0_ptr->sigl;
48da957e11SThomas Gleixner setexponent16(&x, 0);
49da957e11SThomas Gleixner argsign = SIGN_POS;
50da957e11SThomas Gleixner }
51da957e11SThomas Gleixner tag = FPU_normalize_nuo(&x);
52da957e11SThomas Gleixner
533d0d14f9SIngo Molnar if (tag == TAG_Zero) {
54da957e11SThomas Gleixner expon = 0;
55da957e11SThomas Gleixner accumulator.msw = accumulator.midw = accumulator.lsw = 0;
563d0d14f9SIngo Molnar } else {
57da957e11SThomas Gleixner log2_kernel(&x, argsign, &accumulator, &expon);
58da957e11SThomas Gleixner }
59da957e11SThomas Gleixner
603d0d14f9SIngo Molnar if (exponent < 0) {
61da957e11SThomas Gleixner sign = SIGN_NEG;
62da957e11SThomas Gleixner exponent = -exponent;
633d0d14f9SIngo Molnar } else
64da957e11SThomas Gleixner sign = SIGN_POS;
653d0d14f9SIngo Molnar expon_accum.msw = exponent;
663d0d14f9SIngo Molnar expon_accum.midw = expon_accum.lsw = 0;
673d0d14f9SIngo Molnar if (exponent) {
68da957e11SThomas Gleixner expon_expon = 31 + norm_Xsig(&expon_accum);
69da957e11SThomas Gleixner shr_Xsig(&accumulator, expon_expon - expon);
70da957e11SThomas Gleixner
71da957e11SThomas Gleixner if (sign ^ argsign)
72da957e11SThomas Gleixner negate_Xsig(&accumulator);
73da957e11SThomas Gleixner add_Xsig_Xsig(&accumulator, &expon_accum);
743d0d14f9SIngo Molnar } else {
75da957e11SThomas Gleixner expon_expon = expon;
76da957e11SThomas Gleixner sign = argsign;
77da957e11SThomas Gleixner }
78da957e11SThomas Gleixner
793d0d14f9SIngo Molnar yaccum.lsw = 0;
803d0d14f9SIngo Molnar XSIG_LL(yaccum) = significand(st1_ptr);
81da957e11SThomas Gleixner mul_Xsig_Xsig(&accumulator, &yaccum);
82da957e11SThomas Gleixner
83da957e11SThomas Gleixner expon_expon += round_Xsig(&accumulator);
84da957e11SThomas Gleixner
853d0d14f9SIngo Molnar if (accumulator.msw == 0) {
86da957e11SThomas Gleixner FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
87da957e11SThomas Gleixner return;
88da957e11SThomas Gleixner }
89da957e11SThomas Gleixner
90da957e11SThomas Gleixner significand(st1_ptr) = XSIG_LL(accumulator);
91da957e11SThomas Gleixner setexponent16(st1_ptr, expon_expon + exponent16(st1_ptr) + 1);
92da957e11SThomas Gleixner
93da957e11SThomas Gleixner tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign ^ st1_sign);
94da957e11SThomas Gleixner FPU_settagi(1, tag);
95da957e11SThomas Gleixner
96da957e11SThomas Gleixner set_precision_flag_up(); /* 80486 appears to always do this */
97da957e11SThomas Gleixner
98da957e11SThomas Gleixner return;
99da957e11SThomas Gleixner
100da957e11SThomas Gleixner }
101da957e11SThomas Gleixner
102da957e11SThomas Gleixner /*--- poly_l2p1() -----------------------------------------------------------+
103da957e11SThomas Gleixner | Base 2 logarithm by a polynomial approximation. |
104da957e11SThomas Gleixner | log2(x+1) |
105da957e11SThomas Gleixner +---------------------------------------------------------------------------*/
poly_l2p1(u_char sign0,u_char sign1,FPU_REG * st0_ptr,FPU_REG * st1_ptr,FPU_REG * dest)106da957e11SThomas Gleixner int poly_l2p1(u_char sign0, u_char sign1,
107da957e11SThomas Gleixner FPU_REG * st0_ptr, FPU_REG * st1_ptr, FPU_REG * dest)
108da957e11SThomas Gleixner {
109da957e11SThomas Gleixner u_char tag;
110da957e11SThomas Gleixner long int exponent;
111da957e11SThomas Gleixner Xsig accumulator, yaccum;
112da957e11SThomas Gleixner
1133d0d14f9SIngo Molnar if (exponent16(st0_ptr) < 0) {
114da957e11SThomas Gleixner log2_kernel(st0_ptr, sign0, &accumulator, &exponent);
115da957e11SThomas Gleixner
116da957e11SThomas Gleixner yaccum.lsw = 0;
117da957e11SThomas Gleixner XSIG_LL(yaccum) = significand(st1_ptr);
118da957e11SThomas Gleixner mul_Xsig_Xsig(&accumulator, &yaccum);
119da957e11SThomas Gleixner
120da957e11SThomas Gleixner exponent += round_Xsig(&accumulator);
121da957e11SThomas Gleixner
122da957e11SThomas Gleixner exponent += exponent16(st1_ptr) + 1;
1233d0d14f9SIngo Molnar if (exponent < EXP_WAY_UNDER)
1243d0d14f9SIngo Molnar exponent = EXP_WAY_UNDER;
125da957e11SThomas Gleixner
126da957e11SThomas Gleixner significand(dest) = XSIG_LL(accumulator);
127da957e11SThomas Gleixner setexponent16(dest, exponent);
128da957e11SThomas Gleixner
129da957e11SThomas Gleixner tag = FPU_round(dest, 1, 0, FULL_PRECISION, sign0 ^ sign1);
130da957e11SThomas Gleixner FPU_settagi(1, tag);
131da957e11SThomas Gleixner
132da957e11SThomas Gleixner if (tag == TAG_Valid)
133da957e11SThomas Gleixner set_precision_flag_up(); /* 80486 appears to always do this */
1343d0d14f9SIngo Molnar } else {
135da957e11SThomas Gleixner /* The magnitude of st0_ptr is far too large. */
136da957e11SThomas Gleixner
1373d0d14f9SIngo Molnar if (sign0 != SIGN_POS) {
138da957e11SThomas Gleixner /* Trying to get the log of a negative number. */
139da957e11SThomas Gleixner #ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
140da957e11SThomas Gleixner changesign(st1_ptr);
141da957e11SThomas Gleixner #else
142da957e11SThomas Gleixner if (arith_invalid(1) < 0)
143da957e11SThomas Gleixner return 1;
144da957e11SThomas Gleixner #endif /* PECULIAR_486 */
145da957e11SThomas Gleixner }
146da957e11SThomas Gleixner
147da957e11SThomas Gleixner /* 80486 appears to do this */
148da957e11SThomas Gleixner if (sign0 == SIGN_NEG)
149da957e11SThomas Gleixner set_precision_flag_down();
150da957e11SThomas Gleixner else
151da957e11SThomas Gleixner set_precision_flag_up();
152da957e11SThomas Gleixner }
153da957e11SThomas Gleixner
154da957e11SThomas Gleixner if (exponent(dest) <= EXP_UNDER)
155da957e11SThomas Gleixner EXCEPTION(EX_Underflow);
156da957e11SThomas Gleixner
157da957e11SThomas Gleixner return 0;
158da957e11SThomas Gleixner
159da957e11SThomas Gleixner }
160da957e11SThomas Gleixner
161da957e11SThomas Gleixner #undef HIPOWER
162da957e11SThomas Gleixner #define HIPOWER 10
1633d0d14f9SIngo Molnar static const unsigned long long logterms[HIPOWER] = {
164da957e11SThomas Gleixner 0x2a8eca5705fc2ef0LL,
165da957e11SThomas Gleixner 0xf6384ee1d01febceLL,
166da957e11SThomas Gleixner 0x093bb62877cdf642LL,
167da957e11SThomas Gleixner 0x006985d8a9ec439bLL,
168da957e11SThomas Gleixner 0x0005212c4f55a9c8LL,
169da957e11SThomas Gleixner 0x00004326a16927f0LL,
170da957e11SThomas Gleixner 0x0000038d1d80a0e7LL,
171da957e11SThomas Gleixner 0x0000003141cc80c6LL,
172da957e11SThomas Gleixner 0x00000002b1668c9fLL,
173da957e11SThomas Gleixner 0x000000002c7a46aaLL
174da957e11SThomas Gleixner };
175da957e11SThomas Gleixner
176da957e11SThomas Gleixner static const unsigned long leadterm = 0xb8000000;
177da957e11SThomas Gleixner
178da957e11SThomas Gleixner /*--- log2_kernel() ---------------------------------------------------------+
179da957e11SThomas Gleixner | Base 2 logarithm by a polynomial approximation. |
180da957e11SThomas Gleixner | log2(x+1) |
181da957e11SThomas Gleixner +---------------------------------------------------------------------------*/
log2_kernel(FPU_REG const * arg,u_char argsign,Xsig * accum_result,long int * expon)182da957e11SThomas Gleixner static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig *accum_result,
183da957e11SThomas Gleixner long int *expon)
184da957e11SThomas Gleixner {
185da957e11SThomas Gleixner long int exponent, adj;
186da957e11SThomas Gleixner unsigned long long Xsq;
187da957e11SThomas Gleixner Xsig accumulator, Numer, Denom, argSignif, arg_signif;
188da957e11SThomas Gleixner
189da957e11SThomas Gleixner exponent = exponent16(arg);
190da957e11SThomas Gleixner Numer.lsw = Denom.lsw = 0;
191da957e11SThomas Gleixner XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg);
1923d0d14f9SIngo Molnar if (argsign == SIGN_POS) {
193da957e11SThomas Gleixner shr_Xsig(&Denom, 2 - (1 + exponent));
194da957e11SThomas Gleixner Denom.msw |= 0x80000000;
195da957e11SThomas Gleixner div_Xsig(&Numer, &Denom, &argSignif);
1963d0d14f9SIngo Molnar } else {
197da957e11SThomas Gleixner shr_Xsig(&Denom, 1 - (1 + exponent));
198da957e11SThomas Gleixner negate_Xsig(&Denom);
1993d0d14f9SIngo Molnar if (Denom.msw & 0x80000000) {
200da957e11SThomas Gleixner div_Xsig(&Numer, &Denom, &argSignif);
201da957e11SThomas Gleixner exponent++;
2023d0d14f9SIngo Molnar } else {
203da957e11SThomas Gleixner /* Denom must be 1.0 */
2043d0d14f9SIngo Molnar argSignif.lsw = Numer.lsw;
2053d0d14f9SIngo Molnar argSignif.midw = Numer.midw;
206da957e11SThomas Gleixner argSignif.msw = Numer.msw;
207da957e11SThomas Gleixner }
208da957e11SThomas Gleixner }
209da957e11SThomas Gleixner
210da957e11SThomas Gleixner #ifndef PECULIAR_486
211da957e11SThomas Gleixner /* Should check here that |local_arg| is within the valid range */
2123d0d14f9SIngo Molnar if (exponent >= -2) {
2133d0d14f9SIngo Molnar if ((exponent > -2) || (argSignif.msw > (unsigned)0xafb0ccc0)) {
214da957e11SThomas Gleixner /* The argument is too large */
215da957e11SThomas Gleixner }
216da957e11SThomas Gleixner }
217da957e11SThomas Gleixner #endif /* PECULIAR_486 */
218da957e11SThomas Gleixner
2193d0d14f9SIngo Molnar arg_signif.lsw = argSignif.lsw;
2203d0d14f9SIngo Molnar XSIG_LL(arg_signif) = XSIG_LL(argSignif);
221da957e11SThomas Gleixner adj = norm_Xsig(&argSignif);
2223d0d14f9SIngo Molnar accumulator.lsw = argSignif.lsw;
2233d0d14f9SIngo Molnar XSIG_LL(accumulator) = XSIG_LL(argSignif);
224da957e11SThomas Gleixner mul_Xsig_Xsig(&accumulator, &accumulator);
225da957e11SThomas Gleixner shr_Xsig(&accumulator, 2 * (-1 - (1 + exponent + adj)));
226da957e11SThomas Gleixner Xsq = XSIG_LL(accumulator);
227da957e11SThomas Gleixner if (accumulator.lsw & 0x80000000)
228da957e11SThomas Gleixner Xsq++;
229da957e11SThomas Gleixner
230da957e11SThomas Gleixner accumulator.msw = accumulator.midw = accumulator.lsw = 0;
231da957e11SThomas Gleixner /* Do the basic fixed point polynomial evaluation */
232da957e11SThomas Gleixner polynomial_Xsig(&accumulator, &Xsq, logterms, HIPOWER - 1);
233da957e11SThomas Gleixner
234da957e11SThomas Gleixner mul_Xsig_Xsig(&accumulator, &argSignif);
235da957e11SThomas Gleixner shr_Xsig(&accumulator, 6 - adj);
236da957e11SThomas Gleixner
237da957e11SThomas Gleixner mul32_Xsig(&arg_signif, leadterm);
238da957e11SThomas Gleixner add_two_Xsig(&accumulator, &arg_signif, &exponent);
239da957e11SThomas Gleixner
240da957e11SThomas Gleixner *expon = exponent + 1;
241da957e11SThomas Gleixner accum_result->lsw = accumulator.lsw;
242da957e11SThomas Gleixner accum_result->midw = accumulator.midw;
243da957e11SThomas Gleixner accum_result->msw = accumulator.msw;
244da957e11SThomas Gleixner
245da957e11SThomas Gleixner }
246