[PATCH] Improve pow (C, x) -> exp (log (C) * x) optimization (PR middle-end/84309)

Jakub Jelinek jakub@redhat.com
Sat Feb 10 09:49:00 GMT 2018


On Sat, Feb 10, 2018 at 08:00:04AM +0100, Richard Biener wrote:
> On February 10, 2018 12:37:38 AM GMT+01:00, Jakub Jelinek <jakub@redhat.com> wrote:
> >Hi!
> >
> >Apparently the new pow(C,x) -> exp(log(C)*x) if C > 0 optimization
> >breaks some package (Marek should know which), as it has 7ulp error.
> >Generally one should be prepared for some errors with -ffast-math.
> >
> >Though, in this case, if the target has c99 runtime and C is
> >a positive 0x1pNN it seems much better to use exp2 over exp, for
> >C being 2 pow (2, x) is optimized into exp2 (x) and even for other
> >values log2(C) will still be some positive or negative integer, so
> >in many cases there won't be any rounding errors in the multiplication.
> >
> >Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> OK. I wonder whether there are vectorized variants in libmvec? 

Unfortunately libmvec only provides pow and exp, not exp2 nor exp10.
Wonder how much work it would be to provide also that.

Joseph, is exp2 in glibc .5ulp accurate like exp for double, or not?
Anything known about their relative performance?

> >Perhaps we should do something similar if C is a power of 10 (use exp10
> >and log10).
> >
> >2018-02-10  Jakub Jelinek  <jakub@redhat.com>
> >
> >	PR middle-end/84309
> >	* match.pd (pow(C,x) -> exp(log(C)*x)): Optimize instead into
> >	exp2(log2(C)*x) if C is a power of 2 and c99 runtime is available.
> >
> >	* gcc.dg/pr84309.c: New test.
> > 
> >--- gcc/match.pd.jj	2018-01-26 12:43:23.208922420 +0100
> >+++ gcc/match.pd	2018-02-09 18:48:26.412021408 +0100
> >@@ -3992,15 +3992,33 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> >    (logs (pows @0 @1))
> >    (mult @1 (logs @0))))
> > 
> >- /* pow(C,x) -> exp(log(C)*x) if C > 0.  */
> >+ /* pow(C,x) -> exp(log(C)*x) if C > 0,
> >+    or if C is a positive power of 2,
> >+    pow(C,x) -> exp2(log2(C)*x).  */
> >  (for pows (POW)
> >       exps (EXP)
> >       logs (LOG)
> >+      exp2s (EXP2)
> >+      log2s (LOG2)
> >   (simplify
> >    (pows REAL_CST@0 @1)
> >-    (if (real_compare (GT_EXPR, TREE_REAL_CST_PTR (@0), &dconst0)
> >-	 && real_isfinite (TREE_REAL_CST_PTR (@0)))
> >-     (exps (mult (logs @0) @1)))))
> >+   (if (real_compare (GT_EXPR, TREE_REAL_CST_PTR (@0), &dconst0)
> >+	&& real_isfinite (TREE_REAL_CST_PTR (@0)))
> >+    (with {
> >+       const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (@0);
> >+       bool use_exp2 = false;
> >+       if (targetm.libc_has_function (function_c99_misc)
> >+	   && value->cl == rvc_normal)
> >+	 {
> >+	   REAL_VALUE_TYPE frac_rvt = *value;
> >+	   SET_REAL_EXP (&frac_rvt, 1);
> >+	   if (real_equal (&frac_rvt, &dconst1))
> >+	     use_exp2 = true;
> >+	 }
> >+     }
> >+     (if (use_exp2)
> >+       (exp2s (mult (log2s @0) @1))
> >+       (exps (mult (logs @0) @1)))))))
> > 
> >  (for sqrts (SQRT)
> >       cbrts (CBRT)
> >--- gcc/testsuite/gcc.dg/pr84309.c.jj	2018-02-09 18:54:52.254787678
> >+0100
> >+++ gcc/testsuite/gcc.dg/pr84309.c	2018-02-09 18:59:02.343636178 +0100
> >@@ -0,0 +1,14 @@
> >+/* PR middle-end/84309 */
> >+/* { dg-do run { target c99_runtime } } */
> >+/* { dg-options "-O2 -ffast-math" } */
> >+
> >+int
> >+main ()
> >+{
> >+  unsigned long a = 1024;
> >+  unsigned long b = 16 * 1024;
> >+  unsigned long c = __builtin_pow (2, (__builtin_log2 (a) +
> >__builtin_log2 (b)) / 2);
> >+  if (c != 4096)
> >+    __builtin_abort ();
> >+  return 0;
> >+}

	Jakub



More information about the Gcc-patches mailing list