Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/math-emu/reg_divide.c
26451 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*---------------------------------------------------------------------------+
3
| reg_divide.c |
4
| |
5
| Divide one FPU_REG by another and put the result in a destination FPU_REG.|
6
| |
7
| Copyright (C) 1996 |
8
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
9
| E-mail [email protected] |
10
| |
11
| Return value is the tag of the answer, or-ed with FPU_Exception if |
12
| one was raised, or -1 on internal error. |
13
| |
14
+---------------------------------------------------------------------------*/
15
16
/*---------------------------------------------------------------------------+
17
| The destination may be any FPU_REG, including one of the source FPU_REGs. |
18
+---------------------------------------------------------------------------*/
19
20
#include "exception.h"
21
#include "reg_constant.h"
22
#include "fpu_emu.h"
23
#include "fpu_system.h"
24
25
/*
26
Divide one register by another and put the result into a third register.
27
*/
28
int FPU_div(int flags, int rm, int control_w)
29
{
30
FPU_REG x, y;
31
FPU_REG const *a, *b, *st0_ptr, *st_ptr;
32
FPU_REG *dest;
33
u_char taga, tagb, signa, signb, sign, saved_sign;
34
int tag, deststnr;
35
36
if (flags & DEST_RM)
37
deststnr = rm;
38
else
39
deststnr = 0;
40
41
if (flags & REV) {
42
b = &st(0);
43
st0_ptr = b;
44
tagb = FPU_gettag0();
45
if (flags & LOADED) {
46
a = (FPU_REG *) rm;
47
taga = flags & 0x0f;
48
} else {
49
a = &st(rm);
50
st_ptr = a;
51
taga = FPU_gettagi(rm);
52
}
53
} else {
54
a = &st(0);
55
st0_ptr = a;
56
taga = FPU_gettag0();
57
if (flags & LOADED) {
58
b = (FPU_REG *) rm;
59
tagb = flags & 0x0f;
60
} else {
61
b = &st(rm);
62
st_ptr = b;
63
tagb = FPU_gettagi(rm);
64
}
65
}
66
67
signa = getsign(a);
68
signb = getsign(b);
69
70
sign = signa ^ signb;
71
72
dest = &st(deststnr);
73
saved_sign = getsign(dest);
74
75
if (!(taga | tagb)) {
76
/* Both regs Valid, this should be the most common case. */
77
reg_copy(a, &x);
78
reg_copy(b, &y);
79
setpositive(&x);
80
setpositive(&y);
81
tag = FPU_u_div(&x, &y, dest, control_w, sign);
82
83
if (tag < 0)
84
return tag;
85
86
FPU_settagi(deststnr, tag);
87
return tag;
88
}
89
90
if (taga == TAG_Special)
91
taga = FPU_Special(a);
92
if (tagb == TAG_Special)
93
tagb = FPU_Special(b);
94
95
if (((taga == TAG_Valid) && (tagb == TW_Denormal))
96
|| ((taga == TW_Denormal) && (tagb == TAG_Valid))
97
|| ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
98
if (denormal_operand() < 0)
99
return FPU_Exception;
100
101
FPU_to_exp16(a, &x);
102
FPU_to_exp16(b, &y);
103
tag = FPU_u_div(&x, &y, dest, control_w, sign);
104
if (tag < 0)
105
return tag;
106
107
FPU_settagi(deststnr, tag);
108
return tag;
109
} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
110
if (tagb != TAG_Zero) {
111
/* Want to find Zero/Valid */
112
if (tagb == TW_Denormal) {
113
if (denormal_operand() < 0)
114
return FPU_Exception;
115
}
116
117
/* The result is zero. */
118
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
119
setsign(dest, sign);
120
return TAG_Zero;
121
}
122
/* We have an exception condition, either 0/0 or Valid/Zero. */
123
if (taga == TAG_Zero) {
124
/* 0/0 */
125
return arith_invalid(deststnr);
126
}
127
/* Valid/Zero */
128
return FPU_divide_by_zero(deststnr, sign);
129
}
130
/* Must have infinities, NaNs, etc */
131
else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
132
if (flags & LOADED)
133
return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0,
134
st0_ptr);
135
136
if (flags & DEST_RM) {
137
int tag;
138
tag = FPU_gettag0();
139
if (tag == TAG_Special)
140
tag = FPU_Special(st0_ptr);
141
return real_2op_NaN(st0_ptr, tag, rm,
142
(flags & REV) ? st0_ptr : &st(rm));
143
} else {
144
int tag;
145
tag = FPU_gettagi(rm);
146
if (tag == TAG_Special)
147
tag = FPU_Special(&st(rm));
148
return real_2op_NaN(&st(rm), tag, 0,
149
(flags & REV) ? st0_ptr : &st(rm));
150
}
151
} else if (taga == TW_Infinity) {
152
if (tagb == TW_Infinity) {
153
/* infinity/infinity */
154
return arith_invalid(deststnr);
155
} else {
156
/* tagb must be Valid or Zero */
157
if ((tagb == TW_Denormal) && (denormal_operand() < 0))
158
return FPU_Exception;
159
160
/* Infinity divided by Zero or Valid does
161
not raise and exception, but returns Infinity */
162
FPU_copy_to_regi(a, TAG_Special, deststnr);
163
setsign(dest, sign);
164
return taga;
165
}
166
} else if (tagb == TW_Infinity) {
167
if ((taga == TW_Denormal) && (denormal_operand() < 0))
168
return FPU_Exception;
169
170
/* The result is zero. */
171
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
172
setsign(dest, sign);
173
return TAG_Zero;
174
}
175
#ifdef PARANOID
176
else {
177
EXCEPTION(EX_INTERNAL | 0x102);
178
return FPU_Exception;
179
}
180
#endif /* PARANOID */
181
182
return 0;
183
}
184
185