summaryrefslogtreecommitdiffstats
path: root/private/fp32/tran/i386/87except.c
blob: f350d92977795d90cc98e91a441c60de14627342 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/***
*87except.c - floating point exception handling
*
*	Copyright (c) 1991-1991, Microsoft Corporation.	All rights reserved.
*
*Purpose:
*
*Revision History:
*   8-24-91	GDP	written
*   9-26-91	GDP	changed DOMAIN error handling
*   1-29-91	GDP	renamed to 87exept.c
*   3-15-92	GDP	support raising exceptions
*
*******************************************************************************/
#include <errno.h>
#include <math.h>
#include <trans.h>


#define _DOMAIN_QNAN	7 /* should be in sync with elem87.inc */
#define _INEXACT	8 /* should be in sync with elem87.inc */

int _matherr_flag;
extern void _raise_exc(_FPIEEE_RECORD *prec,unsigned int *pcw,
    int flags, int opcode, double *parg1, double *presult);
extern void _set_errno(int matherrtype);
extern int _handle_exc(unsigned int flags, double * presult, unsigned int cw);




/***
*double _87except(struct _exception *except, unsigned int *cw)
*
*Purpose:
*   Handle floating point exceptions.
*
*Entry:
*
*Exit:
*
*Exceptions:
*******************************************************************************/

void _87except(int opcode, struct _exception *exc, unsigned short *pcw16)
{
    int fixed;
    unsigned int flags;
    unsigned int cw, *pcw;

    //
    // convert fp control word into an unsigned int
    //

    cw = *pcw16;
    pcw = &cw;

    switch (exc->type) {
    case _DOMAIN:
    case _TLOSS:
	flags = FP_I;
	break;
    case _OVERFLOW:
	flags = FP_O | FP_P;
	break;
    case _UNDERFLOW:
	flags = FP_U | FP_P;
	break;
    case _SING:
	flags = FP_Z;
	break;
    case _INEXACT:
	flags = FP_P;
	break;
    case _DOMAIN_QNAN:
	exc->type = _DOMAIN;
	// no break
    default:
	flags = 0;
    }



    if (flags && _handle_exc(flags, &exc->retval, *pcw) == 0) {

	//
	// trap should be taken
	//

	_FPIEEE_RECORD rec;

	//
	// fill in operand2 info. The rest of rec will be
	// filled in by _raise_exc
	//

	switch (opcode) {
	case OP_POW:
	case OP_FMOD:
	case OP_ATAN2:
	    rec.Operand2.OperandValid = 1;
	    rec.Operand2.Format = _FpFormatFp64;
	    rec.Operand2.Value.Fp64Value = exc->arg2;
	    break;
	default:
	    rec.Operand2.OperandValid = 0;
	}

	_raise_exc(&rec,
		   pcw,
		   flags,
		   opcode,
		   &exc->arg1,
		   &exc->retval);
    }


    /* restore cw  */
    _rstorfp(*pcw);

    fixed = 0;

    if (exc->type != _INEXACT &&
	! _matherr_flag) {
	fixed = _matherr(exc);
    }
    if (!fixed) {
	_set_errno(exc->type);
    }

}