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"
23 static int compare(FPU_REG const *b, int tagb)
29 u_char st0_sign, signb = getsign(b);
32 st0_tag = FPU_gettag0();
33 st0_sign = getsign(st0_ptr);
35 if (tagb == TAG_Special)
36 tagb = FPU_Special(b);
37 if (st0_tag == TAG_Special)
38 st0_tag = FPU_Special(st0_ptr);
40 if (((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
41 || ((tagb != TAG_Valid) && (tagb != TW_Denormal))) {
42 if (st0_tag == TAG_Zero) {
45 if (tagb == TAG_Valid)
47 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
48 if (tagb == TW_Denormal)
50 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
52 } else if (tagb == TAG_Zero) {
53 if (st0_tag == TAG_Valid)
55 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
56 if (st0_tag == TW_Denormal)
58 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
62 if (st0_tag == TW_Infinity) {
63 if ((tagb == TAG_Valid) || (tagb == TAG_Zero))
65 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
66 else if (tagb == TW_Denormal)
68 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
70 else if (tagb == TW_Infinity) {
71 /* The 80486 book says that infinities can be equal! */
72 return (st0_sign == signb) ? COMP_A_eq_B :
74 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
76 /* Fall through to the NaN code */
77 } else if (tagb == TW_Infinity) {
78 if ((st0_tag == TAG_Valid) || (st0_tag == TAG_Zero))
80 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
81 if (st0_tag == TW_Denormal)
83 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
85 /* Fall through to the NaN code */
88 /* The only possibility now should be that one of the arguments
90 if ((st0_tag == TW_NaN) || (tagb == TW_NaN)) {
91 int signalling = 0, unsupported = 0;
92 if (st0_tag == TW_NaN) {
94 (st0_ptr->sigh & 0xc0000000) == 0x80000000;
95 unsupported = !((exponent(st0_ptr) == EXP_OVER)
101 (b->sigh & 0xc0000000) == 0x80000000;
102 unsupported |= !((exponent(b) == EXP_OVER)
103 && (b->sigh & 0x80000000));
105 if (signalling || unsupported)
106 return COMP_No_Comp | COMP_SNaN | COMP_NaN;
108 /* Neither is a signaling NaN */
109 return COMP_No_Comp | COMP_NaN;
112 EXCEPTION(EX_Invalid);
115 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)) {
122 FPU_to_exp16(st0_ptr, &x);
126 exp0 = exponent16(st0_ptr);
127 expb = exponent16(b);
129 exp0 = exponent(st0_ptr);
134 if (!(st0_ptr->sigh & 0x80000000))
135 EXCEPTION(EX_Invalid);
136 if (!(b->sigh & 0x80000000))
137 EXCEPTION(EX_Invalid);
138 #endif /* PARANOID */
142 diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
145 diff = st0_ptr->sigl > b->sigl;
147 diff = -(st0_ptr->sigl < b->sigl);
152 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
153 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
157 return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
158 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
163 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
168 /* This function requires that st(0) is not empty */
169 int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
173 c = compare(loaded_data, loaded_tag);
176 EXCEPTION(EX_Invalid);
177 f = SW_C3 | SW_C2 | SW_C0;
190 f = SW_C3 | SW_C2 | SW_C0;
194 EXCEPTION(EX_INTERNAL | 0x121);
195 f = SW_C3 | SW_C2 | SW_C0;
197 #endif /* PARANOID */
200 if (c & COMP_Denormal) {
201 return denormal_operand() < 0;
206 static int compare_st_st(int nr)
211 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
212 setcc(SW_C3 | SW_C2 | SW_C0);
214 EXCEPTION(EX_StackUnder);
215 return !(control_word & CW_Invalid);
219 c = compare(st_ptr, FPU_gettagi(nr));
221 setcc(SW_C3 | SW_C2 | SW_C0);
222 EXCEPTION(EX_Invalid);
223 return !(control_word & CW_Invalid);
236 f = SW_C3 | SW_C2 | SW_C0;
240 EXCEPTION(EX_INTERNAL | 0x122);
241 f = SW_C3 | SW_C2 | SW_C0;
243 #endif /* PARANOID */
246 if (c & COMP_Denormal) {
247 return denormal_operand() < 0;
252 static int compare_u_st_st(int nr)
257 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
258 setcc(SW_C3 | SW_C2 | SW_C0);
260 EXCEPTION(EX_StackUnder);
261 return !(control_word & CW_Invalid);
265 c = compare(st_ptr, FPU_gettagi(nr));
267 setcc(SW_C3 | SW_C2 | SW_C0);
268 if (c & COMP_SNaN) { /* This is the only difference between
269 un-ordered and ordinary comparisons */
270 EXCEPTION(EX_Invalid);
271 return !(control_word & CW_Invalid);
286 f = SW_C3 | SW_C2 | SW_C0;
290 EXCEPTION(EX_INTERNAL | 0x123);
291 f = SW_C3 | SW_C2 | SW_C0;
293 #endif /* PARANOID */
296 if (c & COMP_Denormal) {
297 return denormal_operand() < 0;
302 /*---------------------------------------------------------------------------*/
307 compare_st_st(FPU_rm);
313 if (!compare_st_st(FPU_rm))
324 if (!compare_st_st(1))
331 compare_u_st_st(FPU_rm);
338 if (!compare_u_st_st(FPU_rm))
346 if (!compare_u_st_st(1))