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

Linux Cross Reference
Linux/arch/i386/math-emu/reg_compare.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*---------------------------------------------------------------------------+
  2  |  reg_compare.c                                                            |
  3  |                                                                           |
  4  | Compare two floating point registers                                      |
  5  |                                                                           |
  6  | Copyright (C) 1992,1993,1994,1997                                         |
  7  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  8  |                  E-mail   billm@suburbia.net                              |
  9  |                                                                           |
 10  |                                                                           |
 11  +---------------------------------------------------------------------------*/
 12 
 13 /*---------------------------------------------------------------------------+
 14  | compare() is the core FPU_REG comparison function                         |
 15  +---------------------------------------------------------------------------*/
 16 
 17 #include "fpu_system.h"
 18 #include "exception.h"
 19 #include "fpu_emu.h"
 20 #include "control_w.h"
 21 #include "status_w.h"
 22 
 23 
 24 static int compare(FPU_REG const *b, int tagb)
 25 {
 26   int diff, exp0, expb;
 27   u_char                st0_tag;
 28   FPU_REG       *st0_ptr;
 29   FPU_REG       x, y;
 30   u_char                st0_sign, signb = getsign(b);
 31 
 32   st0_ptr = &st(0);
 33   st0_tag = FPU_gettag0();
 34   st0_sign = getsign(st0_ptr);
 35 
 36   if ( tagb == TAG_Special )
 37     tagb = FPU_Special(b);
 38   if ( st0_tag == TAG_Special )
 39     st0_tag = FPU_Special(st0_ptr);
 40 
 41   if ( ((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
 42        || ((tagb != TAG_Valid) && (tagb != TW_Denormal)) )
 43     {
 44       if ( st0_tag == TAG_Zero )
 45         {
 46           if ( tagb == TAG_Zero ) return COMP_A_eq_B;
 47           if ( tagb == TAG_Valid )
 48             return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
 49           if ( tagb == TW_Denormal )
 50             return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
 51             | COMP_Denormal;
 52         }
 53       else if ( tagb == TAG_Zero )
 54         {
 55           if ( st0_tag == TAG_Valid )
 56             return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
 57           if ( st0_tag == TW_Denormal )
 58             return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 59             | COMP_Denormal;
 60         }
 61 
 62       if ( st0_tag == TW_Infinity )
 63         {
 64           if ( (tagb == TAG_Valid) || (tagb == TAG_Zero) )
 65             return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
 66           else if ( tagb == TW_Denormal )
 67             return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 68               | COMP_Denormal;
 69           else if ( tagb == TW_Infinity )
 70             {
 71               /* The 80486 book says that infinities can be equal! */
 72               return (st0_sign == signb) ? COMP_A_eq_B :
 73                 ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
 74             }
 75           /* Fall through to the NaN code */
 76         }
 77       else if ( tagb == TW_Infinity )
 78         {
 79           if ( (st0_tag == TAG_Valid) || (st0_tag == TAG_Zero) )
 80             return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
 81           if ( st0_tag == TW_Denormal )
 82             return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
 83                 | COMP_Denormal;
 84           /* Fall through to the NaN code */
 85         }
 86 
 87       /* The only possibility now should be that one of the arguments
 88          is a NaN */
 89       if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) )
 90         {
 91           int signalling = 0, unsupported = 0;
 92           if ( st0_tag == TW_NaN )
 93             {
 94               signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000;
 95               unsupported = !((exponent(st0_ptr) == EXP_OVER)
 96                               && (st0_ptr->sigh & 0x80000000));
 97             }
 98           if ( tagb == TW_NaN )
 99             {
100               signalling |= (b->sigh & 0xc0000000) == 0x80000000;
101               unsupported |= !((exponent(b) == EXP_OVER)
102                                && (b->sigh & 0x80000000));
103             }
104           if ( signalling || unsupported )
105             return COMP_No_Comp | COMP_SNaN | COMP_NaN;
106           else
107             /* Neither is a signaling NaN */
108             return COMP_No_Comp | COMP_NaN;
109         }
110       
111       EXCEPTION(EX_Invalid);
112     }
113   
114   if (st0_sign != signb)
115     {
116       return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
117         | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
118             COMP_Denormal : 0);
119     }
120 
121   if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) )
122     {
123       FPU_to_exp16(st0_ptr, &x);
124       FPU_to_exp16(b, &y);
125       st0_ptr = &x;
126       b = &y;
127       exp0 = exponent16(st0_ptr);
128       expb = exponent16(b);
129     }
130   else
131     {
132       exp0 = exponent(st0_ptr);
133       expb = exponent(b);
134     }
135 
136 #ifdef PARANOID
137   if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
138   if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
139 #endif PARANOID
140 
141   diff = exp0 - expb;
142   if ( diff == 0 )
143     {
144       diff = st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
145                                               identical */
146       if ( diff == 0 )
147         {
148         diff = st0_ptr->sigl > b->sigl;
149         if ( diff == 0 )
150           diff = -(st0_ptr->sigl < b->sigl);
151         }
152     }
153 
154   if ( diff > 0 )
155     {
156       return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
157         | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
158             COMP_Denormal : 0);
159     }
160   if ( diff < 0 )
161     {
162       return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
163         | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
164             COMP_Denormal : 0);
165     }
166 
167   return COMP_A_eq_B
168     | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
169         COMP_Denormal : 0);
170 
171 }
172 
173 
174 /* This function requires that st(0) is not empty */
175 int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
176 {
177   int f, c;
178 
179   c = compare(loaded_data, loaded_tag);
180 
181   if (c & COMP_NaN)
182     {
183       EXCEPTION(EX_Invalid);
184       f = SW_C3 | SW_C2 | SW_C0;
185     }
186   else
187     switch (c & 7)
188       {
189       case COMP_A_lt_B:
190         f = SW_C0;
191         break;
192       case COMP_A_eq_B:
193         f = SW_C3;
194         break;
195       case COMP_A_gt_B:
196         f = 0;
197         break;
198       case COMP_No_Comp:
199         f = SW_C3 | SW_C2 | SW_C0;
200         break;
201 #ifdef PARANOID
202       default:
203         EXCEPTION(EX_INTERNAL|0x121);
204         f = SW_C3 | SW_C2 | SW_C0;
205         break;
206 #endif PARANOID
207       }
208   setcc(f);
209   if (c & COMP_Denormal)
210     {
211       return denormal_operand() < 0;
212     }
213   return 0;
214 }
215 
216 
217 static int compare_st_st(int nr)
218 {
219   int f, c;
220   FPU_REG *st_ptr;
221 
222   if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
223     {
224       setcc(SW_C3 | SW_C2 | SW_C0);
225       /* Stack fault */
226       EXCEPTION(EX_StackUnder);
227       return !(control_word & CW_Invalid);
228     }
229 
230   st_ptr = &st(nr);
231   c = compare(st_ptr, FPU_gettagi(nr));
232   if (c & COMP_NaN)
233     {
234       setcc(SW_C3 | SW_C2 | SW_C0);
235       EXCEPTION(EX_Invalid);
236       return !(control_word & CW_Invalid);
237     }
238   else
239     switch (c & 7)
240       {
241       case COMP_A_lt_B:
242         f = SW_C0;
243         break;
244       case COMP_A_eq_B:
245         f = SW_C3;
246         break;
247       case COMP_A_gt_B:
248         f = 0;
249         break;
250       case COMP_No_Comp:
251         f = SW_C3 | SW_C2 | SW_C0;
252         break;
253 #ifdef PARANOID
254       default:
255         EXCEPTION(EX_INTERNAL|0x122);
256         f = SW_C3 | SW_C2 | SW_C0;
257         break;
258 #endif PARANOID
259       }
260   setcc(f);
261   if (c & COMP_Denormal)
262     {
263       return denormal_operand() < 0;
264     }
265   return 0;
266 }
267 
268 
269 static int compare_u_st_st(int nr)
270 {
271   int f, c;
272   FPU_REG *st_ptr;
273 
274   if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
275     {
276       setcc(SW_C3 | SW_C2 | SW_C0);
277       /* Stack fault */
278       EXCEPTION(EX_StackUnder);
279       return !(control_word & CW_Invalid);
280     }
281 
282   st_ptr = &st(nr);
283   c = compare(st_ptr, FPU_gettagi(nr));
284   if (c & COMP_NaN)
285     {
286       setcc(SW_C3 | SW_C2 | SW_C0);
287       if (c & COMP_SNaN)       /* This is the only difference between
288                                   un-ordered and ordinary comparisons */
289         {
290           EXCEPTION(EX_Invalid);
291           return !(control_word & CW_Invalid);
292         }
293       return 0;
294     }
295   else
296     switch (c & 7)
297       {
298       case COMP_A_lt_B:
299         f = SW_C0;
300         break;
301       case COMP_A_eq_B:
302         f = SW_C3;
303         break;
304       case COMP_A_gt_B:
305         f = 0;
306         break;
307       case COMP_No_Comp:
308         f = SW_C3 | SW_C2 | SW_C0;
309         break;
310 #ifdef PARANOID
311       default:
312         EXCEPTION(EX_INTERNAL|0x123);
313         f = SW_C3 | SW_C2 | SW_C0;
314         break;
315 #endif PARANOID
316       }
317   setcc(f);
318   if (c & COMP_Denormal)
319     {
320       return denormal_operand() < 0;
321     }
322   return 0;
323 }
324 
325 /*---------------------------------------------------------------------------*/
326 
327 void fcom_st()
328 {
329   /* fcom st(i) */
330   compare_st_st(FPU_rm);
331 }
332 
333 
334 void fcompst()
335 {
336   /* fcomp st(i) */
337   if ( !compare_st_st(FPU_rm) )
338     FPU_pop();
339 }
340 
341 
342 void fcompp()
343 {
344   /* fcompp */
345   if (FPU_rm != 1)
346     {
347       FPU_illegal();
348       return;
349     }
350   if ( !compare_st_st(1) )
351       poppop();
352 }
353 
354 
355 void fucom_()
356 {
357   /* fucom st(i) */
358   compare_u_st_st(FPU_rm);
359 
360 }
361 
362 
363 void fucomp()
364 {
365   /* fucomp st(i) */
366   if ( !compare_u_st_st(FPU_rm) )
367     FPU_pop();
368 }
369 
370 
371 void fucompp()
372 {
373   /* fucompp */
374   if (FPU_rm == 1)
375     {
376       if ( !compare_u_st_st(1) )
377         poppop();
378     }
379   else
380     FPU_illegal();
381 }
382 

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

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.