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