Merge branch 'clockevents/4.21' of http://git.linaro.org/people/daniel.lezcano/linux...
[linux/fpc-iii.git] / arch / x86 / math-emu / reg_divide.c
blob08c2f6de0288b070d3773b556ff9313250cdb727
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 billm@jacobi.maths.monash.edu.au |
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 +---------------------------------------------------------------------------*/
16 /*---------------------------------------------------------------------------+
17 | The destination may be any FPU_REG, including one of the source FPU_REGs. |
18 +---------------------------------------------------------------------------*/
20 #include "exception.h"
21 #include "reg_constant.h"
22 #include "fpu_emu.h"
23 #include "fpu_system.h"
26 Divide one register by another and put the result into a third register.
28 int FPU_div(int flags, int rm, int control_w)
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;
36 if (flags & DEST_RM)
37 deststnr = rm;
38 else
39 deststnr = 0;
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);
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);
67 signa = getsign(a);
68 signb = getsign(b);
70 sign = signa ^ signb;
72 dest = &st(deststnr);
73 saved_sign = getsign(dest);
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);
83 if (tag < 0)
84 return tag;
86 FPU_settagi(deststnr, tag);
87 return tag;
90 if (taga == TAG_Special)
91 taga = FPU_Special(a);
92 if (tagb == TAG_Special)
93 tagb = FPU_Special(b);
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;
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;
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;
117 /* The result is zero. */
118 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
119 setsign(dest, sign);
120 return TAG_Zero;
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);
127 /* Valid/Zero */
128 return FPU_divide_by_zero(deststnr, sign);
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);
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));
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;
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;
166 } else if (tagb == TW_Infinity) {
167 if ((taga == TW_Denormal) && (denormal_operand() < 0))
168 return FPU_Exception;
170 /* The result is zero. */
171 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
172 setsign(dest, sign);
173 return TAG_Zero;
175 #ifdef PARANOID
176 else {
177 EXCEPTION(EX_INTERNAL | 0x102);
178 return FPU_Exception;
180 #endif /* PARANOID */
182 return 0;