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_i_st_st(int nr
)
257 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr
)) {
258 FPU_EFLAGS
|= (X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
);
260 EXCEPTION(EX_StackUnder
);
261 return !(control_word
& CW_Invalid
);
264 partial_status
&= ~SW_C0
;
266 c
= compare(st_ptr
, FPU_gettagi(nr
));
268 FPU_EFLAGS
|= (X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
);
269 EXCEPTION(EX_Invalid
);
270 return !(control_word
& CW_Invalid
);
284 f
= X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
;
288 EXCEPTION(EX_INTERNAL
| 0x122);
291 #endif /* PARANOID */
293 FPU_EFLAGS
= (FPU_EFLAGS
& ~(X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
)) | f
;
294 if (c
& COMP_Denormal
) {
295 return denormal_operand() < 0;
300 static int compare_u_st_st(int nr
)
305 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr
)) {
306 setcc(SW_C3
| SW_C2
| SW_C0
);
308 EXCEPTION(EX_StackUnder
);
309 return !(control_word
& CW_Invalid
);
313 c
= compare(st_ptr
, FPU_gettagi(nr
));
315 setcc(SW_C3
| SW_C2
| SW_C0
);
316 if (c
& COMP_SNaN
) { /* This is the only difference between
317 un-ordered and ordinary comparisons */
318 EXCEPTION(EX_Invalid
);
319 return !(control_word
& CW_Invalid
);
334 f
= SW_C3
| SW_C2
| SW_C0
;
338 EXCEPTION(EX_INTERNAL
| 0x123);
339 f
= SW_C3
| SW_C2
| SW_C0
;
341 #endif /* PARANOID */
344 if (c
& COMP_Denormal
) {
345 return denormal_operand() < 0;
350 static int compare_ui_st_st(int nr
)
355 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr
)) {
356 FPU_EFLAGS
|= (X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
);
358 EXCEPTION(EX_StackUnder
);
359 return !(control_word
& CW_Invalid
);
362 partial_status
&= ~SW_C0
;
364 c
= compare(st_ptr
, FPU_gettagi(nr
));
366 FPU_EFLAGS
|= (X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
);
367 if (c
& COMP_SNaN
) { /* This is the only difference between
368 un-ordered and ordinary comparisons */
369 EXCEPTION(EX_Invalid
);
370 return !(control_word
& CW_Invalid
);
386 f
= X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
;
390 EXCEPTION(EX_INTERNAL
| 0x123);
393 #endif /* PARANOID */
395 FPU_EFLAGS
= (FPU_EFLAGS
& ~(X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
)) | f
;
396 if (c
& COMP_Denormal
) {
397 return denormal_operand() < 0;
402 /*---------------------------------------------------------------------------*/
407 compare_st_st(FPU_rm
);
413 if (!compare_st_st(FPU_rm
))
424 if (!compare_st_st(1))
431 compare_u_st_st(FPU_rm
);
438 if (!compare_u_st_st(FPU_rm
))
446 if (!compare_u_st_st(1))
452 /* P6+ compare-to-EFLAGS ops */
457 compare_i_st_st(FPU_rm
);
463 if (!compare_i_st_st(FPU_rm
))
470 compare_ui_st_st(FPU_rm
);
476 if (!compare_ui_st_st(FPU_rm
))