1 // SPDX-License-Identifier: GPL-2.0
2 /*---------------------------------------------------------------------------+
5 | Compare two floating point registers |
7 | Copyright (C) 1992,1993,1994,1997 |
8 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
9 | E-mail billm@suburbia.net |
12 +---------------------------------------------------------------------------*/
14 /*---------------------------------------------------------------------------+
15 | compare() is the core FPU_REG comparison function |
16 +---------------------------------------------------------------------------*/
18 #include "fpu_system.h"
19 #include "exception.h"
21 #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
))) {
43 if (st0_tag
== TAG_Zero
) {
46 if (tagb
== TAG_Valid
)
48 SIGN_POS
) ? COMP_A_lt_B
: COMP_A_gt_B
);
49 if (tagb
== TW_Denormal
)
51 SIGN_POS
) ? COMP_A_lt_B
: COMP_A_gt_B
)
53 } else if (tagb
== TAG_Zero
) {
54 if (st0_tag
== TAG_Valid
)
56 SIGN_POS
) ? COMP_A_gt_B
: COMP_A_lt_B
);
57 if (st0_tag
== TW_Denormal
)
59 SIGN_POS
) ? COMP_A_gt_B
: COMP_A_lt_B
)
63 if (st0_tag
== TW_Infinity
) {
64 if ((tagb
== TAG_Valid
) || (tagb
== TAG_Zero
))
66 SIGN_POS
) ? COMP_A_gt_B
: COMP_A_lt_B
);
67 else if (tagb
== TW_Denormal
)
69 SIGN_POS
) ? COMP_A_gt_B
: COMP_A_lt_B
)
71 else if (tagb
== TW_Infinity
) {
72 /* The 80486 book says that infinities can be equal! */
73 return (st0_sign
== signb
) ? COMP_A_eq_B
:
75 SIGN_POS
) ? COMP_A_gt_B
: COMP_A_lt_B
);
77 /* Fall through to the NaN code */
78 } else if (tagb
== TW_Infinity
) {
79 if ((st0_tag
== TAG_Valid
) || (st0_tag
== TAG_Zero
))
81 SIGN_POS
) ? COMP_A_lt_B
: COMP_A_gt_B
);
82 if (st0_tag
== TW_Denormal
)
84 SIGN_POS
) ? COMP_A_lt_B
: COMP_A_gt_B
)
86 /* Fall through to the NaN code */
89 /* The only possibility now should be that one of the arguments
91 if ((st0_tag
== TW_NaN
) || (tagb
== TW_NaN
)) {
92 int signalling
= 0, unsupported
= 0;
93 if (st0_tag
== TW_NaN
) {
95 (st0_ptr
->sigh
& 0xc0000000) == 0x80000000;
96 unsupported
= !((exponent(st0_ptr
) == EXP_OVER
)
100 if (tagb
== TW_NaN
) {
102 (b
->sigh
& 0xc0000000) == 0x80000000;
103 unsupported
|= !((exponent(b
) == EXP_OVER
)
104 && (b
->sigh
& 0x80000000));
106 if (signalling
|| unsupported
)
107 return COMP_No_Comp
| COMP_SNaN
| COMP_NaN
;
109 /* Neither is a signaling NaN */
110 return COMP_No_Comp
| COMP_NaN
;
113 EXCEPTION(EX_Invalid
);
116 if (st0_sign
!= signb
) {
117 return ((st0_sign
== SIGN_POS
) ? COMP_A_gt_B
: COMP_A_lt_B
)
118 | (((st0_tag
== TW_Denormal
) || (tagb
== TW_Denormal
)) ?
122 if ((st0_tag
== TW_Denormal
) || (tagb
== TW_Denormal
)) {
123 FPU_to_exp16(st0_ptr
, &x
);
127 exp0
= exponent16(st0_ptr
);
128 expb
= exponent16(b
);
130 exp0
= exponent(st0_ptr
);
135 if (!(st0_ptr
->sigh
& 0x80000000))
136 EXCEPTION(EX_Invalid
);
137 if (!(b
->sigh
& 0x80000000))
138 EXCEPTION(EX_Invalid
);
139 #endif /* PARANOID */
143 diff
= st0_ptr
->sigh
- b
->sigh
; /* Works only if ms bits are
146 diff
= st0_ptr
->sigl
> b
->sigl
;
148 diff
= -(st0_ptr
->sigl
< b
->sigl
);
153 return ((st0_sign
== SIGN_POS
) ? COMP_A_gt_B
: COMP_A_lt_B
)
154 | (((st0_tag
== TW_Denormal
) || (tagb
== TW_Denormal
)) ?
158 return ((st0_sign
== SIGN_POS
) ? COMP_A_lt_B
: COMP_A_gt_B
)
159 | (((st0_tag
== TW_Denormal
) || (tagb
== TW_Denormal
)) ?
164 | (((st0_tag
== TW_Denormal
) || (tagb
== TW_Denormal
)) ?
169 /* This function requires that st(0) is not empty */
170 int FPU_compare_st_data(FPU_REG
const *loaded_data
, u_char loaded_tag
)
174 c
= compare(loaded_data
, loaded_tag
);
177 EXCEPTION(EX_Invalid
);
178 f
= SW_C3
| SW_C2
| SW_C0
;
191 f
= SW_C3
| SW_C2
| SW_C0
;
195 EXCEPTION(EX_INTERNAL
| 0x121);
196 #endif /* PARANOID */
197 f
= SW_C3
| SW_C2
| SW_C0
;
201 if (c
& COMP_Denormal
) {
202 return denormal_operand() < 0;
207 static int compare_st_st(int nr
)
212 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr
)) {
213 setcc(SW_C3
| SW_C2
| SW_C0
);
215 EXCEPTION(EX_StackUnder
);
216 return !(control_word
& CW_Invalid
);
220 c
= compare(st_ptr
, FPU_gettagi(nr
));
222 setcc(SW_C3
| SW_C2
| SW_C0
);
223 EXCEPTION(EX_Invalid
);
224 return !(control_word
& CW_Invalid
);
237 f
= SW_C3
| SW_C2
| SW_C0
;
241 EXCEPTION(EX_INTERNAL
| 0x122);
242 #endif /* PARANOID */
243 f
= SW_C3
| SW_C2
| SW_C0
;
247 if (c
& COMP_Denormal
) {
248 return denormal_operand() < 0;
253 static int compare_i_st_st(int nr
)
258 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr
)) {
259 FPU_EFLAGS
|= (X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
);
261 EXCEPTION(EX_StackUnder
);
262 return !(control_word
& CW_Invalid
);
265 partial_status
&= ~SW_C0
;
267 c
= compare(st_ptr
, FPU_gettagi(nr
));
269 FPU_EFLAGS
|= (X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
);
270 EXCEPTION(EX_Invalid
);
271 return !(control_word
& CW_Invalid
);
285 f
= X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
;
289 EXCEPTION(EX_INTERNAL
| 0x122);
290 #endif /* PARANOID */
294 FPU_EFLAGS
= (FPU_EFLAGS
& ~(X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
)) | f
;
295 if (c
& COMP_Denormal
) {
296 return denormal_operand() < 0;
301 static int compare_u_st_st(int nr
)
306 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr
)) {
307 setcc(SW_C3
| SW_C2
| SW_C0
);
309 EXCEPTION(EX_StackUnder
);
310 return !(control_word
& CW_Invalid
);
314 c
= compare(st_ptr
, FPU_gettagi(nr
));
316 setcc(SW_C3
| SW_C2
| SW_C0
);
317 if (c
& COMP_SNaN
) { /* This is the only difference between
318 un-ordered and ordinary comparisons */
319 EXCEPTION(EX_Invalid
);
320 return !(control_word
& CW_Invalid
);
335 f
= SW_C3
| SW_C2
| SW_C0
;
339 EXCEPTION(EX_INTERNAL
| 0x123);
340 f
= SW_C3
| SW_C2
| SW_C0
;
342 #endif /* PARANOID */
345 if (c
& COMP_Denormal
) {
346 return denormal_operand() < 0;
351 static int compare_ui_st_st(int nr
)
356 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr
)) {
357 FPU_EFLAGS
|= (X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
);
359 EXCEPTION(EX_StackUnder
);
360 return !(control_word
& CW_Invalid
);
363 partial_status
&= ~SW_C0
;
365 c
= compare(st_ptr
, FPU_gettagi(nr
));
367 FPU_EFLAGS
|= (X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
);
368 if (c
& COMP_SNaN
) { /* This is the only difference between
369 un-ordered and ordinary comparisons */
370 EXCEPTION(EX_Invalid
);
371 return !(control_word
& CW_Invalid
);
387 f
= X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
;
391 EXCEPTION(EX_INTERNAL
| 0x123);
394 #endif /* PARANOID */
396 FPU_EFLAGS
= (FPU_EFLAGS
& ~(X86_EFLAGS_ZF
| X86_EFLAGS_PF
| X86_EFLAGS_CF
)) | f
;
397 if (c
& COMP_Denormal
) {
398 return denormal_operand() < 0;
403 /*---------------------------------------------------------------------------*/
408 compare_st_st(FPU_rm
);
414 if (!compare_st_st(FPU_rm
))
425 if (!compare_st_st(1))
432 compare_u_st_st(FPU_rm
);
439 if (!compare_u_st_st(FPU_rm
))
447 if (!compare_u_st_st(1))
453 /* P6+ compare-to-EFLAGS ops */
458 compare_i_st_st(FPU_rm
);
464 if (!compare_i_st_st(FPU_rm
))
471 compare_ui_st_st(FPU_rm
);
477 if (!compare_ui_st_st(FPU_rm
))