[PATCH] Fold sqrt comparisons against constants

Geoff Keating geoffk@geoffk.org
Mon Mar 17 23:36:00 GMT 2003


Roger Sayle <roger@www.eyesopen.com> writes:

> This patch performs constant folding of comparisons of the result
> of sqrt, sqrtf, and sqrtl against floating point constants.  This
> optimization can often be applied in scientific software, where
> the distance between two points is compared against a threshold.
> I know of one structural biology application where the single test
> "sqrt(x) < 9.0" is the critical path.  The patch below transforms
> this into the equivalent "(x>=0.0) && (x<81.0)" with -ffast-math.
> 
> The following patch has been tested on i686-pc-linux-gnu with a
> full "make bootstrap", all languages except Ada and treelang, and
> regression tested with a top-level "make -k check" with no new
> failures.
> 
> Ok for mainline?

This is a very good patch, but I think it'd be even better if it was
rearranged a bit.

The cases are as follows:

1. -funsafe-math-optimisations + -ffinite-math-only  (for instance -ffast-math)
   In this case, you can just unconditionally convert 

   sqrt (x) relop y
   to
   x relop y * y

   and perhaps further into 'true' or 'false'.  We don't care about
   overflows or small loss of accuracy with this flag combination.  We
   do, however care that if y*y overflows, then the correct behaviour
   occurs.  (In such a case, the answer will always be 'true' or
   'false', depending on relop and the sign of y).

2. When -fno-finite-math-only is specified
   The important cases to consider are when x < 0, isnan(x), and x ==
   +Inf.  For instance,

   sqrt (x) < DBL_MAX

   is equivalent to 'x >= 0 && x != +Inf'.

   (You also need to consider 'sqrt (x) < nan()', but I think that probably
   Just Works in your previous patch.)

3. When -fno-unsafe-math-optimisations is specified

   It's always possible to remove the sqrt() operation, but it's not
   nearly as simple as just taking 'x relop y * y'.  sqrt() is
   guaranteed to be monotonic, but it compresses its range, so for any
   output value 'y', there will be a range x_0 ... x_1 for which
   sqrt(x) == y.  The problem is that x_0 and x_1 vary depending on
   the rounding mode in use, which GCC could know at compile time but
   at present doesn't.  So I'd suggest skipping this case for now.

> +       else if (code == GT_EXPR || code == GE_EXPR)
> + 	{
> + 	  REAL_VALUE_TYPE c2;
> +
> + 	  /* sqrt(x) > c is the same as x > c*c.  */
> + 	  REAL_ARITHMETIC (c2, MULT_EXPR, c, c);
> + 	  return fold (build (code, type, arg,
> + 			      build_real (TREE_TYPE (arg), c2)));
> + 	}

So this code needs to handle overflow...

> +       else if (code == LT_EXPR || code == LE_EXPR)
> + 	{
> + 	  /* sqrt(x) < c is the same as x >= 0 && x < c*c.  */
> + 	  if ((*lang_hooks.decls.global_bindings_p) () == 0
> + 	      && ! contains_placeholder_p (arg))
> + 	    {
> + 	      REAL_VALUE_TYPE c2;
> +
> + 	      arg = save_expr (arg);
> + 	      REAL_ARITHMETIC (c2, MULT_EXPR, c, c);
> + 	      return fold (build (TRUTH_ANDIF_EXPR, type,
> + 				  fold (build (GE_EXPR, type, arg,
> + 					       build_real (TREE_TYPE (arg),
> + 							   dconst0))),
> + 				  fold (build (code, type, arg,
> + 					       build_real (TREE_TYPE (arg),
> + 							   c2)))));
> + 	    }
> + 	}

... and this code needs to handle overflow, but doesn't need to check
for 'x >= 0' if ! HONOUR_NANS.

-- 
- Geoffrey Keating <geoffk@geoffk.org>



More information about the Gcc-patches mailing list