125c28e83SPiotr Jasiukajtis /*
225c28e83SPiotr Jasiukajtis * CDDL HEADER START
325c28e83SPiotr Jasiukajtis *
425c28e83SPiotr Jasiukajtis * The contents of this file are subject to the terms of the
525c28e83SPiotr Jasiukajtis * Common Development and Distribution License (the "License").
625c28e83SPiotr Jasiukajtis * You may not use this file except in compliance with the License.
725c28e83SPiotr Jasiukajtis *
825c28e83SPiotr Jasiukajtis * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925c28e83SPiotr Jasiukajtis * or http://www.opensolaris.org/os/licensing.
1025c28e83SPiotr Jasiukajtis * See the License for the specific language governing permissions
1125c28e83SPiotr Jasiukajtis * and limitations under the License.
1225c28e83SPiotr Jasiukajtis *
1325c28e83SPiotr Jasiukajtis * When distributing Covered Code, include this CDDL HEADER in each
1425c28e83SPiotr Jasiukajtis * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525c28e83SPiotr Jasiukajtis * If applicable, add the following below this CDDL HEADER, with the
1625c28e83SPiotr Jasiukajtis * fields enclosed by brackets "[]" replaced with your own identifying
1725c28e83SPiotr Jasiukajtis * information: Portions Copyright [yyyy] [name of copyright owner]
1825c28e83SPiotr Jasiukajtis *
1925c28e83SPiotr Jasiukajtis * CDDL HEADER END
2025c28e83SPiotr Jasiukajtis */
2125c28e83SPiotr Jasiukajtis
2225c28e83SPiotr Jasiukajtis /*
2325c28e83SPiotr Jasiukajtis * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
2425c28e83SPiotr Jasiukajtis */
2525c28e83SPiotr Jasiukajtis /*
2625c28e83SPiotr Jasiukajtis * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
2725c28e83SPiotr Jasiukajtis * Use is subject to license terms.
2825c28e83SPiotr Jasiukajtis */
2925c28e83SPiotr Jasiukajtis
3025c28e83SPiotr Jasiukajtis #include <stdio.h>
3125c28e83SPiotr Jasiukajtis #include <unistd.h>
3225c28e83SPiotr Jasiukajtis #include <stdlib.h>
3325c28e83SPiotr Jasiukajtis #include <string.h>
3425c28e83SPiotr Jasiukajtis #include <signal.h>
3525c28e83SPiotr Jasiukajtis #include <siginfo.h>
3625c28e83SPiotr Jasiukajtis #include <ucontext.h>
3725c28e83SPiotr Jasiukajtis #include <thread.h>
3825c28e83SPiotr Jasiukajtis #include <math.h>
3925c28e83SPiotr Jasiukajtis #if defined(__SUNPRO_C)
4025c28e83SPiotr Jasiukajtis #include <sunmath.h>
4125c28e83SPiotr Jasiukajtis #endif
4225c28e83SPiotr Jasiukajtis #include <fenv.h>
4325c28e83SPiotr Jasiukajtis #include "fex_handler.h"
4425c28e83SPiotr Jasiukajtis #include "fenv_inlines.h"
4525c28e83SPiotr Jasiukajtis
4625c28e83SPiotr Jasiukajtis #if defined(__amd64)
4725c28e83SPiotr Jasiukajtis #define test_sse_hw 1
4825c28e83SPiotr Jasiukajtis #else
4925c28e83SPiotr Jasiukajtis /*
5025c28e83SPiotr Jasiukajtis * The following variable lives in libc on Solaris 10, where it
5125c28e83SPiotr Jasiukajtis * gets set to a nonzero value at startup time on systems with SSE.
5225c28e83SPiotr Jasiukajtis */
53f665a76fSRichard Lowe extern int _sse_hw;
54f665a76fSRichard Lowe #define test_sse_hw _sse_hw
5525c28e83SPiotr Jasiukajtis #endif
5625c28e83SPiotr Jasiukajtis
5725c28e83SPiotr Jasiukajtis static int accrued = 0;
5825c28e83SPiotr Jasiukajtis static thread_key_t accrued_key;
5925c28e83SPiotr Jasiukajtis static mutex_t accrued_key_lock = DEFAULTMUTEX;
6025c28e83SPiotr Jasiukajtis
6125c28e83SPiotr Jasiukajtis int *
__fex_accrued()6225c28e83SPiotr Jasiukajtis __fex_accrued()
6325c28e83SPiotr Jasiukajtis {
6425c28e83SPiotr Jasiukajtis int *p;
6525c28e83SPiotr Jasiukajtis
6625c28e83SPiotr Jasiukajtis if (thr_main())
6725c28e83SPiotr Jasiukajtis return &accrued;
6825c28e83SPiotr Jasiukajtis else {
6925c28e83SPiotr Jasiukajtis p = NULL;
7025c28e83SPiotr Jasiukajtis mutex_lock(&accrued_key_lock);
7125c28e83SPiotr Jasiukajtis if (thr_getspecific(accrued_key, (void **)&p) != 0 &&
7225c28e83SPiotr Jasiukajtis thr_keycreate(&accrued_key, free) != 0) {
7325c28e83SPiotr Jasiukajtis mutex_unlock(&accrued_key_lock);
7425c28e83SPiotr Jasiukajtis return NULL;
7525c28e83SPiotr Jasiukajtis }
7625c28e83SPiotr Jasiukajtis mutex_unlock(&accrued_key_lock);
7725c28e83SPiotr Jasiukajtis if (!p) {
7825c28e83SPiotr Jasiukajtis if ((p = (int*) malloc(sizeof(int))) == NULL)
7925c28e83SPiotr Jasiukajtis return NULL;
8025c28e83SPiotr Jasiukajtis if (thr_setspecific(accrued_key, (void *)p) != 0) {
8125c28e83SPiotr Jasiukajtis (void)free(p);
8225c28e83SPiotr Jasiukajtis return NULL;
8325c28e83SPiotr Jasiukajtis }
8425c28e83SPiotr Jasiukajtis *p = 0;
8525c28e83SPiotr Jasiukajtis }
8625c28e83SPiotr Jasiukajtis return p;
8725c28e83SPiotr Jasiukajtis }
8825c28e83SPiotr Jasiukajtis }
8925c28e83SPiotr Jasiukajtis
9025c28e83SPiotr Jasiukajtis void
__fenv_getfsr(unsigned long * fsr)9125c28e83SPiotr Jasiukajtis __fenv_getfsr(unsigned long *fsr)
9225c28e83SPiotr Jasiukajtis {
9325c28e83SPiotr Jasiukajtis unsigned int cwsw, mxcsr;
9425c28e83SPiotr Jasiukajtis
9525c28e83SPiotr Jasiukajtis __fenv_getcwsw(&cwsw);
9625c28e83SPiotr Jasiukajtis /* clear reserved bits for no particularly good reason */
9725c28e83SPiotr Jasiukajtis cwsw &= ~0xe0c00000u;
9825c28e83SPiotr Jasiukajtis if (test_sse_hw) {
9925c28e83SPiotr Jasiukajtis /* pick up exception flags (excluding denormal operand
10025c28e83SPiotr Jasiukajtis flag) from mxcsr */
10125c28e83SPiotr Jasiukajtis __fenv_getmxcsr(&mxcsr);
10225c28e83SPiotr Jasiukajtis cwsw |= (mxcsr & 0x3d);
10325c28e83SPiotr Jasiukajtis }
10425c28e83SPiotr Jasiukajtis cwsw |= *__fex_accrued();
10525c28e83SPiotr Jasiukajtis *fsr = cwsw ^ 0x003f0000u;
10625c28e83SPiotr Jasiukajtis }
10725c28e83SPiotr Jasiukajtis
10825c28e83SPiotr Jasiukajtis void
__fenv_setfsr(const unsigned long * fsr)10925c28e83SPiotr Jasiukajtis __fenv_setfsr(const unsigned long *fsr)
11025c28e83SPiotr Jasiukajtis {
11125c28e83SPiotr Jasiukajtis unsigned int cwsw, mxcsr;
11225c28e83SPiotr Jasiukajtis int te;
11325c28e83SPiotr Jasiukajtis
11425c28e83SPiotr Jasiukajtis /* save accrued exception flags corresponding to enabled exceptions */
11525c28e83SPiotr Jasiukajtis cwsw = (unsigned int)*fsr;
11625c28e83SPiotr Jasiukajtis te = __fenv_get_te(cwsw);
11725c28e83SPiotr Jasiukajtis *__fex_accrued() = cwsw & te;
11825c28e83SPiotr Jasiukajtis cwsw = (cwsw & ~te) ^ 0x003f0000;
11925c28e83SPiotr Jasiukajtis if (test_sse_hw) {
12025c28e83SPiotr Jasiukajtis /* propagate rounding direction, masks, and exception flags
12125c28e83SPiotr Jasiukajtis (excluding denormal operand mask and flag) to mxcsr */
12225c28e83SPiotr Jasiukajtis __fenv_getmxcsr(&mxcsr);
12325c28e83SPiotr Jasiukajtis mxcsr = (mxcsr & ~0x7ebd) | ((cwsw >> 13) & 0x6000) |
12425c28e83SPiotr Jasiukajtis ((cwsw >> 9) & 0x1e80) | (cwsw & 0x3d);
12525c28e83SPiotr Jasiukajtis __fenv_setmxcsr(&mxcsr);
12625c28e83SPiotr Jasiukajtis }
12725c28e83SPiotr Jasiukajtis __fenv_setcwsw(&cwsw);
12825c28e83SPiotr Jasiukajtis }
12925c28e83SPiotr Jasiukajtis
13025c28e83SPiotr Jasiukajtis /* Offsets into the fp environment save area (assumes 32-bit protected mode) */
13125c28e83SPiotr Jasiukajtis #define CW 0 /* control word */
13225c28e83SPiotr Jasiukajtis #define SW 1 /* status word */
13325c28e83SPiotr Jasiukajtis #define TW 2 /* tag word */
13425c28e83SPiotr Jasiukajtis #define IP 3 /* instruction pointer */
13525c28e83SPiotr Jasiukajtis #define OP 4 /* opcode */
13625c28e83SPiotr Jasiukajtis #define EA 5 /* operand address */
13725c28e83SPiotr Jasiukajtis
13825c28e83SPiotr Jasiukajtis /* macro for accessing fp registers in the save area */
13925c28e83SPiotr Jasiukajtis #if defined(__amd64)
14025c28e83SPiotr Jasiukajtis #define fpreg(u,x) *(long double *)(10*(x)+(char*)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.st)
14125c28e83SPiotr Jasiukajtis #else
14225c28e83SPiotr Jasiukajtis #define fpreg(u,x) *(long double *)(10*(x)+(char*)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[7])
14325c28e83SPiotr Jasiukajtis #endif
14425c28e83SPiotr Jasiukajtis
14525c28e83SPiotr Jasiukajtis /*
14625c28e83SPiotr Jasiukajtis * Fix sip->si_code; the Solaris x86 kernel can get it wrong
14725c28e83SPiotr Jasiukajtis */
14825c28e83SPiotr Jasiukajtis void
__fex_get_x86_exc(siginfo_t * sip,ucontext_t * uap)14925c28e83SPiotr Jasiukajtis __fex_get_x86_exc(siginfo_t *sip, ucontext_t *uap)
15025c28e83SPiotr Jasiukajtis {
15125c28e83SPiotr Jasiukajtis unsigned sw, cw;
15225c28e83SPiotr Jasiukajtis
15325c28e83SPiotr Jasiukajtis sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status;
15425c28e83SPiotr Jasiukajtis #if defined(__amd64)
15525c28e83SPiotr Jasiukajtis cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw;
15625c28e83SPiotr Jasiukajtis #else
15725c28e83SPiotr Jasiukajtis cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[CW];
15825c28e83SPiotr Jasiukajtis #endif
15925c28e83SPiotr Jasiukajtis if ((sw & FE_INVALID) && !(cw & (1 << fp_trap_invalid)))
16025c28e83SPiotr Jasiukajtis /* store 0 for stack fault, FPE_FLTINV for IEEE invalid op */
16125c28e83SPiotr Jasiukajtis sip->si_code = ((sw & 0x40)? 0 : FPE_FLTINV);
16225c28e83SPiotr Jasiukajtis else if ((sw & FE_DIVBYZERO) && !(cw & (1 << fp_trap_division)))
16325c28e83SPiotr Jasiukajtis sip->si_code = FPE_FLTDIV;
16425c28e83SPiotr Jasiukajtis else if ((sw & FE_OVERFLOW) && !(cw & (1 << fp_trap_overflow)))
16525c28e83SPiotr Jasiukajtis sip->si_code = FPE_FLTOVF;
16625c28e83SPiotr Jasiukajtis else if ((sw & FE_UNDERFLOW) && !(cw & (1 << fp_trap_underflow)))
16725c28e83SPiotr Jasiukajtis sip->si_code = FPE_FLTUND;
16825c28e83SPiotr Jasiukajtis else if ((sw & FE_INEXACT) && !(cw & (1 << fp_trap_inexact)))
16925c28e83SPiotr Jasiukajtis sip->si_code = FPE_FLTRES;
17025c28e83SPiotr Jasiukajtis else
17125c28e83SPiotr Jasiukajtis sip->si_code = 0;
17225c28e83SPiotr Jasiukajtis }
17325c28e83SPiotr Jasiukajtis
17425c28e83SPiotr Jasiukajtis static enum fp_class_type
my_fp_classf(float * x)17525c28e83SPiotr Jasiukajtis my_fp_classf(float *x)
17625c28e83SPiotr Jasiukajtis {
17725c28e83SPiotr Jasiukajtis int i = *(int*)x & ~0x80000000;
17825c28e83SPiotr Jasiukajtis
17925c28e83SPiotr Jasiukajtis if (i < 0x7f800000) {
18025c28e83SPiotr Jasiukajtis if (i < 0x00800000)
18125c28e83SPiotr Jasiukajtis return ((i == 0)? fp_zero : fp_subnormal);
18225c28e83SPiotr Jasiukajtis return fp_normal;
18325c28e83SPiotr Jasiukajtis }
18425c28e83SPiotr Jasiukajtis else if (i == 0x7f800000)
18525c28e83SPiotr Jasiukajtis return fp_infinity;
18625c28e83SPiotr Jasiukajtis else if (i & 0x400000)
18725c28e83SPiotr Jasiukajtis return fp_quiet;
18825c28e83SPiotr Jasiukajtis else
18925c28e83SPiotr Jasiukajtis return fp_signaling;
19025c28e83SPiotr Jasiukajtis }
19125c28e83SPiotr Jasiukajtis
19225c28e83SPiotr Jasiukajtis static enum fp_class_type
my_fp_class(double * x)19325c28e83SPiotr Jasiukajtis my_fp_class(double *x)
19425c28e83SPiotr Jasiukajtis {
19525c28e83SPiotr Jasiukajtis int i = *(1+(int*)x) & ~0x80000000;
19625c28e83SPiotr Jasiukajtis
19725c28e83SPiotr Jasiukajtis if (i < 0x7ff00000) {
19825c28e83SPiotr Jasiukajtis if (i < 0x00100000)
19925c28e83SPiotr Jasiukajtis return (((i | *(int*)x) == 0)? fp_zero : fp_subnormal);
20025c28e83SPiotr Jasiukajtis return fp_normal;
20125c28e83SPiotr Jasiukajtis }
20225c28e83SPiotr Jasiukajtis else if (i == 0x7ff00000 && *(int*)x == 0)
20325c28e83SPiotr Jasiukajtis return fp_infinity;
20425c28e83SPiotr Jasiukajtis else if (i & 0x80000)
20525c28e83SPiotr Jasiukajtis return fp_quiet;
20625c28e83SPiotr Jasiukajtis else
20725c28e83SPiotr Jasiukajtis return fp_signaling;
20825c28e83SPiotr Jasiukajtis }
20925c28e83SPiotr Jasiukajtis
21025c28e83SPiotr Jasiukajtis static enum fp_class_type
my_fp_classl(long double * x)21125c28e83SPiotr Jasiukajtis my_fp_classl(long double *x)
21225c28e83SPiotr Jasiukajtis {
21325c28e83SPiotr Jasiukajtis int i = *(2+(int*)x) & 0x7fff;
21425c28e83SPiotr Jasiukajtis
21525c28e83SPiotr Jasiukajtis if (i < 0x7fff) {
21625c28e83SPiotr Jasiukajtis if (i < 1) {
21725c28e83SPiotr Jasiukajtis if (*(1+(int*)x) < 0) return fp_normal; /* pseudo-denormal */
218f665a76fSRichard Lowe return (((*(1+(int*)x) | *(int*)x) == 0)?
21925c28e83SPiotr Jasiukajtis fp_zero : fp_subnormal);
22025c28e83SPiotr Jasiukajtis }
22125c28e83SPiotr Jasiukajtis return ((*(1+(int*)x) < 0)? fp_normal :
22225c28e83SPiotr Jasiukajtis (enum fp_class_type) -1); /* unsupported format */
22325c28e83SPiotr Jasiukajtis }
22425c28e83SPiotr Jasiukajtis else if (*(1+(int*)x) == 0x80000000 && *(int*)x == 0)
22525c28e83SPiotr Jasiukajtis return fp_infinity;
22625c28e83SPiotr Jasiukajtis else if (*(1+(unsigned*)x) >= 0xc0000000)
22725c28e83SPiotr Jasiukajtis return fp_quiet;
22825c28e83SPiotr Jasiukajtis else if (*(1+(int*)x) < 0)
22925c28e83SPiotr Jasiukajtis return fp_signaling;
23025c28e83SPiotr Jasiukajtis else
23125c28e83SPiotr Jasiukajtis return (enum fp_class_type) -1; /* unsupported format */
23225c28e83SPiotr Jasiukajtis }
23325c28e83SPiotr Jasiukajtis
23425c28e83SPiotr Jasiukajtis /*
23525c28e83SPiotr Jasiukajtis * Determine which type of invalid operation exception occurred
23625c28e83SPiotr Jasiukajtis */
23725c28e83SPiotr Jasiukajtis enum fex_exception
__fex_get_invalid_type(siginfo_t * sip,ucontext_t * uap)23825c28e83SPiotr Jasiukajtis __fex_get_invalid_type(siginfo_t *sip, ucontext_t *uap)
23925c28e83SPiotr Jasiukajtis {
24025c28e83SPiotr Jasiukajtis unsigned op;
24125c28e83SPiotr Jasiukajtis unsigned long ea;
24225c28e83SPiotr Jasiukajtis enum fp_class_type t1, t2;
24325c28e83SPiotr Jasiukajtis
24425c28e83SPiotr Jasiukajtis /* get the opcode and data address */
24525c28e83SPiotr Jasiukajtis #if defined(__amd64)
24625c28e83SPiotr Jasiukajtis op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
24725c28e83SPiotr Jasiukajtis ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp;
24825c28e83SPiotr Jasiukajtis #else
24925c28e83SPiotr Jasiukajtis op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
25025c28e83SPiotr Jasiukajtis ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
25125c28e83SPiotr Jasiukajtis #endif
25225c28e83SPiotr Jasiukajtis
25325c28e83SPiotr Jasiukajtis /* if the instruction is fld, the source must be snan (it can't be
25425c28e83SPiotr Jasiukajtis an unsupported format, since fldt doesn't raise any exceptions) */
25525c28e83SPiotr Jasiukajtis switch (op & 0x7f8) {
25625c28e83SPiotr Jasiukajtis case 0x100:
25725c28e83SPiotr Jasiukajtis case 0x140:
25825c28e83SPiotr Jasiukajtis case 0x180:
25925c28e83SPiotr Jasiukajtis case 0x500:
26025c28e83SPiotr Jasiukajtis case 0x540:
26125c28e83SPiotr Jasiukajtis case 0x580:
26225c28e83SPiotr Jasiukajtis return fex_inv_snan;
26325c28e83SPiotr Jasiukajtis }
26425c28e83SPiotr Jasiukajtis
26525c28e83SPiotr Jasiukajtis /* otherwise st is one of the operands; see if it's snan */
26625c28e83SPiotr Jasiukajtis t1 = my_fp_classl(&fpreg(uap, 0));
26725c28e83SPiotr Jasiukajtis if (t1 == fp_signaling)
26825c28e83SPiotr Jasiukajtis return fex_inv_snan;
26925c28e83SPiotr Jasiukajtis else if (t1 == (enum fp_class_type) -1)
27025c28e83SPiotr Jasiukajtis return (enum fex_exception) -1;
27125c28e83SPiotr Jasiukajtis
27225c28e83SPiotr Jasiukajtis /* determine the class of the second operand if there is one */
27325c28e83SPiotr Jasiukajtis t2 = fp_normal;
27425c28e83SPiotr Jasiukajtis switch (op & 0x7e0) {
27525c28e83SPiotr Jasiukajtis case 0x600:
27625c28e83SPiotr Jasiukajtis case 0x620:
27725c28e83SPiotr Jasiukajtis case 0x640:
27825c28e83SPiotr Jasiukajtis case 0x660:
27925c28e83SPiotr Jasiukajtis case 0x680:
28025c28e83SPiotr Jasiukajtis case 0x6a0:
28125c28e83SPiotr Jasiukajtis /* short memory operand */
28225c28e83SPiotr Jasiukajtis if (!ea)
28325c28e83SPiotr Jasiukajtis return (enum fex_exception) -1;
28425c28e83SPiotr Jasiukajtis if (*(short *)ea == 0)
28525c28e83SPiotr Jasiukajtis t2 = fp_zero;
28625c28e83SPiotr Jasiukajtis break;
28725c28e83SPiotr Jasiukajtis
28825c28e83SPiotr Jasiukajtis case 0x200:
28925c28e83SPiotr Jasiukajtis case 0x220:
29025c28e83SPiotr Jasiukajtis case 0x240:
29125c28e83SPiotr Jasiukajtis case 0x260:
29225c28e83SPiotr Jasiukajtis case 0x280:
29325c28e83SPiotr Jasiukajtis case 0x2a0:
29425c28e83SPiotr Jasiukajtis /* int memory operand */
29525c28e83SPiotr Jasiukajtis if (!ea)
29625c28e83SPiotr Jasiukajtis return (enum fex_exception) -1;
29725c28e83SPiotr Jasiukajtis if (*(int *)ea == 0)
29825c28e83SPiotr Jasiukajtis t2 = fp_zero;
29925c28e83SPiotr Jasiukajtis break;
30025c28e83SPiotr Jasiukajtis
30125c28e83SPiotr Jasiukajtis case 0x000:
30225c28e83SPiotr Jasiukajtis case 0x020:
30325c28e83SPiotr Jasiukajtis case 0x040:
30425c28e83SPiotr Jasiukajtis case 0x060:
30525c28e83SPiotr Jasiukajtis case 0x080:
30625c28e83SPiotr Jasiukajtis case 0x0a0:
30725c28e83SPiotr Jasiukajtis /* single precision memory operand */
30825c28e83SPiotr Jasiukajtis if (!ea)
30925c28e83SPiotr Jasiukajtis return (enum fex_exception) -1;
31025c28e83SPiotr Jasiukajtis t2 = my_fp_classf((float *)ea);
31125c28e83SPiotr Jasiukajtis break;
31225c28e83SPiotr Jasiukajtis
31325c28e83SPiotr Jasiukajtis case 0x400:
31425c28e83SPiotr Jasiukajtis case 0x420:
31525c28e83SPiotr Jasiukajtis case 0x440:
31625c28e83SPiotr Jasiukajtis case 0x460:
31725c28e83SPiotr Jasiukajtis case 0x480:
31825c28e83SPiotr Jasiukajtis case 0x4a0:
31925c28e83SPiotr Jasiukajtis /* double precision memory operand */
32025c28e83SPiotr Jasiukajtis if (!ea)
32125c28e83SPiotr Jasiukajtis return (enum fex_exception) -1;
32225c28e83SPiotr Jasiukajtis t2 = my_fp_class((double *)ea);
32325c28e83SPiotr Jasiukajtis break;
32425c28e83SPiotr Jasiukajtis
32525c28e83SPiotr Jasiukajtis case 0x0c0:
32625c28e83SPiotr Jasiukajtis case 0x0e0:
32725c28e83SPiotr Jasiukajtis case 0x3e0:
32825c28e83SPiotr Jasiukajtis case 0x4c0:
32925c28e83SPiotr Jasiukajtis case 0x4e0:
33025c28e83SPiotr Jasiukajtis case 0x5e0:
33125c28e83SPiotr Jasiukajtis case 0x6c0:
33225c28e83SPiotr Jasiukajtis case 0x6e0:
33325c28e83SPiotr Jasiukajtis case 0x7e0:
33425c28e83SPiotr Jasiukajtis /* register operand determined by opcode */
33525c28e83SPiotr Jasiukajtis switch (op & 0x7f8) {
33625c28e83SPiotr Jasiukajtis case 0x3e0:
33725c28e83SPiotr Jasiukajtis case 0x3f8:
33825c28e83SPiotr Jasiukajtis case 0x5f0:
33925c28e83SPiotr Jasiukajtis case 0x5f8:
34025c28e83SPiotr Jasiukajtis case 0x7e0:
34125c28e83SPiotr Jasiukajtis case 0x7f8:
34225c28e83SPiotr Jasiukajtis /* weed out nonexistent opcodes */
34325c28e83SPiotr Jasiukajtis break;
34425c28e83SPiotr Jasiukajtis
34525c28e83SPiotr Jasiukajtis default:
34625c28e83SPiotr Jasiukajtis t2 = my_fp_classl(&fpreg(uap, op & 7));
34725c28e83SPiotr Jasiukajtis }
34825c28e83SPiotr Jasiukajtis break;
34925c28e83SPiotr Jasiukajtis
35025c28e83SPiotr Jasiukajtis case 0x1e0:
35125c28e83SPiotr Jasiukajtis case 0x2e0:
35225c28e83SPiotr Jasiukajtis /* special forms */
35325c28e83SPiotr Jasiukajtis switch (op) {
35425c28e83SPiotr Jasiukajtis case 0x1f1: /* fyl2x */
35525c28e83SPiotr Jasiukajtis case 0x1f3: /* fpatan */
35625c28e83SPiotr Jasiukajtis case 0x1f5: /* fprem1 */
35725c28e83SPiotr Jasiukajtis case 0x1f8: /* fprem */
35825c28e83SPiotr Jasiukajtis case 0x1f9: /* fyl2xp1 */
35925c28e83SPiotr Jasiukajtis case 0x1fd: /* fscale */
36025c28e83SPiotr Jasiukajtis case 0x2e9: /* fucompp */
36125c28e83SPiotr Jasiukajtis t2 = my_fp_classl(&fpreg(uap, 1));
36225c28e83SPiotr Jasiukajtis break;
36325c28e83SPiotr Jasiukajtis }
36425c28e83SPiotr Jasiukajtis break;
36525c28e83SPiotr Jasiukajtis }
36625c28e83SPiotr Jasiukajtis
36725c28e83SPiotr Jasiukajtis /* see if the second op is snan */
36825c28e83SPiotr Jasiukajtis if (t2 == fp_signaling)
36925c28e83SPiotr Jasiukajtis return fex_inv_snan;
37025c28e83SPiotr Jasiukajtis else if (t2 == (enum fp_class_type) -1)
37125c28e83SPiotr Jasiukajtis return (enum fex_exception) -1;
37225c28e83SPiotr Jasiukajtis
37325c28e83SPiotr Jasiukajtis /* determine the type of operation */
37425c28e83SPiotr Jasiukajtis switch (op & 0x7f8) {
37525c28e83SPiotr Jasiukajtis case 0x000:
37625c28e83SPiotr Jasiukajtis case 0x020:
37725c28e83SPiotr Jasiukajtis case 0x028:
37825c28e83SPiotr Jasiukajtis case 0x040:
37925c28e83SPiotr Jasiukajtis case 0x060:
38025c28e83SPiotr Jasiukajtis case 0x068:
38125c28e83SPiotr Jasiukajtis case 0x080:
38225c28e83SPiotr Jasiukajtis case 0x0a0:
38325c28e83SPiotr Jasiukajtis case 0x0a8:
38425c28e83SPiotr Jasiukajtis case 0x0c0:
38525c28e83SPiotr Jasiukajtis case 0x0e0:
38625c28e83SPiotr Jasiukajtis case 0x0e8:
38725c28e83SPiotr Jasiukajtis case 0x400:
38825c28e83SPiotr Jasiukajtis case 0x420:
38925c28e83SPiotr Jasiukajtis case 0x428:
39025c28e83SPiotr Jasiukajtis case 0x440:
39125c28e83SPiotr Jasiukajtis case 0x460:
39225c28e83SPiotr Jasiukajtis case 0x468:
39325c28e83SPiotr Jasiukajtis case 0x480:
39425c28e83SPiotr Jasiukajtis case 0x4a0:
39525c28e83SPiotr Jasiukajtis case 0x4a8:
39625c28e83SPiotr Jasiukajtis case 0x4c0:
39725c28e83SPiotr Jasiukajtis case 0x4e0:
39825c28e83SPiotr Jasiukajtis case 0x4e8:
39925c28e83SPiotr Jasiukajtis case 0x6c0:
40025c28e83SPiotr Jasiukajtis case 0x6e0:
40125c28e83SPiotr Jasiukajtis case 0x6e8:
40225c28e83SPiotr Jasiukajtis /* fadd, fsub, fsubr */
40325c28e83SPiotr Jasiukajtis if (t1 == fp_infinity && t2 == fp_infinity)
40425c28e83SPiotr Jasiukajtis return fex_inv_isi;
40525c28e83SPiotr Jasiukajtis break;
40625c28e83SPiotr Jasiukajtis
40725c28e83SPiotr Jasiukajtis case 0x008:
40825c28e83SPiotr Jasiukajtis case 0x048:
40925c28e83SPiotr Jasiukajtis case 0x088:
41025c28e83SPiotr Jasiukajtis case 0x0c8:
41125c28e83SPiotr Jasiukajtis case 0x208:
41225c28e83SPiotr Jasiukajtis case 0x248:
41325c28e83SPiotr Jasiukajtis case 0x288:
41425c28e83SPiotr Jasiukajtis case 0x408:
41525c28e83SPiotr Jasiukajtis case 0x448:
41625c28e83SPiotr Jasiukajtis case 0x488:
41725c28e83SPiotr Jasiukajtis case 0x4c8:
41825c28e83SPiotr Jasiukajtis case 0x608:
41925c28e83SPiotr Jasiukajtis case 0x648:
42025c28e83SPiotr Jasiukajtis case 0x688:
42125c28e83SPiotr Jasiukajtis case 0x6c8:
42225c28e83SPiotr Jasiukajtis /* fmul */
42325c28e83SPiotr Jasiukajtis if ((t1 == fp_zero && t2 == fp_infinity) || (t2 == fp_zero &&
42425c28e83SPiotr Jasiukajtis t1 == fp_infinity))
42525c28e83SPiotr Jasiukajtis return fex_inv_zmi;
42625c28e83SPiotr Jasiukajtis break;
42725c28e83SPiotr Jasiukajtis
42825c28e83SPiotr Jasiukajtis case 0x030:
42925c28e83SPiotr Jasiukajtis case 0x038:
43025c28e83SPiotr Jasiukajtis case 0x070:
43125c28e83SPiotr Jasiukajtis case 0x078:
43225c28e83SPiotr Jasiukajtis case 0x0b0:
43325c28e83SPiotr Jasiukajtis case 0x0b8:
43425c28e83SPiotr Jasiukajtis case 0x0f0:
43525c28e83SPiotr Jasiukajtis case 0x0f8:
43625c28e83SPiotr Jasiukajtis case 0x230:
43725c28e83SPiotr Jasiukajtis case 0x238:
43825c28e83SPiotr Jasiukajtis case 0x270:
43925c28e83SPiotr Jasiukajtis case 0x278:
44025c28e83SPiotr Jasiukajtis case 0x2b0:
44125c28e83SPiotr Jasiukajtis case 0x2b8:
44225c28e83SPiotr Jasiukajtis case 0x430:
44325c28e83SPiotr Jasiukajtis case 0x438:
44425c28e83SPiotr Jasiukajtis case 0x470:
44525c28e83SPiotr Jasiukajtis case 0x478:
44625c28e83SPiotr Jasiukajtis case 0x4b0:
44725c28e83SPiotr Jasiukajtis case 0x4b8:
44825c28e83SPiotr Jasiukajtis case 0x4f0:
44925c28e83SPiotr Jasiukajtis case 0x4f8:
45025c28e83SPiotr Jasiukajtis case 0x630:
45125c28e83SPiotr Jasiukajtis case 0x638:
45225c28e83SPiotr Jasiukajtis case 0x670:
45325c28e83SPiotr Jasiukajtis case 0x678:
45425c28e83SPiotr Jasiukajtis case 0x6b0:
45525c28e83SPiotr Jasiukajtis case 0x6b8:
45625c28e83SPiotr Jasiukajtis case 0x6f0:
45725c28e83SPiotr Jasiukajtis case 0x6f8:
45825c28e83SPiotr Jasiukajtis /* fdiv */
45925c28e83SPiotr Jasiukajtis if (t1 == fp_zero && t2 == fp_zero)
46025c28e83SPiotr Jasiukajtis return fex_inv_zdz;
46125c28e83SPiotr Jasiukajtis else if (t1 == fp_infinity && t2 == fp_infinity)
46225c28e83SPiotr Jasiukajtis return fex_inv_idi;
46325c28e83SPiotr Jasiukajtis break;
46425c28e83SPiotr Jasiukajtis
46525c28e83SPiotr Jasiukajtis case 0x1f0:
46625c28e83SPiotr Jasiukajtis case 0x1f8:
46725c28e83SPiotr Jasiukajtis /* fsqrt, other special ops */
46825c28e83SPiotr Jasiukajtis return fex_inv_sqrt;
46925c28e83SPiotr Jasiukajtis
47025c28e83SPiotr Jasiukajtis case 0x010:
47125c28e83SPiotr Jasiukajtis case 0x018:
47225c28e83SPiotr Jasiukajtis case 0x050:
47325c28e83SPiotr Jasiukajtis case 0x058:
47425c28e83SPiotr Jasiukajtis case 0x090:
47525c28e83SPiotr Jasiukajtis case 0x098:
47625c28e83SPiotr Jasiukajtis case 0x0d0:
47725c28e83SPiotr Jasiukajtis case 0x0d8:
47825c28e83SPiotr Jasiukajtis case 0x210:
47925c28e83SPiotr Jasiukajtis case 0x218:
48025c28e83SPiotr Jasiukajtis case 0x250:
48125c28e83SPiotr Jasiukajtis case 0x258:
48225c28e83SPiotr Jasiukajtis case 0x290:
48325c28e83SPiotr Jasiukajtis case 0x298:
48425c28e83SPiotr Jasiukajtis case 0x2e8:
48525c28e83SPiotr Jasiukajtis case 0x3f0:
48625c28e83SPiotr Jasiukajtis case 0x410:
48725c28e83SPiotr Jasiukajtis case 0x418:
48825c28e83SPiotr Jasiukajtis case 0x450:
48925c28e83SPiotr Jasiukajtis case 0x458:
49025c28e83SPiotr Jasiukajtis case 0x490:
49125c28e83SPiotr Jasiukajtis case 0x498:
49225c28e83SPiotr Jasiukajtis case 0x4d0:
49325c28e83SPiotr Jasiukajtis case 0x4d8:
49425c28e83SPiotr Jasiukajtis case 0x5e0:
49525c28e83SPiotr Jasiukajtis case 0x5e8:
49625c28e83SPiotr Jasiukajtis case 0x610:
49725c28e83SPiotr Jasiukajtis case 0x618:
49825c28e83SPiotr Jasiukajtis case 0x650:
49925c28e83SPiotr Jasiukajtis case 0x658:
50025c28e83SPiotr Jasiukajtis case 0x690:
50125c28e83SPiotr Jasiukajtis case 0x698:
50225c28e83SPiotr Jasiukajtis case 0x6d0:
50325c28e83SPiotr Jasiukajtis case 0x6d8:
50425c28e83SPiotr Jasiukajtis case 0x7f0:
50525c28e83SPiotr Jasiukajtis /* fcom */
50625c28e83SPiotr Jasiukajtis if (t1 == fp_quiet || t2 == fp_quiet)
50725c28e83SPiotr Jasiukajtis return fex_inv_cmp;
50825c28e83SPiotr Jasiukajtis break;
50925c28e83SPiotr Jasiukajtis
51025c28e83SPiotr Jasiukajtis case 0x1e0:
51125c28e83SPiotr Jasiukajtis /* ftst */
51225c28e83SPiotr Jasiukajtis if (op == 0x1e4 && t1 == fp_quiet)
51325c28e83SPiotr Jasiukajtis return fex_inv_cmp;
51425c28e83SPiotr Jasiukajtis break;
51525c28e83SPiotr Jasiukajtis
51625c28e83SPiotr Jasiukajtis case 0x310:
51725c28e83SPiotr Jasiukajtis case 0x318:
51825c28e83SPiotr Jasiukajtis case 0x350:
51925c28e83SPiotr Jasiukajtis case 0x358:
52025c28e83SPiotr Jasiukajtis case 0x390:
52125c28e83SPiotr Jasiukajtis case 0x398:
52225c28e83SPiotr Jasiukajtis case 0x710:
52325c28e83SPiotr Jasiukajtis case 0x718:
52425c28e83SPiotr Jasiukajtis case 0x730:
52525c28e83SPiotr Jasiukajtis case 0x738:
52625c28e83SPiotr Jasiukajtis case 0x750:
52725c28e83SPiotr Jasiukajtis case 0x758:
52825c28e83SPiotr Jasiukajtis case 0x770:
52925c28e83SPiotr Jasiukajtis case 0x778:
53025c28e83SPiotr Jasiukajtis case 0x790:
53125c28e83SPiotr Jasiukajtis case 0x798:
53225c28e83SPiotr Jasiukajtis case 0x7b0:
53325c28e83SPiotr Jasiukajtis case 0x7b8:
53425c28e83SPiotr Jasiukajtis /* fist, fbst */
53525c28e83SPiotr Jasiukajtis return fex_inv_int;
53625c28e83SPiotr Jasiukajtis }
53725c28e83SPiotr Jasiukajtis
53825c28e83SPiotr Jasiukajtis return (enum fex_exception) -1;
53925c28e83SPiotr Jasiukajtis }
54025c28e83SPiotr Jasiukajtis
54125c28e83SPiotr Jasiukajtis /* scale factors for exponent unwrapping */
54225c28e83SPiotr Jasiukajtis static const long double
54325c28e83SPiotr Jasiukajtis two12288 = 1.139165225263043370845938579315932009e+3699l, /* 2^12288 */
54425c28e83SPiotr Jasiukajtis twom12288 = 8.778357852076208839765066529179033145e-3700l, /* 2^-12288 */
54525c28e83SPiotr Jasiukajtis twom12288mulp = 8.778357852076208839289190796475222545e-3700l;
54625c28e83SPiotr Jasiukajtis /* (")*(1-2^-64) */
54725c28e83SPiotr Jasiukajtis
54825c28e83SPiotr Jasiukajtis /* inline templates */
54925c28e83SPiotr Jasiukajtis extern long double f2xm1(long double);
55025c28e83SPiotr Jasiukajtis extern long double fyl2x(long double, long double);
55125c28e83SPiotr Jasiukajtis extern long double fptan(long double);
55225c28e83SPiotr Jasiukajtis extern long double fpatan(long double, long double);
55325c28e83SPiotr Jasiukajtis extern long double fxtract(long double);
55425c28e83SPiotr Jasiukajtis extern long double fprem1(long double, long double);
55525c28e83SPiotr Jasiukajtis extern long double fprem(long double, long double);
55625c28e83SPiotr Jasiukajtis extern long double fyl2xp1(long double, long double);
55725c28e83SPiotr Jasiukajtis extern long double fsqrt(long double);
55825c28e83SPiotr Jasiukajtis extern long double fsincos(long double);
55925c28e83SPiotr Jasiukajtis extern long double frndint(long double);
56025c28e83SPiotr Jasiukajtis extern long double fscale(long double, long double);
56125c28e83SPiotr Jasiukajtis extern long double fsin(long double);
56225c28e83SPiotr Jasiukajtis extern long double fcos(long double);
56325c28e83SPiotr Jasiukajtis
56425c28e83SPiotr Jasiukajtis /*
56525c28e83SPiotr Jasiukajtis * Get the operands, generate the default untrapped result with
56625c28e83SPiotr Jasiukajtis * exceptions, and set a code indicating the type of operation
56725c28e83SPiotr Jasiukajtis */
56825c28e83SPiotr Jasiukajtis void
__fex_get_op(siginfo_t * sip,ucontext_t * uap,fex_info_t * info)56925c28e83SPiotr Jasiukajtis __fex_get_op(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
57025c28e83SPiotr Jasiukajtis {
57125c28e83SPiotr Jasiukajtis fex_numeric_t t;
57225c28e83SPiotr Jasiukajtis long double op2v, x;
57325c28e83SPiotr Jasiukajtis unsigned int cwsw, ex, sw, op;
57425c28e83SPiotr Jasiukajtis unsigned long ea;
575*862246c1SToomas Soome volatile int c __unused;
57625c28e83SPiotr Jasiukajtis
57725c28e83SPiotr Jasiukajtis /* get the exception type, status word, opcode, and data address */
57825c28e83SPiotr Jasiukajtis ex = sip->si_code;
57925c28e83SPiotr Jasiukajtis sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status;
58025c28e83SPiotr Jasiukajtis #if defined(__amd64)
58125c28e83SPiotr Jasiukajtis op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
58225c28e83SPiotr Jasiukajtis ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp;
58325c28e83SPiotr Jasiukajtis #else
58425c28e83SPiotr Jasiukajtis op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
58525c28e83SPiotr Jasiukajtis ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
58625c28e83SPiotr Jasiukajtis #endif
58725c28e83SPiotr Jasiukajtis
58825c28e83SPiotr Jasiukajtis /* initialize res to the default untrapped result and ex to the
58925c28e83SPiotr Jasiukajtis corresponding flags (assume trapping is disabled and flags
59025c28e83SPiotr Jasiukajtis are clear) */
59125c28e83SPiotr Jasiukajtis
59225c28e83SPiotr Jasiukajtis /* single operand instructions */
59325c28e83SPiotr Jasiukajtis info->op = fex_cnvt;
59425c28e83SPiotr Jasiukajtis info->op2.type = fex_nodata;
59525c28e83SPiotr Jasiukajtis switch (op & 0x7f8) {
59625c28e83SPiotr Jasiukajtis /* load instructions */
59725c28e83SPiotr Jasiukajtis case 0x100:
59825c28e83SPiotr Jasiukajtis case 0x140:
59925c28e83SPiotr Jasiukajtis case 0x180:
60025c28e83SPiotr Jasiukajtis if (!ea) {
60125c28e83SPiotr Jasiukajtis info->op = fex_other;
60225c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
60325c28e83SPiotr Jasiukajtis info->flags = 0;
60425c28e83SPiotr Jasiukajtis return;
60525c28e83SPiotr Jasiukajtis }
60625c28e83SPiotr Jasiukajtis info->op1.type = fex_float;
60725c28e83SPiotr Jasiukajtis info->op1.val.f = *(float *)ea;
60825c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
60925c28e83SPiotr Jasiukajtis info->res.val.q = (long double) info->op1.val.f;
61025c28e83SPiotr Jasiukajtis goto done;
61125c28e83SPiotr Jasiukajtis
61225c28e83SPiotr Jasiukajtis case 0x500:
61325c28e83SPiotr Jasiukajtis case 0x540:
61425c28e83SPiotr Jasiukajtis case 0x580:
61525c28e83SPiotr Jasiukajtis if (!ea) {
61625c28e83SPiotr Jasiukajtis info->op = fex_other;
61725c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
61825c28e83SPiotr Jasiukajtis info->flags = 0;
61925c28e83SPiotr Jasiukajtis return;
62025c28e83SPiotr Jasiukajtis }
62125c28e83SPiotr Jasiukajtis info->op1.type = fex_double;
62225c28e83SPiotr Jasiukajtis info->op1.val.d = *(double *)ea;
62325c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
62425c28e83SPiotr Jasiukajtis info->res.val.q = (long double) info->op1.val.d;
62525c28e83SPiotr Jasiukajtis goto done;
62625c28e83SPiotr Jasiukajtis
62725c28e83SPiotr Jasiukajtis /* store instructions */
62825c28e83SPiotr Jasiukajtis case 0x110:
62925c28e83SPiotr Jasiukajtis case 0x118:
63025c28e83SPiotr Jasiukajtis case 0x150:
63125c28e83SPiotr Jasiukajtis case 0x158:
63225c28e83SPiotr Jasiukajtis case 0x190:
63325c28e83SPiotr Jasiukajtis case 0x198:
63425c28e83SPiotr Jasiukajtis info->res.type = fex_float;
63525c28e83SPiotr Jasiukajtis if (ex == FPE_FLTRES && (op & 8) != 0) {
63625c28e83SPiotr Jasiukajtis /* inexact, stack popped */
63725c28e83SPiotr Jasiukajtis if (!ea) {
63825c28e83SPiotr Jasiukajtis info->op = fex_other;
63925c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
64025c28e83SPiotr Jasiukajtis info->flags = 0;
64125c28e83SPiotr Jasiukajtis return;
64225c28e83SPiotr Jasiukajtis }
64325c28e83SPiotr Jasiukajtis info->op1.type = fex_nodata;
64425c28e83SPiotr Jasiukajtis info->res.val.f = *(float *)ea;
64525c28e83SPiotr Jasiukajtis info->flags = FE_INEXACT;
64625c28e83SPiotr Jasiukajtis return;
64725c28e83SPiotr Jasiukajtis }
64825c28e83SPiotr Jasiukajtis info->op1.type = fex_ldouble;
64925c28e83SPiotr Jasiukajtis info->op1.val.q = fpreg(uap, 0);
65025c28e83SPiotr Jasiukajtis info->res.val.f = (float) info->op1.val.q;
65125c28e83SPiotr Jasiukajtis goto done;
65225c28e83SPiotr Jasiukajtis
65325c28e83SPiotr Jasiukajtis case 0x310:
65425c28e83SPiotr Jasiukajtis case 0x318:
65525c28e83SPiotr Jasiukajtis case 0x350:
65625c28e83SPiotr Jasiukajtis case 0x358:
65725c28e83SPiotr Jasiukajtis case 0x390:
65825c28e83SPiotr Jasiukajtis case 0x398:
65925c28e83SPiotr Jasiukajtis info->res.type = fex_int;
66025c28e83SPiotr Jasiukajtis if (ex == FPE_FLTRES && (op & 8) != 0) {
66125c28e83SPiotr Jasiukajtis /* inexact, stack popped */
66225c28e83SPiotr Jasiukajtis if (!ea) {
66325c28e83SPiotr Jasiukajtis info->op = fex_other;
66425c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
66525c28e83SPiotr Jasiukajtis info->flags = 0;
66625c28e83SPiotr Jasiukajtis return;
66725c28e83SPiotr Jasiukajtis }
66825c28e83SPiotr Jasiukajtis info->op1.type = fex_nodata;
66925c28e83SPiotr Jasiukajtis info->res.val.i = *(int *)ea;
67025c28e83SPiotr Jasiukajtis info->flags = FE_INEXACT;
67125c28e83SPiotr Jasiukajtis return;
67225c28e83SPiotr Jasiukajtis }
67325c28e83SPiotr Jasiukajtis info->op1.type = fex_ldouble;
67425c28e83SPiotr Jasiukajtis info->op1.val.q = fpreg(uap, 0);
67525c28e83SPiotr Jasiukajtis info->res.val.i = (int) info->op1.val.q;
67625c28e83SPiotr Jasiukajtis goto done;
67725c28e83SPiotr Jasiukajtis
67825c28e83SPiotr Jasiukajtis case 0x510:
67925c28e83SPiotr Jasiukajtis case 0x518:
68025c28e83SPiotr Jasiukajtis case 0x550:
68125c28e83SPiotr Jasiukajtis case 0x558:
68225c28e83SPiotr Jasiukajtis case 0x590:
68325c28e83SPiotr Jasiukajtis case 0x598:
68425c28e83SPiotr Jasiukajtis info->res.type = fex_double;
68525c28e83SPiotr Jasiukajtis if (ex == FPE_FLTRES && (op & 8) != 0) {
68625c28e83SPiotr Jasiukajtis /* inexact, stack popped */
68725c28e83SPiotr Jasiukajtis if (!ea) {
68825c28e83SPiotr Jasiukajtis info->op = fex_other;
68925c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
69025c28e83SPiotr Jasiukajtis info->flags = 0;
69125c28e83SPiotr Jasiukajtis return;
69225c28e83SPiotr Jasiukajtis }
69325c28e83SPiotr Jasiukajtis info->op1.type = fex_nodata;
69425c28e83SPiotr Jasiukajtis info->res.val.d = *(double *)ea;
69525c28e83SPiotr Jasiukajtis info->flags = FE_INEXACT;
69625c28e83SPiotr Jasiukajtis return;
69725c28e83SPiotr Jasiukajtis }
69825c28e83SPiotr Jasiukajtis info->op1.type = fex_ldouble;
69925c28e83SPiotr Jasiukajtis info->op1.val.q = fpreg(uap, 0);
70025c28e83SPiotr Jasiukajtis info->res.val.d = (double) info->op1.val.q;
70125c28e83SPiotr Jasiukajtis goto done;
70225c28e83SPiotr Jasiukajtis
70325c28e83SPiotr Jasiukajtis case 0x710:
70425c28e83SPiotr Jasiukajtis case 0x718:
70525c28e83SPiotr Jasiukajtis case 0x750:
70625c28e83SPiotr Jasiukajtis case 0x758:
70725c28e83SPiotr Jasiukajtis case 0x790:
70825c28e83SPiotr Jasiukajtis case 0x798:
70925c28e83SPiotr Jasiukajtis info->res.type = fex_int;
71025c28e83SPiotr Jasiukajtis if (ex == FPE_FLTRES && (op & 8) != 0) {
71125c28e83SPiotr Jasiukajtis /* inexact, stack popped */
71225c28e83SPiotr Jasiukajtis if (!ea) {
71325c28e83SPiotr Jasiukajtis info->op = fex_other;
71425c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
71525c28e83SPiotr Jasiukajtis info->flags = 0;
71625c28e83SPiotr Jasiukajtis return;
71725c28e83SPiotr Jasiukajtis }
71825c28e83SPiotr Jasiukajtis info->op1.type = fex_nodata;
71925c28e83SPiotr Jasiukajtis info->res.val.i = *(short *)ea;
72025c28e83SPiotr Jasiukajtis info->flags = FE_INEXACT;
72125c28e83SPiotr Jasiukajtis return;
72225c28e83SPiotr Jasiukajtis }
72325c28e83SPiotr Jasiukajtis info->op1.type = fex_ldouble;
72425c28e83SPiotr Jasiukajtis info->op1.val.q = fpreg(uap, 0);
72525c28e83SPiotr Jasiukajtis info->res.val.i = (short) info->op1.val.q;
72625c28e83SPiotr Jasiukajtis goto done;
72725c28e83SPiotr Jasiukajtis
72825c28e83SPiotr Jasiukajtis case 0x730:
72925c28e83SPiotr Jasiukajtis case 0x770:
73025c28e83SPiotr Jasiukajtis case 0x7b0:
73125c28e83SPiotr Jasiukajtis /* fbstp; don't bother */
73225c28e83SPiotr Jasiukajtis info->op = fex_other;
73325c28e83SPiotr Jasiukajtis info->op1.type = info->res.type = fex_nodata;
73425c28e83SPiotr Jasiukajtis info->flags = 0;
73525c28e83SPiotr Jasiukajtis return;
73625c28e83SPiotr Jasiukajtis
73725c28e83SPiotr Jasiukajtis case 0x738:
73825c28e83SPiotr Jasiukajtis case 0x778:
73925c28e83SPiotr Jasiukajtis case 0x7b8:
74025c28e83SPiotr Jasiukajtis info->res.type = fex_llong;
74125c28e83SPiotr Jasiukajtis if (ex == FPE_FLTRES) {
74225c28e83SPiotr Jasiukajtis /* inexact, stack popped */
74325c28e83SPiotr Jasiukajtis if (!ea) {
74425c28e83SPiotr Jasiukajtis info->op = fex_other;
74525c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
74625c28e83SPiotr Jasiukajtis info->flags = 0;
74725c28e83SPiotr Jasiukajtis return;
74825c28e83SPiotr Jasiukajtis }
74925c28e83SPiotr Jasiukajtis info->op1.type = fex_nodata;
75025c28e83SPiotr Jasiukajtis info->res.val.l = *(long long *)ea;
75125c28e83SPiotr Jasiukajtis info->flags = FE_INEXACT;
75225c28e83SPiotr Jasiukajtis return;
75325c28e83SPiotr Jasiukajtis }
75425c28e83SPiotr Jasiukajtis info->op1.type = fex_ldouble;
75525c28e83SPiotr Jasiukajtis info->op1.val.q = fpreg(uap, 0);
75625c28e83SPiotr Jasiukajtis info->res.val.l = (long long) info->op1.val.q;
75725c28e83SPiotr Jasiukajtis goto done;
75825c28e83SPiotr Jasiukajtis }
75925c28e83SPiotr Jasiukajtis
76025c28e83SPiotr Jasiukajtis /* all other ops (except compares) have destinations on the stack
76125c28e83SPiotr Jasiukajtis so overflow, underflow, and inexact will stomp their operands */
76225c28e83SPiotr Jasiukajtis if (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES) {
76325c28e83SPiotr Jasiukajtis /* find the trapped result */
76425c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = fex_nodata;
76525c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
76625c28e83SPiotr Jasiukajtis switch (op & 0x7f8) {
76725c28e83SPiotr Jasiukajtis case 0x1f0:
76825c28e83SPiotr Jasiukajtis /* fptan pushes 1.0 afterward, so result is in st(1) */
76925c28e83SPiotr Jasiukajtis info->res.val.q = ((op == 0x1f2)? fpreg(uap, 1) :
77025c28e83SPiotr Jasiukajtis fpreg(uap, 0));
77125c28e83SPiotr Jasiukajtis break;
77225c28e83SPiotr Jasiukajtis
77325c28e83SPiotr Jasiukajtis case 0x4c0:
77425c28e83SPiotr Jasiukajtis case 0x4c8:
77525c28e83SPiotr Jasiukajtis case 0x4e0:
77625c28e83SPiotr Jasiukajtis case 0x4e8:
77725c28e83SPiotr Jasiukajtis case 0x4f0:
77825c28e83SPiotr Jasiukajtis case 0x4f8:
77925c28e83SPiotr Jasiukajtis info->res.val.q = fpreg(uap, op & 7);
78025c28e83SPiotr Jasiukajtis break;
78125c28e83SPiotr Jasiukajtis
78225c28e83SPiotr Jasiukajtis case 0x6c0:
78325c28e83SPiotr Jasiukajtis case 0x6c8:
78425c28e83SPiotr Jasiukajtis case 0x6e0:
78525c28e83SPiotr Jasiukajtis case 0x6e8:
78625c28e83SPiotr Jasiukajtis case 0x6f0:
78725c28e83SPiotr Jasiukajtis case 0x6f8:
78825c28e83SPiotr Jasiukajtis /* stack was popped afterward */
78925c28e83SPiotr Jasiukajtis info->res.val.q = fpreg(uap, (op - 1) & 7);
79025c28e83SPiotr Jasiukajtis break;
79125c28e83SPiotr Jasiukajtis
79225c28e83SPiotr Jasiukajtis default:
79325c28e83SPiotr Jasiukajtis info->res.val.q = fpreg(uap, 0);
79425c28e83SPiotr Jasiukajtis }
79525c28e83SPiotr Jasiukajtis
79625c28e83SPiotr Jasiukajtis /* reconstruct default untrapped result */
79725c28e83SPiotr Jasiukajtis if (ex == FPE_FLTOVF) {
79825c28e83SPiotr Jasiukajtis /* generate an overflow with the sign of the result */
79925c28e83SPiotr Jasiukajtis x = two12288;
80025c28e83SPiotr Jasiukajtis *(4+(short*)&x) |= (*(4+(short*)&info->res.val.q) & 0x8000);
80125c28e83SPiotr Jasiukajtis info->res.val.q = x * two12288;
80225c28e83SPiotr Jasiukajtis info->flags = FE_OVERFLOW | FE_INEXACT;
80325c28e83SPiotr Jasiukajtis __fenv_getcwsw(&cwsw);
80425c28e83SPiotr Jasiukajtis cwsw &= ~FE_ALL_EXCEPT;
80525c28e83SPiotr Jasiukajtis __fenv_setcwsw(&cwsw);
80625c28e83SPiotr Jasiukajtis }
80725c28e83SPiotr Jasiukajtis else if (ex == FPE_FLTUND) {
80825c28e83SPiotr Jasiukajtis /* undo the scaling; we can't distinguish a chopped result
80925c28e83SPiotr Jasiukajtis from an exact one without futzing around to trap all in-
81025c28e83SPiotr Jasiukajtis exact exceptions so as to keep the flag clear, so we just
81125c28e83SPiotr Jasiukajtis punt */
81225c28e83SPiotr Jasiukajtis if (sw & 0x200) /* result was rounded up */
81325c28e83SPiotr Jasiukajtis info->res.val.q = (info->res.val.q * twom12288) * twom12288mulp;
81425c28e83SPiotr Jasiukajtis else
81525c28e83SPiotr Jasiukajtis info->res.val.q = (info->res.val.q * twom12288) * twom12288;
81625c28e83SPiotr Jasiukajtis __fenv_getcwsw(&cwsw);
81725c28e83SPiotr Jasiukajtis info->flags = (cwsw & FE_INEXACT) | FE_UNDERFLOW;
81825c28e83SPiotr Jasiukajtis cwsw &= ~FE_ALL_EXCEPT;
81925c28e83SPiotr Jasiukajtis __fenv_setcwsw(&cwsw);
82025c28e83SPiotr Jasiukajtis }
82125c28e83SPiotr Jasiukajtis else
82225c28e83SPiotr Jasiukajtis info->flags = FE_INEXACT;
82325c28e83SPiotr Jasiukajtis
82425c28e83SPiotr Jasiukajtis /* determine the operation code */
82525c28e83SPiotr Jasiukajtis switch (op) {
82625c28e83SPiotr Jasiukajtis case 0x1f0: /* f2xm1 */
82725c28e83SPiotr Jasiukajtis case 0x1f1: /* fyl2x */
82825c28e83SPiotr Jasiukajtis case 0x1f2: /* fptan */
82925c28e83SPiotr Jasiukajtis case 0x1f3: /* fpatan */
83025c28e83SPiotr Jasiukajtis case 0x1f5: /* fprem1 */
83125c28e83SPiotr Jasiukajtis case 0x1f8: /* fprem */
83225c28e83SPiotr Jasiukajtis case 0x1f9: /* fyl2xp1 */
83325c28e83SPiotr Jasiukajtis case 0x1fb: /* fsincos */
83425c28e83SPiotr Jasiukajtis case 0x1fc: /* frndint */
83525c28e83SPiotr Jasiukajtis case 0x1fd: /* fscale */
83625c28e83SPiotr Jasiukajtis case 0x1fe: /* fsin */
83725c28e83SPiotr Jasiukajtis case 0x1ff: /* fcos */
83825c28e83SPiotr Jasiukajtis info->op = fex_other;
83925c28e83SPiotr Jasiukajtis return;
84025c28e83SPiotr Jasiukajtis
84125c28e83SPiotr Jasiukajtis case 0x1fa: /* fsqrt */
84225c28e83SPiotr Jasiukajtis info->op = fex_sqrt;
84325c28e83SPiotr Jasiukajtis return;
84425c28e83SPiotr Jasiukajtis }
84525c28e83SPiotr Jasiukajtis
84625c28e83SPiotr Jasiukajtis info->op = fex_other;
84725c28e83SPiotr Jasiukajtis switch (op & 0x7c0) {
84825c28e83SPiotr Jasiukajtis case 0x000:
84925c28e83SPiotr Jasiukajtis case 0x040:
85025c28e83SPiotr Jasiukajtis case 0x080:
85125c28e83SPiotr Jasiukajtis case 0x0c0:
85225c28e83SPiotr Jasiukajtis case 0x200:
85325c28e83SPiotr Jasiukajtis case 0x240:
85425c28e83SPiotr Jasiukajtis case 0x280:
85525c28e83SPiotr Jasiukajtis case 0x400:
85625c28e83SPiotr Jasiukajtis case 0x440:
85725c28e83SPiotr Jasiukajtis case 0x480:
85825c28e83SPiotr Jasiukajtis case 0x4c0:
85925c28e83SPiotr Jasiukajtis case 0x600:
86025c28e83SPiotr Jasiukajtis case 0x640:
86125c28e83SPiotr Jasiukajtis case 0x680:
86225c28e83SPiotr Jasiukajtis case 0x6c0:
86325c28e83SPiotr Jasiukajtis switch (op & 0x38) {
86425c28e83SPiotr Jasiukajtis case 0x00:
86525c28e83SPiotr Jasiukajtis info->op = fex_add;
86625c28e83SPiotr Jasiukajtis break;
86725c28e83SPiotr Jasiukajtis
86825c28e83SPiotr Jasiukajtis case 0x08:
86925c28e83SPiotr Jasiukajtis info->op = fex_mul;
87025c28e83SPiotr Jasiukajtis break;
87125c28e83SPiotr Jasiukajtis
87225c28e83SPiotr Jasiukajtis case 0x20:
87325c28e83SPiotr Jasiukajtis case 0x28:
87425c28e83SPiotr Jasiukajtis info->op = fex_sub;
87525c28e83SPiotr Jasiukajtis break;
87625c28e83SPiotr Jasiukajtis
87725c28e83SPiotr Jasiukajtis case 0x30:
87825c28e83SPiotr Jasiukajtis case 0x38:
87925c28e83SPiotr Jasiukajtis info->op = fex_div;
88025c28e83SPiotr Jasiukajtis break;
88125c28e83SPiotr Jasiukajtis }
88225c28e83SPiotr Jasiukajtis }
88325c28e83SPiotr Jasiukajtis return;
88425c28e83SPiotr Jasiukajtis }
88525c28e83SPiotr Jasiukajtis
88625c28e83SPiotr Jasiukajtis /* for other exceptions, the operands are preserved, so we can
88725c28e83SPiotr Jasiukajtis just emulate the operation with traps disabled */
88825c28e83SPiotr Jasiukajtis
88925c28e83SPiotr Jasiukajtis /* one operand is always in st */
89025c28e83SPiotr Jasiukajtis info->op1.type = fex_ldouble;
89125c28e83SPiotr Jasiukajtis info->op1.val.q = fpreg(uap, 0);
89225c28e83SPiotr Jasiukajtis
89325c28e83SPiotr Jasiukajtis /* oddball instructions */
89425c28e83SPiotr Jasiukajtis info->op = fex_other;
89525c28e83SPiotr Jasiukajtis switch (op) {
89625c28e83SPiotr Jasiukajtis case 0x1e4: /* ftst */
89725c28e83SPiotr Jasiukajtis info->op = fex_cmp;
89825c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
89925c28e83SPiotr Jasiukajtis info->op2.val.q = 0.0l;
90025c28e83SPiotr Jasiukajtis info->res.type = fex_nodata;
90125c28e83SPiotr Jasiukajtis c = (info->op1.val.q < info->op2.val.q);
90225c28e83SPiotr Jasiukajtis goto done;
90325c28e83SPiotr Jasiukajtis
90425c28e83SPiotr Jasiukajtis case 0x1f0: /* f2xm1 */
90525c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
90625c28e83SPiotr Jasiukajtis info->res.val.q = f2xm1(info->op1.val.q);
90725c28e83SPiotr Jasiukajtis goto done;
90825c28e83SPiotr Jasiukajtis
90925c28e83SPiotr Jasiukajtis case 0x1f1: /* fyl2x */
91025c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
91125c28e83SPiotr Jasiukajtis info->op2.val.q = fpreg(uap, 1);
91225c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
91325c28e83SPiotr Jasiukajtis info->res.val.q = fyl2x(info->op1.val.q, info->op2.val.q);
91425c28e83SPiotr Jasiukajtis goto done;
91525c28e83SPiotr Jasiukajtis
91625c28e83SPiotr Jasiukajtis case 0x1f2: /* fptan */
91725c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
91825c28e83SPiotr Jasiukajtis info->res.val.q = fptan(info->op1.val.q);
91925c28e83SPiotr Jasiukajtis goto done;
92025c28e83SPiotr Jasiukajtis
92125c28e83SPiotr Jasiukajtis case 0x1f3: /* fpatan */
92225c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
92325c28e83SPiotr Jasiukajtis info->op2.val.q = fpreg(uap, 1);
92425c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
92525c28e83SPiotr Jasiukajtis info->res.val.q = fpatan(info->op1.val.q, info->op2.val.q);
92625c28e83SPiotr Jasiukajtis goto done;
92725c28e83SPiotr Jasiukajtis
92825c28e83SPiotr Jasiukajtis case 0x1f4: /* fxtract */
92925c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
93025c28e83SPiotr Jasiukajtis info->res.val.q = fxtract(info->op1.val.q);
93125c28e83SPiotr Jasiukajtis goto done;
93225c28e83SPiotr Jasiukajtis
93325c28e83SPiotr Jasiukajtis case 0x1f5: /* fprem1 */
93425c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
93525c28e83SPiotr Jasiukajtis info->op2.val.q = fpreg(uap, 1);
93625c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
93725c28e83SPiotr Jasiukajtis info->res.val.q = fprem1(info->op1.val.q, info->op2.val.q);
93825c28e83SPiotr Jasiukajtis goto done;
93925c28e83SPiotr Jasiukajtis
94025c28e83SPiotr Jasiukajtis case 0x1f8: /* fprem */
94125c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
94225c28e83SPiotr Jasiukajtis info->op2.val.q = fpreg(uap, 1);
94325c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
94425c28e83SPiotr Jasiukajtis info->res.val.q = fprem(info->op1.val.q, info->op2.val.q);
94525c28e83SPiotr Jasiukajtis goto done;
94625c28e83SPiotr Jasiukajtis
94725c28e83SPiotr Jasiukajtis case 0x1f9: /* fyl2xp1 */
94825c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
94925c28e83SPiotr Jasiukajtis info->op2.val.q = fpreg(uap, 1);
95025c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
95125c28e83SPiotr Jasiukajtis info->res.val.q = fyl2xp1(info->op1.val.q, info->op2.val.q);
95225c28e83SPiotr Jasiukajtis goto done;
95325c28e83SPiotr Jasiukajtis
95425c28e83SPiotr Jasiukajtis case 0x1fa: /* fsqrt */
95525c28e83SPiotr Jasiukajtis info->op = fex_sqrt;
95625c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
95725c28e83SPiotr Jasiukajtis info->res.val.q = fsqrt(info->op1.val.q);
95825c28e83SPiotr Jasiukajtis goto done;
95925c28e83SPiotr Jasiukajtis
96025c28e83SPiotr Jasiukajtis case 0x1fb: /* fsincos */
96125c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
96225c28e83SPiotr Jasiukajtis info->res.val.q = fsincos(info->op1.val.q);
96325c28e83SPiotr Jasiukajtis goto done;
96425c28e83SPiotr Jasiukajtis
96525c28e83SPiotr Jasiukajtis case 0x1fc: /* frndint */
96625c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
96725c28e83SPiotr Jasiukajtis info->res.val.q = frndint(info->op1.val.q);
96825c28e83SPiotr Jasiukajtis goto done;
96925c28e83SPiotr Jasiukajtis
97025c28e83SPiotr Jasiukajtis case 0x1fd: /* fscale */
97125c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
97225c28e83SPiotr Jasiukajtis info->op2.val.q = fpreg(uap, 1);
97325c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
97425c28e83SPiotr Jasiukajtis info->res.val.q = fscale(info->op1.val.q, info->op2.val.q);
97525c28e83SPiotr Jasiukajtis goto done;
97625c28e83SPiotr Jasiukajtis
97725c28e83SPiotr Jasiukajtis case 0x1fe: /* fsin */
97825c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
97925c28e83SPiotr Jasiukajtis info->res.val.q = fsin(info->op1.val.q);
98025c28e83SPiotr Jasiukajtis goto done;
98125c28e83SPiotr Jasiukajtis
98225c28e83SPiotr Jasiukajtis case 0x1ff: /* fcos */
98325c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
98425c28e83SPiotr Jasiukajtis info->res.val.q = fcos(info->op1.val.q);
98525c28e83SPiotr Jasiukajtis goto done;
98625c28e83SPiotr Jasiukajtis
98725c28e83SPiotr Jasiukajtis case 0x2e9: /* fucompp */
98825c28e83SPiotr Jasiukajtis info->op = fex_cmp;
98925c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
99025c28e83SPiotr Jasiukajtis info->op2.val.q = fpreg(uap, 1);
99125c28e83SPiotr Jasiukajtis info->res.type = fex_nodata;
99225c28e83SPiotr Jasiukajtis c = (info->op1.val.q == info->op2.val.q);
99325c28e83SPiotr Jasiukajtis goto done;
99425c28e83SPiotr Jasiukajtis }
99525c28e83SPiotr Jasiukajtis
99625c28e83SPiotr Jasiukajtis /* fucom[p], fcomi[p], fucomi[p] */
99725c28e83SPiotr Jasiukajtis switch (op & 0x7f8) {
99825c28e83SPiotr Jasiukajtis case 0x3e8:
99925c28e83SPiotr Jasiukajtis case 0x5e0:
100025c28e83SPiotr Jasiukajtis case 0x5e8:
100125c28e83SPiotr Jasiukajtis case 0x7e8: /* unordered compares */
100225c28e83SPiotr Jasiukajtis info->op = fex_cmp;
100325c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
100425c28e83SPiotr Jasiukajtis info->op2.val.q = fpreg(uap, op & 7);
100525c28e83SPiotr Jasiukajtis info->res.type = fex_nodata;
100625c28e83SPiotr Jasiukajtis c = (info->op1.val.q == info->op2.val.q);
100725c28e83SPiotr Jasiukajtis goto done;
100825c28e83SPiotr Jasiukajtis
100925c28e83SPiotr Jasiukajtis case 0x3f0:
101025c28e83SPiotr Jasiukajtis case 0x7f0: /* ordered compares */
101125c28e83SPiotr Jasiukajtis info->op = fex_cmp;
101225c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
101325c28e83SPiotr Jasiukajtis info->op2.val.q = fpreg(uap, op & 7);
101425c28e83SPiotr Jasiukajtis info->res.type = fex_nodata;
101525c28e83SPiotr Jasiukajtis c = (info->op1.val.q < info->op2.val.q);
101625c28e83SPiotr Jasiukajtis goto done;
101725c28e83SPiotr Jasiukajtis }
101825c28e83SPiotr Jasiukajtis
101925c28e83SPiotr Jasiukajtis /* all other instructions come in groups of the form
102025c28e83SPiotr Jasiukajtis fadd, fmul, fcom, fcomp, fsub, fsubr, fdiv, fdivr */
102125c28e83SPiotr Jasiukajtis
102225c28e83SPiotr Jasiukajtis /* get the second operand */
102325c28e83SPiotr Jasiukajtis switch (op & 0x7c0) {
102425c28e83SPiotr Jasiukajtis case 0x000:
102525c28e83SPiotr Jasiukajtis case 0x040:
102625c28e83SPiotr Jasiukajtis case 0x080:
102725c28e83SPiotr Jasiukajtis if (!ea) {
102825c28e83SPiotr Jasiukajtis info->op = fex_other;
102925c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
103025c28e83SPiotr Jasiukajtis info->flags = 0;
103125c28e83SPiotr Jasiukajtis return;
103225c28e83SPiotr Jasiukajtis }
103325c28e83SPiotr Jasiukajtis info->op2.type = fex_float;
103425c28e83SPiotr Jasiukajtis info->op2.val.f = *(float *)ea;
103525c28e83SPiotr Jasiukajtis op2v = (long double) info->op2.val.f;
103625c28e83SPiotr Jasiukajtis break;
103725c28e83SPiotr Jasiukajtis
103825c28e83SPiotr Jasiukajtis case 0x0c0:
103925c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
104025c28e83SPiotr Jasiukajtis op2v = info->op2.val.q = fpreg(uap, op & 7);
104125c28e83SPiotr Jasiukajtis break;
104225c28e83SPiotr Jasiukajtis
104325c28e83SPiotr Jasiukajtis case 0x200:
104425c28e83SPiotr Jasiukajtis case 0x240:
104525c28e83SPiotr Jasiukajtis case 0x280:
104625c28e83SPiotr Jasiukajtis if (!ea) {
104725c28e83SPiotr Jasiukajtis info->op = fex_other;
104825c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
104925c28e83SPiotr Jasiukajtis info->flags = 0;
105025c28e83SPiotr Jasiukajtis return;
105125c28e83SPiotr Jasiukajtis }
105225c28e83SPiotr Jasiukajtis info->op2.type = fex_int;
105325c28e83SPiotr Jasiukajtis info->op2.val.i = *(int *)ea;
105425c28e83SPiotr Jasiukajtis op2v = (long double) info->op2.val.i;
105525c28e83SPiotr Jasiukajtis break;
105625c28e83SPiotr Jasiukajtis
105725c28e83SPiotr Jasiukajtis case 0x400:
105825c28e83SPiotr Jasiukajtis case 0x440:
105925c28e83SPiotr Jasiukajtis case 0x480:
106025c28e83SPiotr Jasiukajtis if (!ea) {
106125c28e83SPiotr Jasiukajtis info->op = fex_other;
106225c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
106325c28e83SPiotr Jasiukajtis info->flags = 0;
106425c28e83SPiotr Jasiukajtis return;
106525c28e83SPiotr Jasiukajtis }
106625c28e83SPiotr Jasiukajtis info->op2.type = fex_double;
106725c28e83SPiotr Jasiukajtis info->op2.val.d = *(double *)ea;
106825c28e83SPiotr Jasiukajtis op2v = (long double) info->op2.val.d;
106925c28e83SPiotr Jasiukajtis break;
107025c28e83SPiotr Jasiukajtis
107125c28e83SPiotr Jasiukajtis case 0x4c0:
107225c28e83SPiotr Jasiukajtis case 0x6c0:
107325c28e83SPiotr Jasiukajtis info->op2.type = fex_ldouble;
107425c28e83SPiotr Jasiukajtis info->op2.val.q = fpreg(uap, op & 7);
107525c28e83SPiotr Jasiukajtis t = info->op1;
107625c28e83SPiotr Jasiukajtis info->op1 = info->op2;
107725c28e83SPiotr Jasiukajtis info->op2 = t;
107825c28e83SPiotr Jasiukajtis op2v = info->op2.val.q;
107925c28e83SPiotr Jasiukajtis break;
108025c28e83SPiotr Jasiukajtis
108125c28e83SPiotr Jasiukajtis case 0x600:
108225c28e83SPiotr Jasiukajtis case 0x640:
108325c28e83SPiotr Jasiukajtis case 0x680:
108425c28e83SPiotr Jasiukajtis if (!ea) {
108525c28e83SPiotr Jasiukajtis info->op = fex_other;
108625c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
108725c28e83SPiotr Jasiukajtis info->flags = 0;
108825c28e83SPiotr Jasiukajtis return;
108925c28e83SPiotr Jasiukajtis }
109025c28e83SPiotr Jasiukajtis info->op2.type = fex_int;
109125c28e83SPiotr Jasiukajtis info->op2.val.i = *(short *)ea;
109225c28e83SPiotr Jasiukajtis op2v = (long double) info->op2.val.i;
109325c28e83SPiotr Jasiukajtis break;
109425c28e83SPiotr Jasiukajtis
109525c28e83SPiotr Jasiukajtis default:
109625c28e83SPiotr Jasiukajtis info->op = fex_other;
109725c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
109825c28e83SPiotr Jasiukajtis info->flags = 0;
109925c28e83SPiotr Jasiukajtis return;
110025c28e83SPiotr Jasiukajtis }
110125c28e83SPiotr Jasiukajtis
110225c28e83SPiotr Jasiukajtis /* distinguish different operations in the group */
110325c28e83SPiotr Jasiukajtis info->res.type = fex_ldouble;
110425c28e83SPiotr Jasiukajtis switch (op & 0x38) {
110525c28e83SPiotr Jasiukajtis case 0x00:
110625c28e83SPiotr Jasiukajtis info->op = fex_add;
110725c28e83SPiotr Jasiukajtis info->res.val.q = info->op1.val.q + op2v;
110825c28e83SPiotr Jasiukajtis break;
110925c28e83SPiotr Jasiukajtis
111025c28e83SPiotr Jasiukajtis case 0x08:
111125c28e83SPiotr Jasiukajtis info->op = fex_mul;
111225c28e83SPiotr Jasiukajtis info->res.val.q = info->op1.val.q * op2v;
111325c28e83SPiotr Jasiukajtis break;
111425c28e83SPiotr Jasiukajtis
111525c28e83SPiotr Jasiukajtis case 0x10:
111625c28e83SPiotr Jasiukajtis case 0x18:
111725c28e83SPiotr Jasiukajtis info->op = fex_cmp;
111825c28e83SPiotr Jasiukajtis info->res.type = fex_nodata;
111925c28e83SPiotr Jasiukajtis c = (info->op1.val.q < op2v);
112025c28e83SPiotr Jasiukajtis break;
112125c28e83SPiotr Jasiukajtis
112225c28e83SPiotr Jasiukajtis case 0x20:
112325c28e83SPiotr Jasiukajtis info->op = fex_sub;
112425c28e83SPiotr Jasiukajtis info->res.val.q = info->op1.val.q - op2v;
112525c28e83SPiotr Jasiukajtis break;
112625c28e83SPiotr Jasiukajtis
112725c28e83SPiotr Jasiukajtis case 0x28:
112825c28e83SPiotr Jasiukajtis info->op = fex_sub;
112925c28e83SPiotr Jasiukajtis info->res.val.q = op2v - info->op1.val.q;
113025c28e83SPiotr Jasiukajtis t = info->op1;
113125c28e83SPiotr Jasiukajtis info->op1 = info->op2;
113225c28e83SPiotr Jasiukajtis info->op2 = t;
113325c28e83SPiotr Jasiukajtis break;
113425c28e83SPiotr Jasiukajtis
113525c28e83SPiotr Jasiukajtis case 0x30:
113625c28e83SPiotr Jasiukajtis info->op = fex_div;
113725c28e83SPiotr Jasiukajtis info->res.val.q = info->op1.val.q / op2v;
113825c28e83SPiotr Jasiukajtis break;
113925c28e83SPiotr Jasiukajtis
114025c28e83SPiotr Jasiukajtis case 0x38:
114125c28e83SPiotr Jasiukajtis info->op = fex_div;
114225c28e83SPiotr Jasiukajtis info->res.val.q = op2v / info->op1.val.q;
114325c28e83SPiotr Jasiukajtis t = info->op1;
114425c28e83SPiotr Jasiukajtis info->op1 = info->op2;
114525c28e83SPiotr Jasiukajtis info->op2 = t;
114625c28e83SPiotr Jasiukajtis break;
114725c28e83SPiotr Jasiukajtis
114825c28e83SPiotr Jasiukajtis default:
114925c28e83SPiotr Jasiukajtis info->op = fex_other;
115025c28e83SPiotr Jasiukajtis info->op1.type = info->op2.type = info->res.type = fex_nodata;
115125c28e83SPiotr Jasiukajtis info->flags = 0;
115225c28e83SPiotr Jasiukajtis return;
115325c28e83SPiotr Jasiukajtis }
115425c28e83SPiotr Jasiukajtis
115525c28e83SPiotr Jasiukajtis done:
115625c28e83SPiotr Jasiukajtis __fenv_getcwsw(&cwsw);
115725c28e83SPiotr Jasiukajtis info->flags = cwsw & FE_ALL_EXCEPT;
115825c28e83SPiotr Jasiukajtis cwsw &= ~FE_ALL_EXCEPT;
115925c28e83SPiotr Jasiukajtis __fenv_setcwsw(&cwsw);
116025c28e83SPiotr Jasiukajtis }
116125c28e83SPiotr Jasiukajtis
116225c28e83SPiotr Jasiukajtis /* pop the saved stack */
pop(ucontext_t * uap)116325c28e83SPiotr Jasiukajtis static void pop(ucontext_t *uap)
116425c28e83SPiotr Jasiukajtis {
116525c28e83SPiotr Jasiukajtis unsigned top;
116625c28e83SPiotr Jasiukajtis
116725c28e83SPiotr Jasiukajtis fpreg(uap, 0) = fpreg(uap, 1);
116825c28e83SPiotr Jasiukajtis fpreg(uap, 1) = fpreg(uap, 2);
116925c28e83SPiotr Jasiukajtis fpreg(uap, 2) = fpreg(uap, 3);
117025c28e83SPiotr Jasiukajtis fpreg(uap, 3) = fpreg(uap, 4);
117125c28e83SPiotr Jasiukajtis fpreg(uap, 4) = fpreg(uap, 5);
117225c28e83SPiotr Jasiukajtis fpreg(uap, 5) = fpreg(uap, 6);
117325c28e83SPiotr Jasiukajtis fpreg(uap, 6) = fpreg(uap, 7);
117425c28e83SPiotr Jasiukajtis #if defined(__amd64)
117525c28e83SPiotr Jasiukajtis top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10)
117625c28e83SPiotr Jasiukajtis & 0xe;
117725c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw |= (3 << top);
117825c28e83SPiotr Jasiukajtis top = (top + 2) & 0xe;
117925c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw =
118025c28e83SPiotr Jasiukajtis (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800)
118125c28e83SPiotr Jasiukajtis | (top << 10);
118225c28e83SPiotr Jasiukajtis #else
118325c28e83SPiotr Jasiukajtis top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >> 10)
118425c28e83SPiotr Jasiukajtis & 0xe;
118525c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] |= (3 << top);
118625c28e83SPiotr Jasiukajtis top = (top + 2) & 0xe;
118725c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] =
118825c28e83SPiotr Jasiukajtis (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] & ~0x3800)
118925c28e83SPiotr Jasiukajtis | (top << 10);
119025c28e83SPiotr Jasiukajtis #endif
119125c28e83SPiotr Jasiukajtis }
119225c28e83SPiotr Jasiukajtis
119325c28e83SPiotr Jasiukajtis /* push x onto the saved stack */
push(long double x,ucontext_t * uap)119425c28e83SPiotr Jasiukajtis static void push(long double x, ucontext_t *uap)
119525c28e83SPiotr Jasiukajtis {
119625c28e83SPiotr Jasiukajtis unsigned top;
119725c28e83SPiotr Jasiukajtis
119825c28e83SPiotr Jasiukajtis fpreg(uap, 7) = fpreg(uap, 6);
119925c28e83SPiotr Jasiukajtis fpreg(uap, 6) = fpreg(uap, 5);
120025c28e83SPiotr Jasiukajtis fpreg(uap, 5) = fpreg(uap, 4);
120125c28e83SPiotr Jasiukajtis fpreg(uap, 4) = fpreg(uap, 3);
120225c28e83SPiotr Jasiukajtis fpreg(uap, 3) = fpreg(uap, 2);
120325c28e83SPiotr Jasiukajtis fpreg(uap, 2) = fpreg(uap, 1);
120425c28e83SPiotr Jasiukajtis fpreg(uap, 1) = fpreg(uap, 0);
120525c28e83SPiotr Jasiukajtis fpreg(uap, 0) = x;
120625c28e83SPiotr Jasiukajtis #if defined(__amd64)
120725c28e83SPiotr Jasiukajtis top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10)
120825c28e83SPiotr Jasiukajtis & 0xe;
120925c28e83SPiotr Jasiukajtis top = (top - 2) & 0xe;
121025c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw &= ~(3 << top);
121125c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw =
121225c28e83SPiotr Jasiukajtis (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800)
121325c28e83SPiotr Jasiukajtis | (top << 10);
121425c28e83SPiotr Jasiukajtis #else
121525c28e83SPiotr Jasiukajtis top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >> 10)
121625c28e83SPiotr Jasiukajtis & 0xe;
121725c28e83SPiotr Jasiukajtis top = (top - 2) & 0xe;
121825c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] &= ~(3 << top);
121925c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] =
122025c28e83SPiotr Jasiukajtis (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] & ~0x3800)
122125c28e83SPiotr Jasiukajtis | (top << 10);
122225c28e83SPiotr Jasiukajtis #endif
122325c28e83SPiotr Jasiukajtis }
122425c28e83SPiotr Jasiukajtis
122525c28e83SPiotr Jasiukajtis /* scale factors for exponent wrapping */
122625c28e83SPiotr Jasiukajtis static const float
122725c28e83SPiotr Jasiukajtis fun = 7.922816251e+28f, /* 2^96 */
122825c28e83SPiotr Jasiukajtis fov = 1.262177448e-29f; /* 2^-96 */
122925c28e83SPiotr Jasiukajtis static const double
123025c28e83SPiotr Jasiukajtis dun = 1.552518092300708935e+231, /* 2^768 */
123125c28e83SPiotr Jasiukajtis dov = 6.441148769597133308e-232; /* 2^-768 */
123225c28e83SPiotr Jasiukajtis
123325c28e83SPiotr Jasiukajtis /*
123425c28e83SPiotr Jasiukajtis * Store the specified result; if no result is given but the exception
123525c28e83SPiotr Jasiukajtis * is underflow or overflow, use the default trapped result
123625c28e83SPiotr Jasiukajtis */
123725c28e83SPiotr Jasiukajtis void
__fex_st_result(siginfo_t * sip,ucontext_t * uap,fex_info_t * info)123825c28e83SPiotr Jasiukajtis __fex_st_result(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
123925c28e83SPiotr Jasiukajtis {
124025c28e83SPiotr Jasiukajtis fex_numeric_t r;
124125c28e83SPiotr Jasiukajtis unsigned long ex, op, ea, stack;
124225c28e83SPiotr Jasiukajtis
124325c28e83SPiotr Jasiukajtis /* get the exception type, opcode, and data address */
124425c28e83SPiotr Jasiukajtis ex = sip->si_code;
124525c28e83SPiotr Jasiukajtis #if defined(__amd64)
124625c28e83SPiotr Jasiukajtis op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
124725c28e83SPiotr Jasiukajtis ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp; /*???*/
124825c28e83SPiotr Jasiukajtis #else
124925c28e83SPiotr Jasiukajtis op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
125025c28e83SPiotr Jasiukajtis ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
125125c28e83SPiotr Jasiukajtis #endif
125225c28e83SPiotr Jasiukajtis
125325c28e83SPiotr Jasiukajtis /* if the instruction is a compare, set the condition codes
125425c28e83SPiotr Jasiukajtis to unordered and update the stack */
125525c28e83SPiotr Jasiukajtis switch (op & 0x7f8) {
125625c28e83SPiotr Jasiukajtis case 0x010:
125725c28e83SPiotr Jasiukajtis case 0x050:
125825c28e83SPiotr Jasiukajtis case 0x090:
125925c28e83SPiotr Jasiukajtis case 0x0d0:
126025c28e83SPiotr Jasiukajtis case 0x210:
126125c28e83SPiotr Jasiukajtis case 0x250:
126225c28e83SPiotr Jasiukajtis case 0x290:
126325c28e83SPiotr Jasiukajtis case 0x410:
126425c28e83SPiotr Jasiukajtis case 0x450:
126525c28e83SPiotr Jasiukajtis case 0x490:
126625c28e83SPiotr Jasiukajtis case 0x4d0:
126725c28e83SPiotr Jasiukajtis case 0x5e0:
126825c28e83SPiotr Jasiukajtis case 0x610:
126925c28e83SPiotr Jasiukajtis case 0x650:
127025c28e83SPiotr Jasiukajtis case 0x690:
127125c28e83SPiotr Jasiukajtis /* f[u]com */
127225c28e83SPiotr Jasiukajtis #if defined(__amd64)
127325c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
127425c28e83SPiotr Jasiukajtis #else
127525c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
127625c28e83SPiotr Jasiukajtis #endif
127725c28e83SPiotr Jasiukajtis return;
127825c28e83SPiotr Jasiukajtis
127925c28e83SPiotr Jasiukajtis case 0x018:
128025c28e83SPiotr Jasiukajtis case 0x058:
128125c28e83SPiotr Jasiukajtis case 0x098:
128225c28e83SPiotr Jasiukajtis case 0x0d8:
128325c28e83SPiotr Jasiukajtis case 0x218:
128425c28e83SPiotr Jasiukajtis case 0x258:
128525c28e83SPiotr Jasiukajtis case 0x298:
128625c28e83SPiotr Jasiukajtis case 0x418:
128725c28e83SPiotr Jasiukajtis case 0x458:
128825c28e83SPiotr Jasiukajtis case 0x498:
128925c28e83SPiotr Jasiukajtis case 0x4d8:
129025c28e83SPiotr Jasiukajtis case 0x5e8:
129125c28e83SPiotr Jasiukajtis case 0x618:
129225c28e83SPiotr Jasiukajtis case 0x658:
129325c28e83SPiotr Jasiukajtis case 0x698:
129425c28e83SPiotr Jasiukajtis case 0x6d0:
129525c28e83SPiotr Jasiukajtis /* f[u]comp */
129625c28e83SPiotr Jasiukajtis #if defined(__amd64)
129725c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
129825c28e83SPiotr Jasiukajtis #else
129925c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
130025c28e83SPiotr Jasiukajtis #endif
130125c28e83SPiotr Jasiukajtis pop(uap);
130225c28e83SPiotr Jasiukajtis return;
130325c28e83SPiotr Jasiukajtis
130425c28e83SPiotr Jasiukajtis case 0x2e8:
130525c28e83SPiotr Jasiukajtis case 0x6d8:
130625c28e83SPiotr Jasiukajtis /* f[u]compp */
130725c28e83SPiotr Jasiukajtis #if defined(__amd64)
130825c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
130925c28e83SPiotr Jasiukajtis #else
131025c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
131125c28e83SPiotr Jasiukajtis #endif
131225c28e83SPiotr Jasiukajtis pop(uap);
131325c28e83SPiotr Jasiukajtis pop(uap);
131425c28e83SPiotr Jasiukajtis return;
131525c28e83SPiotr Jasiukajtis
131625c28e83SPiotr Jasiukajtis case 0x1e0:
131725c28e83SPiotr Jasiukajtis if (op == 0x1e4) { /* ftst */
131825c28e83SPiotr Jasiukajtis #if defined(__amd64)
131925c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
132025c28e83SPiotr Jasiukajtis #else
132125c28e83SPiotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
132225c28e83SPiotr Jasiukajtis #endif
132325c28e83SPiotr Jasiukajtis return;
132425c28e83SPiotr Jasiukajtis }
132525c28e83SPiotr Jasiukajtis break;
132625c28e83SPiotr Jasiukajtis
132725c28e83SPiotr Jasiukajtis case 0x3e8:
132825c28e83SPiotr Jasiukajtis case 0x3f0:
132925c28e83SPiotr Jasiukajtis /* f[u]comi */
133025c28e83SPiotr Jasiukajtis #if defined(__amd64)
133125c28e83SPiotr Jasiukajtis uap->uc_mcontext.gregs[REG_PS] |= 0x45;
133225c28e83SPiotr Jasiukajtis #else
133325c28e83SPiotr Jasiukajtis uap->uc_mcontext.gregs[EFL] |= 0x45;
133425c28e83SPiotr Jasiukajtis #endif
133525c28e83SPiotr Jasiukajtis return;
133625c28e83SPiotr Jasiukajtis
133725c28e83SPiotr Jasiukajtis case 0x7e8:
133825c28e83SPiotr Jasiukajtis case 0x7f0:
133925c28e83SPiotr Jasiukajtis /* f[u]comip */
134025c28e83SPiotr Jasiukajtis #if defined(__amd64)
134125c28e83SPiotr Jasiukajtis uap->uc_mcontext.gregs[REG_PS] |= 0x45;
134225c28e83SPiotr Jasiukajtis #else
134325c28e83SPiotr Jasiukajtis uap->uc_mcontext.gregs[EFL] |= 0x45;
134425c28e83SPiotr Jasiukajtis #endif
134525c28e83SPiotr Jasiukajtis pop(uap);
134625c28e83SPiotr Jasiukajtis return;
134725c28e83SPiotr Jasiukajtis }
134825c28e83SPiotr Jasiukajtis
134925c28e83SPiotr Jasiukajtis /* if there is no result available and the exception is overflow
135025c28e83SPiotr Jasiukajtis or underflow, use the wrapped result */
135125c28e83SPiotr Jasiukajtis r = info->res;
135225c28e83SPiotr Jasiukajtis if (r.type == fex_nodata) {
135325c28e83SPiotr Jasiukajtis if (ex == FPE_FLTOVF || ex == FPE_FLTUND) {
135425c28e83SPiotr Jasiukajtis /* for store instructions, do the scaling and store */
135525c28e83SPiotr Jasiukajtis switch (op & 0x7f8) {
135625c28e83SPiotr Jasiukajtis case 0x110:
135725c28e83SPiotr Jasiukajtis case 0x118:
135825c28e83SPiotr Jasiukajtis case 0x150:
135925c28e83SPiotr Jasiukajtis case 0x158:
136025c28e83SPiotr Jasiukajtis case 0x190:
136125c28e83SPiotr Jasiukajtis case 0x198:
136225c28e83SPiotr Jasiukajtis if (!ea)
136325c28e83SPiotr Jasiukajtis return;
136425c28e83SPiotr Jasiukajtis if (ex == FPE_FLTOVF)
136525c28e83SPiotr Jasiukajtis *(float *)ea = (fpreg(uap, 0) * fov) * fov;
136625c28e83SPiotr Jasiukajtis else
136725c28e83SPiotr Jasiukajtis *(float *)ea = (fpreg(uap, 0) * fun) * fun;
136825c28e83SPiotr Jasiukajtis if ((op & 8) != 0)
136925c28e83SPiotr Jasiukajtis pop(uap);
137025c28e83SPiotr Jasiukajtis break;
137125c28e83SPiotr Jasiukajtis
137225c28e83SPiotr Jasiukajtis case 0x510:
137325c28e83SPiotr Jasiukajtis case 0x518:
137425c28e83SPiotr Jasiukajtis case 0x550:
137525c28e83SPiotr Jasiukajtis case 0x558:
137625c28e83SPiotr Jasiukajtis case 0x590:
137725c28e83SPiotr Jasiukajtis case 0x598:
137825c28e83SPiotr Jasiukajtis if (!ea)
137925c28e83SPiotr Jasiukajtis return;
138025c28e83SPiotr Jasiukajtis if (ex == FPE_FLTOVF)
138125c28e83SPiotr Jasiukajtis *(double *)ea = (fpreg(uap, 0) * dov) * dov;
138225c28e83SPiotr Jasiukajtis else
138325c28e83SPiotr Jasiukajtis *(double *)ea = (fpreg(uap, 0) * dun) * dun;
138425c28e83SPiotr Jasiukajtis if ((op & 8) != 0)
138525c28e83SPiotr Jasiukajtis pop(uap);
138625c28e83SPiotr Jasiukajtis break;
138725c28e83SPiotr Jasiukajtis }
138825c28e83SPiotr Jasiukajtis }
138925c28e83SPiotr Jasiukajtis #ifdef DEBUG
139025c28e83SPiotr Jasiukajtis else if (ex != FPE_FLTRES)
139125c28e83SPiotr Jasiukajtis printf("No result supplied, stack may be hosed\n");
139225c28e83SPiotr Jasiukajtis #endif
139325c28e83SPiotr Jasiukajtis return;
139425c28e83SPiotr Jasiukajtis }
139525c28e83SPiotr Jasiukajtis
139625c28e83SPiotr Jasiukajtis /* otherwise convert the supplied result to the correct type,
139725c28e83SPiotr Jasiukajtis put it in the destination, and update the stack as need be */
139825c28e83SPiotr Jasiukajtis
139925c28e83SPiotr Jasiukajtis /* store instructions */
140025c28e83SPiotr Jasiukajtis switch (op & 0x7f8) {
140125c28e83SPiotr Jasiukajtis case 0x110:
140225c28e83SPiotr Jasiukajtis case 0x118:
140325c28e83SPiotr Jasiukajtis case 0x150:
140425c28e83SPiotr Jasiukajtis case 0x158:
140525c28e83SPiotr Jasiukajtis case 0x190:
140625c28e83SPiotr Jasiukajtis case 0x198:
140725c28e83SPiotr Jasiukajtis if (!ea)
140825c28e83SPiotr Jasiukajtis return;
140925c28e83SPiotr Jasiukajtis switch (r.type) {
141025c28e83SPiotr Jasiukajtis case fex_int:
141125c28e83SPiotr Jasiukajtis *(float *)ea = (float) r.val.i;
141225c28e83SPiotr Jasiukajtis break;
141325c28e83SPiotr Jasiukajtis
141425c28e83SPiotr Jasiukajtis case fex_llong:
141525c28e83SPiotr Jasiukajtis *(float *)ea = (float) r.val.l;
141625c28e83SPiotr Jasiukajtis break;
141725c28e83SPiotr Jasiukajtis
141825c28e83SPiotr Jasiukajtis case fex_float:
141925c28e83SPiotr Jasiukajtis *(float *)ea = r.val.f;
142025c28e83SPiotr Jasiukajtis break;
142125c28e83SPiotr Jasiukajtis
142225c28e83SPiotr Jasiukajtis case fex_double:
142325c28e83SPiotr Jasiukajtis *(float *)ea = (float) r.val.d;
142425c28e83SPiotr Jasiukajtis break;
142525c28e83SPiotr Jasiukajtis
142625c28e83SPiotr Jasiukajtis case fex_ldouble:
142725c28e83SPiotr Jasiukajtis *(float *)ea = (float) r.val.q;
142825c28e83SPiotr Jasiukajtis break;
142925c28e83SPiotr Jasiukajtis
143025c28e83SPiotr Jasiukajtis default:
143125c28e83SPiotr Jasiukajtis break;
143225c28e83SPiotr Jasiukajtis }
143325c28e83SPiotr Jasiukajtis if (ex != FPE_FLTRES && (op & 8) != 0)
143425c28e83SPiotr Jasiukajtis pop(uap);
143525c28e83SPiotr Jasiukajtis return;
143625c28e83SPiotr Jasiukajtis
143725c28e83SPiotr Jasiukajtis case 0x310:
143825c28e83SPiotr Jasiukajtis case 0x318:
143925c28e83SPiotr Jasiukajtis case 0x350:
144025c28e83SPiotr Jasiukajtis case 0x358:
144125c28e83SPiotr Jasiukajtis case 0x390:
144225c28e83SPiotr Jasiukajtis case 0x398:
144325c28e83SPiotr Jasiukajtis if (!ea)
144425c28e83SPiotr Jasiukajtis return;
144525c28e83SPiotr Jasiukajtis switch (r.type) {
144625c28e83SPiotr Jasiukajtis case fex_int:
144725c28e83SPiotr Jasiukajtis *(int *)ea = r.val.i;
144825c28e83SPiotr Jasiukajtis break;
144925c28e83SPiotr Jasiukajtis
145025c28e83SPiotr Jasiukajtis case fex_llong:
145125c28e83SPiotr Jasiukajtis *(int *)ea = (int) r.val.l;
145225c28e83SPiotr Jasiukajtis break;
145325c28e83SPiotr Jasiukajtis
145425c28e83SPiotr Jasiukajtis case fex_float:
145525c28e83SPiotr Jasiukajtis *(int *)ea = (int) r.val.f;
145625c28e83SPiotr Jasiukajtis break;
145725c28e83SPiotr Jasiukajtis
145825c28e83SPiotr Jasiukajtis case fex_double:
145925c28e83SPiotr Jasiukajtis *(int *)ea = (int) r.val.d;
146025c28e83SPiotr Jasiukajtis break;
146125c28e83SPiotr Jasiukajtis
146225c28e83SPiotr Jasiukajtis case fex_ldouble:
146325c28e83SPiotr Jasiukajtis *(int *)ea = (int) r.val.q;
146425c28e83SPiotr Jasiukajtis break;
146525c28e83SPiotr Jasiukajtis
146625c28e83SPiotr Jasiukajtis default:
146725c28e83SPiotr Jasiukajtis break;
146825c28e83SPiotr Jasiukajtis }
146925c28e83SPiotr Jasiukajtis if (ex != FPE_FLTRES && (op & 8) != 0)
147025c28e83SPiotr Jasiukajtis pop(uap);
147125c28e83SPiotr Jasiukajtis return;
147225c28e83SPiotr Jasiukajtis
147325c28e83SPiotr Jasiukajtis case 0x510:
147425c28e83SPiotr Jasiukajtis case 0x518:
147525c28e83SPiotr Jasiukajtis case 0x550:
147625c28e83SPiotr Jasiukajtis case 0x558:
147725c28e83SPiotr Jasiukajtis case 0x590:
147825c28e83SPiotr Jasiukajtis case 0x598:
147925c28e83SPiotr Jasiukajtis if (!ea)
148025c28e83SPiotr Jasiukajtis return;
148125c28e83SPiotr Jasiukajtis switch (r.type) {
148225c28e83SPiotr Jasiukajtis case fex_int:
148325c28e83SPiotr Jasiukajtis *(double *)ea = (double) r.val.i;
148425c28e83SPiotr Jasiukajtis break;
148525c28e83SPiotr Jasiukajtis
148625c28e83SPiotr Jasiukajtis case fex_llong:
148725c28e83SPiotr Jasiukajtis *(double *)ea = (double) r.val.l;
148825c28e83SPiotr Jasiukajtis break;
148925c28e83SPiotr Jasiukajtis
149025c28e83SPiotr Jasiukajtis case fex_float:
149125c28e83SPiotr Jasiukajtis *(double *)ea = (double) r.val.f;
149225c28e83SPiotr Jasiukajtis break;
149325c28e83SPiotr Jasiukajtis
149425c28e83SPiotr Jasiukajtis case fex_double:
149525c28e83SPiotr Jasiukajtis *(double *)ea = r.val.d;
149625c28e83SPiotr Jasiukajtis break;
149725c28e83SPiotr Jasiukajtis
149825c28e83SPiotr Jasiukajtis case fex_ldouble:
149925c28e83SPiotr Jasiukajtis *(double *)ea = (double) r.val.q;
150025c28e83SPiotr Jasiukajtis break;
150125c28e83SPiotr Jasiukajtis
150225c28e83SPiotr Jasiukajtis default:
150325c28e83SPiotr Jasiukajtis break;
150425c28e83SPiotr Jasiukajtis }
150525c28e83SPiotr Jasiukajtis if (ex != FPE_FLTRES && (op & 8) != 0)
150625c28e83SPiotr Jasiukajtis pop(uap);
150725c28e83SPiotr Jasiukajtis return;
150825c28e83SPiotr Jasiukajtis
150925c28e83SPiotr Jasiukajtis case 0x710:
151025c28e83SPiotr Jasiukajtis case 0x718:
151125c28e83SPiotr Jasiukajtis case 0x750:
151225c28e83SPiotr Jasiukajtis case 0x758:
151325c28e83SPiotr Jasiukajtis case 0x790:
151425c28e83SPiotr Jasiukajtis case 0x798:
151525c28e83SPiotr Jasiukajtis if (!ea)
151625c28e83SPiotr Jasiukajtis return;
151725c28e83SPiotr Jasiukajtis switch (r.type) {
151825c28e83SPiotr Jasiukajtis case fex_int:
151925c28e83SPiotr Jasiukajtis *(short *)ea = (short) r.val.i;
152025c28e83SPiotr Jasiukajtis break;
152125c28e83SPiotr Jasiukajtis
152225c28e83SPiotr Jasiukajtis case fex_llong:
152325c28e83SPiotr Jasiukajtis *(short *)ea = (short) r.val.l;
152425c28e83SPiotr Jasiukajtis break;
152525c28e83SPiotr Jasiukajtis
152625c28e83SPiotr Jasiukajtis case fex_float:
152725c28e83SPiotr Jasiukajtis *(short *)ea = (short) r.val.f;
152825c28e83SPiotr Jasiukajtis break;
152925c28e83SPiotr Jasiukajtis
153025c28e83SPiotr Jasiukajtis case fex_double:
153125c28e83SPiotr Jasiukajtis *(short *)ea = (short) r.val.d;
153225c28e83SPiotr Jasiukajtis break;
153325c28e83SPiotr Jasiukajtis
153425c28e83SPiotr Jasiukajtis case fex_ldouble:
153525c28e83SPiotr Jasiukajtis *(short *)ea = (short) r.val.q;
153625c28e83SPiotr Jasiukajtis break;
153725c28e83SPiotr Jasiukajtis
153825c28e83SPiotr Jasiukajtis default:
153925c28e83SPiotr Jasiukajtis break;
154025c28e83SPiotr Jasiukajtis }
154125c28e83SPiotr Jasiukajtis if (ex != FPE_FLTRES && (op & 8) != 0)
154225c28e83SPiotr Jasiukajtis pop(uap);
154325c28e83SPiotr Jasiukajtis return;
154425c28e83SPiotr Jasiukajtis
154525c28e83SPiotr Jasiukajtis case 0x730:
154625c28e83SPiotr Jasiukajtis case 0x770:
154725c28e83SPiotr Jasiukajtis case 0x7b0:
154825c28e83SPiotr Jasiukajtis /* fbstp; don't bother */
154925c28e83SPiotr Jasiukajtis if (ea && ex != FPE_FLTRES)
155025c28e83SPiotr Jasiukajtis pop(uap);
155125c28e83SPiotr Jasiukajtis return;
155225c28e83SPiotr Jasiukajtis
155325c28e83SPiotr Jasiukajtis case 0x738:
155425c28e83SPiotr Jasiukajtis case 0x778:
155525c28e83SPiotr Jasiukajtis case 0x7b8:
155625c28e83SPiotr Jasiukajtis if (!ea)
155725c28e83SPiotr Jasiukajtis return;
155825c28e83SPiotr Jasiukajtis switch (r.type) {
155925c28e83SPiotr Jasiukajtis case fex_int:
156025c28e83SPiotr Jasiukajtis *(long long *)ea = (long long) r.val.i;
156125c28e83SPiotr Jasiukajtis break;
156225c28e83SPiotr Jasiukajtis
156325c28e83SPiotr Jasiukajtis case fex_llong:
156425c28e83SPiotr Jasiukajtis *(long long *)ea = r.val.l;
156525c28e83SPiotr Jasiukajtis break;
156625c28e83SPiotr Jasiukajtis
156725c28e83SPiotr Jasiukajtis case fex_float:
156825c28e83SPiotr Jasiukajtis *(long long *)ea = (long long) r.val.f;
156925c28e83SPiotr Jasiukajtis break;
157025c28e83SPiotr Jasiukajtis
157125c28e83SPiotr Jasiukajtis case fex_double:
157225c28e83SPiotr Jasiukajtis *(long long *)ea = (long long) r.val.d;
157325c28e83SPiotr Jasiukajtis break;
157425c28e83SPiotr Jasiukajtis
157525c28e83SPiotr Jasiukajtis case fex_ldouble:
157625c28e83SPiotr Jasiukajtis *(long long *)ea = (long long) r.val.q;
157725c28e83SPiotr Jasiukajtis break;
157825c28e83SPiotr Jasiukajtis
157925c28e83SPiotr Jasiukajtis default:
158025c28e83SPiotr Jasiukajtis break;
158125c28e83SPiotr Jasiukajtis }
158225c28e83SPiotr Jasiukajtis if (ex != FPE_FLTRES)
158325c28e83SPiotr Jasiukajtis pop(uap);
158425c28e83SPiotr Jasiukajtis return;
158525c28e83SPiotr Jasiukajtis }
158625c28e83SPiotr Jasiukajtis
158725c28e83SPiotr Jasiukajtis /* for all other instructions, the result goes into a register */
158825c28e83SPiotr Jasiukajtis switch (r.type) {
158925c28e83SPiotr Jasiukajtis case fex_int:
159025c28e83SPiotr Jasiukajtis r.val.q = (long double) r.val.i;
159125c28e83SPiotr Jasiukajtis break;
159225c28e83SPiotr Jasiukajtis
159325c28e83SPiotr Jasiukajtis case fex_llong:
159425c28e83SPiotr Jasiukajtis r.val.q = (long double) r.val.l;
159525c28e83SPiotr Jasiukajtis break;
159625c28e83SPiotr Jasiukajtis
159725c28e83SPiotr Jasiukajtis case fex_float:
159825c28e83SPiotr Jasiukajtis r.val.q = (long double) r.val.f;
159925c28e83SPiotr Jasiukajtis break;
160025c28e83SPiotr Jasiukajtis
160125c28e83SPiotr Jasiukajtis case fex_double:
160225c28e83SPiotr Jasiukajtis r.val.q = (long double) r.val.d;
160325c28e83SPiotr Jasiukajtis break;
160425c28e83SPiotr Jasiukajtis
160525c28e83SPiotr Jasiukajtis default:
160625c28e83SPiotr Jasiukajtis break;
160725c28e83SPiotr Jasiukajtis }
160825c28e83SPiotr Jasiukajtis
160925c28e83SPiotr Jasiukajtis /* for load instructions, push the result onto the stack */
161025c28e83SPiotr Jasiukajtis switch (op & 0x7f8) {
161125c28e83SPiotr Jasiukajtis case 0x100:
161225c28e83SPiotr Jasiukajtis case 0x140:
161325c28e83SPiotr Jasiukajtis case 0x180:
161425c28e83SPiotr Jasiukajtis case 0x500:
161525c28e83SPiotr Jasiukajtis case 0x540:
161625c28e83SPiotr Jasiukajtis case 0x580:
161725c28e83SPiotr Jasiukajtis if (ea)
161825c28e83SPiotr Jasiukajtis push(r.val.q, uap);
161925c28e83SPiotr Jasiukajtis return;
162025c28e83SPiotr Jasiukajtis }
162125c28e83SPiotr Jasiukajtis
162225c28e83SPiotr Jasiukajtis /* for all other instructions, if the exception is overflow,
162325c28e83SPiotr Jasiukajtis underflow, or inexact, the stack has already been updated */
162425c28e83SPiotr Jasiukajtis stack = (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES);
162525c28e83SPiotr Jasiukajtis switch (op & 0x7f8) {
162625c28e83SPiotr Jasiukajtis case 0x1f0: /* oddballs */
162725c28e83SPiotr Jasiukajtis switch (op) {
162825c28e83SPiotr Jasiukajtis case 0x1f1: /* fyl2x */
162925c28e83SPiotr Jasiukajtis case 0x1f3: /* fpatan */
163025c28e83SPiotr Jasiukajtis case 0x1f9: /* fyl2xp1 */
163125c28e83SPiotr Jasiukajtis /* pop the stack, leaving the result in st */
163225c28e83SPiotr Jasiukajtis if (!stack)
163325c28e83SPiotr Jasiukajtis pop(uap);
163425c28e83SPiotr Jasiukajtis fpreg(uap, 0) = r.val.q;
163525c28e83SPiotr Jasiukajtis return;
163625c28e83SPiotr Jasiukajtis
163725c28e83SPiotr Jasiukajtis case 0x1f2: /* fpatan */
163825c28e83SPiotr Jasiukajtis /* fptan pushes 1.0 afterward */
163925c28e83SPiotr Jasiukajtis if (stack)
164025c28e83SPiotr Jasiukajtis fpreg(uap, 1) = r.val.q;
164125c28e83SPiotr Jasiukajtis else {
164225c28e83SPiotr Jasiukajtis fpreg(uap, 0) = r.val.q;
164325c28e83SPiotr Jasiukajtis push(1.0L, uap);
164425c28e83SPiotr Jasiukajtis }
164525c28e83SPiotr Jasiukajtis return;
164625c28e83SPiotr Jasiukajtis
164725c28e83SPiotr Jasiukajtis case 0x1f4: /* fxtract */
164825c28e83SPiotr Jasiukajtis case 0x1fb: /* fsincos */
164925c28e83SPiotr Jasiukajtis /* leave the supplied result in st */
165025c28e83SPiotr Jasiukajtis if (stack)
165125c28e83SPiotr Jasiukajtis fpreg(uap, 0) = r.val.q;
165225c28e83SPiotr Jasiukajtis else {
165325c28e83SPiotr Jasiukajtis fpreg(uap, 0) = 0.0; /* punt */
165425c28e83SPiotr Jasiukajtis push(r.val.q, uap);
165525c28e83SPiotr Jasiukajtis }
165625c28e83SPiotr Jasiukajtis return;
165725c28e83SPiotr Jasiukajtis }
165825c28e83SPiotr Jasiukajtis
165925c28e83SPiotr Jasiukajtis /* all others leave the stack alone and the result in st */
166025c28e83SPiotr Jasiukajtis fpreg(uap, 0) = r.val.q;
166125c28e83SPiotr Jasiukajtis return;
166225c28e83SPiotr Jasiukajtis
166325c28e83SPiotr Jasiukajtis case 0x4c0:
166425c28e83SPiotr Jasiukajtis case 0x4c8:
166525c28e83SPiotr Jasiukajtis case 0x4e0:
166625c28e83SPiotr Jasiukajtis case 0x4e8:
166725c28e83SPiotr Jasiukajtis case 0x4f0:
166825c28e83SPiotr Jasiukajtis case 0x4f8:
166925c28e83SPiotr Jasiukajtis fpreg(uap, op & 7) = r.val.q;
167025c28e83SPiotr Jasiukajtis return;
167125c28e83SPiotr Jasiukajtis
167225c28e83SPiotr Jasiukajtis case 0x6c0:
167325c28e83SPiotr Jasiukajtis case 0x6c8:
167425c28e83SPiotr Jasiukajtis case 0x6e0:
167525c28e83SPiotr Jasiukajtis case 0x6e8:
167625c28e83SPiotr Jasiukajtis case 0x6f0:
167725c28e83SPiotr Jasiukajtis case 0x6f8:
167825c28e83SPiotr Jasiukajtis /* stack is popped afterward */
167925c28e83SPiotr Jasiukajtis if (stack)
168025c28e83SPiotr Jasiukajtis fpreg(uap, (op - 1) & 7) = r.val.q;
168125c28e83SPiotr Jasiukajtis else {
168225c28e83SPiotr Jasiukajtis fpreg(uap, op & 7) = r.val.q;
168325c28e83SPiotr Jasiukajtis pop(uap);
168425c28e83SPiotr Jasiukajtis }
168525c28e83SPiotr Jasiukajtis return;
168625c28e83SPiotr Jasiukajtis
168725c28e83SPiotr Jasiukajtis default:
168825c28e83SPiotr Jasiukajtis fpreg(uap, 0) = r.val.q;
168925c28e83SPiotr Jasiukajtis return;
169025c28e83SPiotr Jasiukajtis }
169125c28e83SPiotr Jasiukajtis }
1692