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