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))