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

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