~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/math-emu/reg_divide.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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  +---------------------------------------------------------------------------*/
 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php