1 /*---------------------------------------------------------------------------+
4 | Compare two floating point registers |
6 | Copyright (C) 1992,1993,1994,1997 |
7 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8 | E-mail billm@suburbia.net |
11 +---------------------------------------------------------------------------*/
13 /*---------------------------------------------------------------------------+
14 | compare() is the core FPU_REG comparison function |
15 +---------------------------------------------------------------------------*/
17 #include "fpu_system.h"
18 #include "exception.h"
20 #include "control_w.h"
24 static int compare(FPU_REG const *b, int tagb)
30 u_char st0_sign, signb = getsign(b);
33 st0_tag = FPU_gettag0();
34 st0_sign = getsign(st0_ptr);
36 if ( tagb == TAG_Special )
37 tagb = FPU_Special(b);
38 if ( st0_tag == TAG_Special )
39 st0_tag = FPU_Special(st0_ptr);
41 if ( ((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
42 || ((tagb != TAG_Valid) && (tagb != TW_Denormal)) )
44 if ( st0_tag == TAG_Zero )
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)
53 else if ( tagb == TAG_Zero )
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)
62 if ( st0_tag == TW_Infinity )
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)
69 else if ( tagb == TW_Infinity )
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);
75 /* Fall through to the NaN code */
77 else if ( tagb == TW_Infinity )
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)
84 /* Fall through to the NaN code */
87 /* The only possibility now should be that one of the arguments
89 if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) )
91 int signalling = 0, unsupported = 0;
92 if ( st0_tag == TW_NaN )
94 signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000;
95 unsupported = !((exponent(st0_ptr) == EXP_OVER)
96 && (st0_ptr->sigh & 0x80000000));
100 signalling |= (b->sigh & 0xc0000000) == 0x80000000;
101 unsupported |= !((exponent(b) == EXP_OVER)
102 && (b->sigh & 0x80000000));
104 if ( signalling || unsupported )
105 return COMP_No_Comp | COMP_SNaN | COMP_NaN;
107 /* Neither is a signaling NaN */
108 return COMP_No_Comp | COMP_NaN;
111 EXCEPTION(EX_Invalid);
114 if (st0_sign != signb)
116 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
117 | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
121 if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) )
123 FPU_to_exp16(st0_ptr, &x);
127 exp0 = exponent16(st0_ptr);
128 expb = exponent16(b);
132 exp0 = exponent(st0_ptr);
137 if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
138 if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
139 #endif /* PARANOID */
144 diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
148 diff = st0_ptr->sigl > b->sigl;
150 diff = -(st0_ptr->sigl < b->sigl);
156 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
157 | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
162 return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
163 | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
168 | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
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)
179 c = compare(loaded_data, loaded_tag);
183 EXCEPTION(EX_Invalid);
184 f = SW_C3 | SW_C2 | SW_C0;
199 f = SW_C3 | SW_C2 | SW_C0;
203 EXCEPTION(EX_INTERNAL|0x121);
204 f = SW_C3 | SW_C2 | SW_C0;
206 #endif /* PARANOID */
209 if (c & COMP_Denormal)
211 return denormal_operand() < 0;
217 static int compare_st_st(int nr)
222 if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
224 setcc(SW_C3 | SW_C2 | SW_C0);
226 EXCEPTION(EX_StackUnder);
227 return !(control_word & CW_Invalid);
231 c = compare(st_ptr, FPU_gettagi(nr));
234 setcc(SW_C3 | SW_C2 | SW_C0);
235 EXCEPTION(EX_Invalid);
236 return !(control_word & CW_Invalid);
251 f = SW_C3 | SW_C2 | SW_C0;
255 EXCEPTION(EX_INTERNAL|0x122);
256 f = SW_C3 | SW_C2 | SW_C0;
258 #endif /* PARANOID */
261 if (c & COMP_Denormal)
263 return denormal_operand() < 0;
269 static int compare_u_st_st(int nr)
274 if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
276 setcc(SW_C3 | SW_C2 | SW_C0);
278 EXCEPTION(EX_StackUnder);
279 return !(control_word & CW_Invalid);
283 c = compare(st_ptr, FPU_gettagi(nr));
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 */
290 EXCEPTION(EX_Invalid);
291 return !(control_word & CW_Invalid);
308 f = SW_C3 | SW_C2 | SW_C0;
312 EXCEPTION(EX_INTERNAL|0x123);
313 f = SW_C3 | SW_C2 | SW_C0;
315 #endif /* PARANOID */
318 if (c & COMP_Denormal)
320 return denormal_operand() < 0;
325 /*---------------------------------------------------------------------------*/
330 compare_st_st(FPU_rm);
337 if ( !compare_st_st(FPU_rm) )
350 if ( !compare_st_st(1) )
358 compare_u_st_st(FPU_rm);
366 if ( !compare_u_st_st(FPU_rm) )
376 if ( !compare_u_st_st(1) )