patch-2.1.73 linux/arch/i386/math-emu/reg_compare.c
Next file: linux/arch/i386/math-emu/reg_constant.c
Previous file: linux/arch/i386/math-emu/reg_add_sub.c
Back to the patch index
Back to the overall index
- Lines: 339
- Date:
Tue Dec 9 17:57:09 1997
- Orig file:
v2.1.72/linux/arch/i386/math-emu/reg_compare.c
- Orig date:
Thu Jun 2 00:28:27 1994
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_compare.c linux/arch/i386/math-emu/reg_compare.c
@@ -3,9 +3,9 @@
| |
| Compare two floating point registers |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -21,86 +21,87 @@
#include "status_w.h"
-int compare(FPU_REG const *b)
+static int compare(FPU_REG const *b, int tagb)
{
- int diff;
- char st0_tag;
- FPU_REG *st0_ptr;
+ int diff, exp0, expb;
+ u_char st0_tag;
+ FPU_REG *st0_ptr;
+ FPU_REG x, y;
+ u_char st0_sign, signb = getsign(b);
st0_ptr = &st(0);
- st0_tag = st0_ptr->tag;
+ st0_tag = FPU_gettag0();
+ st0_sign = getsign(st0_ptr);
- if ( st0_tag | b->tag )
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+
+ if ( ((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
+ || ((tagb != TAG_Valid) && (tagb != TW_Denormal)) )
{
- if ( st0_tag == TW_Zero )
+ if ( st0_tag == TAG_Zero )
{
- if ( b->tag == TW_Zero ) return COMP_A_eq_B;
- if ( b->tag == TW_Valid )
- {
- return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
-#ifdef DENORM_OPERAND
- | ((b->exp <= EXP_UNDER) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
- }
+ if ( tagb == TAG_Zero ) return COMP_A_eq_B;
+ if ( tagb == TAG_Valid )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
+ if ( tagb == TW_Denormal )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+ | COMP_Denormal;
}
- else if ( b->tag == TW_Zero )
+ else if ( tagb == TAG_Zero )
{
- if ( st0_tag == TW_Valid )
- {
- return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
- : COMP_A_lt_B)
-#ifdef DENORM_OPERAND
- | ((st0_ptr->exp <= EXP_UNDER )
- ? COMP_Denormal : 0 )
-#endif DENORM_OPERAND
- ;
- }
+ if ( st0_tag == TAG_Valid )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ if ( st0_tag == TW_Denormal )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | COMP_Denormal;
}
if ( st0_tag == TW_Infinity )
{
- if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
- {
- return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
- : COMP_A_lt_B)
-#ifdef DENORM_OPERAND
- | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0 )
-#endif DENORM_OPERAND
-;
- }
- else if ( b->tag == TW_Infinity )
+ if ( (tagb == TAG_Valid) || (tagb == TAG_Zero) )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ else if ( tagb == TW_Denormal )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | COMP_Denormal;
+ else if ( tagb == TW_Infinity )
{
/* The 80486 book says that infinities can be equal! */
- return (st0_ptr->sign == b->sign) ? COMP_A_eq_B :
- ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ return (st0_sign == signb) ? COMP_A_eq_B :
+ ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
}
/* Fall through to the NaN code */
}
- else if ( b->tag == TW_Infinity )
+ else if ( tagb == TW_Infinity )
{
- if ( (st0_tag == TW_Valid) || (st0_tag == TW_Zero) )
- {
- return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
-#ifdef DENORM_OPERAND
- | (((st0_tag == TW_Valid)
- && (st0_ptr->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
- }
+ if ( (st0_tag == TAG_Valid) || (st0_tag == TAG_Zero) )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
+ if ( st0_tag == TW_Denormal )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+ | COMP_Denormal;
/* Fall through to the NaN code */
}
/* The only possibility now should be that one of the arguments
is a NaN */
- if ( (st0_tag == TW_NaN) || (b->tag == TW_NaN) )
+ if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) )
{
- if ( ((st0_tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000))
- || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
- /* At least one arg is a signaling NaN */
+ int signalling = 0, unsupported = 0;
+ if ( st0_tag == TW_NaN )
+ {
+ signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000;
+ unsupported = !((exponent(st0_ptr) == EXP_OVER)
+ && (st0_ptr->sigh & 0x80000000));
+ }
+ if ( tagb == TW_NaN )
+ {
+ signalling |= (b->sigh & 0xc0000000) == 0x80000000;
+ unsupported |= !((exponent(b) == EXP_OVER)
+ && (b->sigh & 0x80000000));
+ }
+ if ( signalling || unsupported )
return COMP_No_Comp | COMP_SNaN | COMP_NaN;
else
/* Neither is a signaling NaN */
@@ -110,24 +111,34 @@
EXCEPTION(EX_Invalid);
}
+ if (st0_sign != signb)
+ {
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
+ }
+
+ if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) )
+ {
+ FPU_to_exp16(st0_ptr, &x);
+ FPU_to_exp16(b, &y);
+ st0_ptr = &x;
+ b = &y;
+ exp0 = exponent16(st0_ptr);
+ expb = exponent16(b);
+ }
+ else
+ {
+ exp0 = exponent(st0_ptr);
+ expb = exponent(b);
+ }
+
#ifdef PARANOID
if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
#endif PARANOID
-
- if (st0_ptr->sign != b->sign)
- {
- return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
-#ifdef DENORM_OPERAND
- |
- ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
- }
-
- diff = st0_ptr->exp - b->exp;
+ diff = exp0 - expb;
if ( diff == 0 )
{
diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
@@ -142,42 +153,30 @@
if ( diff > 0 )
{
- return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
-#ifdef DENORM_OPERAND
- |
- ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
}
if ( diff < 0 )
{
- return ((st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
-#ifdef DENORM_OPERAND
- |
- ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
+ return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
}
return COMP_A_eq_B
-#ifdef DENORM_OPERAND
- |
- ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
}
/* This function requires that st(0) is not empty */
-int compare_st_data(FPU_REG const *loaded_data)
+int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
{
int f, c;
- c = compare(loaded_data);
+ c = compare(loaded_data, loaded_tag);
if (c & COMP_NaN)
{
@@ -209,7 +208,7 @@
setcc(f);
if (c & COMP_Denormal)
{
- return denormal_operand();
+ return denormal_operand() < 0;
}
return 0;
}
@@ -218,6 +217,7 @@
static int compare_st_st(int nr)
{
int f, c;
+ FPU_REG *st_ptr;
if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
{
@@ -227,7 +227,8 @@
return !(control_word & CW_Invalid);
}
- c = compare(&st(nr));
+ st_ptr = &st(nr);
+ c = compare(st_ptr, FPU_gettagi(nr));
if (c & COMP_NaN)
{
setcc(SW_C3 | SW_C2 | SW_C0);
@@ -259,7 +260,7 @@
setcc(f);
if (c & COMP_Denormal)
{
- return denormal_operand();
+ return denormal_operand() < 0;
}
return 0;
}
@@ -268,6 +269,7 @@
static int compare_u_st_st(int nr)
{
int f, c;
+ FPU_REG *st_ptr;
if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
{
@@ -277,7 +279,8 @@
return !(control_word & CW_Invalid);
}
- c = compare(&st(nr));
+ st_ptr = &st(nr);
+ c = compare(st_ptr, FPU_gettagi(nr));
if (c & COMP_NaN)
{
setcc(SW_C3 | SW_C2 | SW_C0);
@@ -314,7 +317,7 @@
setcc(f);
if (c & COMP_Denormal)
{
- return denormal_operand();
+ return denormal_operand() < 0;
}
return 0;
}
@@ -332,7 +335,7 @@
{
/* fcomp st(i) */
if ( !compare_st_st(FPU_rm) )
- pop();
+ FPU_pop();
}
@@ -361,7 +364,7 @@
{
/* fucomp st(i) */
if ( !compare_u_st_st(FPU_rm) )
- pop();
+ FPU_pop();
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov