[PATCH] Fold comparisons against Inf and NaN

Roger Sayle roger@www.eyesopen.com
Thu Mar 27 06:10:00 GMT 2003


The following patch performs constant folding of comparisons against
+Inf, -Inf and NaN.

This patch has been tested on i686-pc-linux-gnu by a full bootstrap,
all languages except Ada and treelang, and regression tested with a
top-level "make -k check" with no new failures [except for libjava
due to timeouts].

Ok for mainline?


2003-03-26  Roger Sayle  <roger@eyesopen.com>

	* fold-const.c (fold_inf_compare):  New function to simplify FP
	comparisons against +Infinity or -Infinity.
	(fold):  Optimize floating point comparisons against Infs and NaNs.

	* gcc.c-torture/execute/ieee/fp-cmp-6.c: New test case.
	* gcc.c-torture/execute/ieee/fp-cmp-7.c: New test case.


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.241
diff -c -3 -p -r1.241 fold-const.c
*** fold-const.c	21 Mar 2003 00:03:24 -0000	1.241
--- fold-const.c	26 Mar 2003 16:59:47 -0000
*************** static tree fold_binary_op_with_conditio
*** 114,119 ****
--- 114,120 ----
  static bool fold_real_zero_addition_p	PARAMS ((tree, tree, int));
  static tree fold_mathfn_compare	PARAMS ((enum built_in_function,
  					 enum tree_code, tree, tree, tree));
+ static tree fold_inf_compare	PARAMS ((enum tree_code, tree, tree, tree));

  /* The following constants represent a bit based encoding of GCC's
     comparison operators.  This encoding simplifies transformations
*************** fold_mathfn_compare (fcode, code, type,
*** 4793,4798 ****
--- 4794,4855 ----
    return NULL_TREE;
  }

+ /* Subroutine of fold() that optimizes comparisons against Infinities,
+    either +Inf or -Inf.
+
+    CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR,
+    GE_EXPR or LE_EXPR.  TYPE is the type of the result and ARG0 and ARG1
+    are the operands of the comparison.  ARG1 must be a TREE_REAL_CST.
+
+    The function returns the constant folded tree if a simplification
+    can be made, and NULL_TREE otherwise.  */
+
+ static tree
+ fold_inf_compare (code, type, arg0, arg1)
+      enum tree_code code;
+      tree type, arg0, arg1;
+ {
+   /* For negative infinity swap the sense of the comparison.  */
+   if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)))
+     code = swap_tree_comparison (code);
+
+   switch (code)
+     {
+     case GT_EXPR:
+       /* x > +Inf is always false, if with ignore sNANs.  */
+       if (HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))))
+         return NULL_TREE;
+       return omit_one_operand (type,
+ 			       convert (type, integer_zero_node),
+ 			       arg0);
+
+     case LE_EXPR:
+       /* x <= +Inf is always true, if we don't case about NaNs.  */
+       if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+ 	return omit_one_operand (type,
+ 				 convert (type, integer_one_node),
+ 				 arg0);
+
+       /* x <= +Inf is the same as x == x, i.e. isfinite(x).  */
+       if ((*lang_hooks.decls.global_bindings_p) () == 0
+ 	  && ! contains_placeholder_p (arg0))
+ 	{
+ 	  arg0 = save_expr (arg0);
+ 	  return fold (build (EQ_EXPR, type, arg0, arg0));
+ 	}
+       break;
+
+     case EQ_EXPR:  /* ??? x == +Inf is x > DBL_MAX  */
+     case GE_EXPR:  /* ??? x >= +Inf is x > DBL_MAX  */
+     case LT_EXPR:  /* ??? x < +Inf is x <= DBL_MAX  */
+     case NE_EXPR:  /* ??? x != +Inf is !(x > DBL_MAX)  */
+
+     default:
+       break;
+     }
+
+   return NULL_TREE;
+ }

  /* Perform constant folding and related simplification of EXPR.
     The related simplifications include x*1 => x, x*0 => 0, etc.,
*************** fold (expr)
*** 6312,6331 ****
  	      && TREE_CODE (arg1) == NEGATE_EXPR)
  	    return fold (build (code, type, TREE_OPERAND (arg1, 0),
  				TREE_OPERAND (arg0, 0)));
! 	  /* (-a) CMP CST -> a swap(CMP) (-CST)  */
! 	  if (TREE_CODE (arg0) == NEGATE_EXPR && TREE_CODE (arg1) == REAL_CST)
! 	    return
! 	      fold (build
! 		    (swap_tree_comparison (code), type,
! 		     TREE_OPERAND (arg0, 0),
! 		     build_real (TREE_TYPE (arg1),
! 				 REAL_VALUE_NEGATE (TREE_REAL_CST (arg1)))));
! 	  /* IEEE doesn't distinguish +0 and -0 in comparisons.  */
! 	  /* a CMP (-0) -> a CMP 0  */
! 	  if (TREE_CODE (arg1) == REAL_CST
! 	      && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (arg1)))
! 	    return fold (build (code, type, arg0,
! 				build_real (TREE_TYPE (arg1), dconst0)));

  	  /* If this is a comparison of a real constant with a PLUS_EXPR
  	     or a MINUS_EXPR of a real constant, we can convert it into a
--- 6369,6410 ----
  	      && TREE_CODE (arg1) == NEGATE_EXPR)
  	    return fold (build (code, type, TREE_OPERAND (arg1, 0),
  				TREE_OPERAND (arg0, 0)));
!
! 	  if (TREE_CODE (arg1) == REAL_CST)
! 	  {
! 	    REAL_VALUE_TYPE cst;
! 	    cst = TREE_REAL_CST (arg1);
!
! 	    /* (-a) CMP CST -> a swap(CMP) (-CST)  */
! 	    if (TREE_CODE (arg0) == NEGATE_EXPR)
! 	      return
! 		fold (build (swap_tree_comparison (code), type,
! 			     TREE_OPERAND (arg0, 0),
! 			     build_real (TREE_TYPE (arg1),
! 					 REAL_VALUE_NEGATE (cst))));
!
! 	    /* IEEE doesn't distinguish +0 and -0 in comparisons.  */
! 	    /* a CMP (-0) -> a CMP 0  */
! 	    if (REAL_VALUE_MINUS_ZERO (cst))
! 	      return fold (build (code, type, arg0,
! 				  build_real (TREE_TYPE (arg1), dconst0)));
!
! 	    /* x != NaN is always true, other ops are always false.  */
! 	    if (REAL_VALUE_ISNAN (cst)
! 		&& ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))))
! 	      {
! 		t = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
! 		return omit_one_operand (type, convert (type, t), arg0);
! 	      }
!
! 	    /* Fold comparisons against infinity.  */
! 	    if (REAL_VALUE_ISINF (cst))
! 	      {
! 		tem = fold_inf_compare (code, type, arg0, arg1);
! 		if (tem != NULL_TREE)
! 		  return tem;
! 	      }
! 	  }

  	  /* If this is a comparison of a real constant with a PLUS_EXPR
  	     or a MINUS_EXPR of a real constant, we can convert it into a



const double dnan = 1.0/0.0 - 1.0/0.0;
double x = 1.0;

extern void link_error ();

main ()
{
#if ! defined (__vax__) && ! defined (_CRAY)
  /* NaN is an IEEE unordered operand.  All these test should be false.  */
  if (dnan == dnan)
    link_error ();
  if (dnan != x)
    x = 1.0;
  else
    link_error ();

  if (dnan < x)
    link_error ();
  if (dnan > x)
    link_error ();
  if (dnan <= x)
    link_error ();
  if (dnan >= x)
    link_error ();
  if (dnan == x)
    link_error ();
#endif
  exit (0);
}


extern void link_error ();

void foo(double x)
{
  if (x > __builtin_inf())
    link_error ();
}

int main ()
{
  foo (1.0);
  return 0;
}


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833



More information about the Gcc-patches mailing list