Hi,
This patch adds two transforms to match.pd to CSE erf/erfc pair.
erfc(x) is canonicalized to 1 - erf(x) and is then reversed to 1 -
erf(x) when canonicalization is disabled and result of erf(x) has
single use within 1 - erf(x).

The patch regressed builtin-nonneg-1.c. The following test-case
reproduces the issue with patch:

void test(double d1) {
  if (signbit(erfc(d1)))
    link_failure_erfc();
}

ssa dump:

  <bb 2> :
  _5 = __builtin_erf (d1_4(D));
  _1 = 1.0e+0 - _5;
  _6 = _1 < 0.0;
  _2 = (int) _6;
  if (_2 != 0)
    goto <bb 3>; [INV]
  else
    goto <bb 4>; [INV]

  <bb 3> :
  link_failure_erfc ();

  <bb 4> :
  return;

As can be seen, erfc(d1) is folded to 1 - erf(d1).
forwprop then transforms the if condition from _2 != 0
to _5 > 1.0e+0 and that defeats DCE thus resulting in link failure
in undefined reference to link_failure_erfc().

So, the patch adds another transform erf(x) > 1 -> 0
which resolves the regression.

Bootstrapped+tested on x86_64-unknown-linux-gnu.
Cross-testing on arm and aarch64 variants in progress.
OK for trunk if passes ?

Thanks,
Prathamesh
2018-11-02  Prathamesh Kulkarni  <prathamesh.kulka...@linaro.org>

        * match.pd (erfc(x) -> 1 - erf(x)): New pattern.
        (1 - erf(x) -> erfc(x)): Likewise.
        (erf(x) > 1 -> 0): Likewise.

testsuite/
        * gcc.dg/tree-ssa/pr83750-1.c: New test
        * gcc.dg/tree-ssa/pr83750-2.c: Likewise.

diff --git a/gcc/match.pd b/gcc/match.pd
index d07ceb7d087..03e9230a579 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -4490,7 +4490,28 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (if (targetm.libc_has_function (function_c99_math_complex))
     (complex
      (mult (exps@1 (realpart @0)) (realpart (cexpis:type@2 (imagpart @0))))
-     (mult @1 (imagpart @2)))))))
+     (mult @1 (imagpart @2))))))
+
+
+ /* Canonicalize erfc(x) -> 1 - erf(x) */
+ (simplify
+  (ERFC @0)
+   (minus { build_one_cst (TREE_TYPE (@0)); } (ERF @0))))
+
+(if (flag_unsafe_math_optimizations
+     && !canonicalize_math_p())
+
+ /* 1 - erf(x) -> erfc(x)
+    This is only done if result of erf() has single use in 1 - erf(x). */
+ (simplify
+  (minus real_onep (ERF@1 @0))
+   (if (single_use (@1))
+    (ERFC @0)))
+
+ /* erf(x) > 1 -> 0 */
+ (simplify
+  (gt (ERF @0) real_onep)
+  { integer_zero_node; }))
 
 (if (canonicalize_math_p ())
  /* floor(x) -> trunc(x) if x is nonnegative.  */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr83750-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr83750-1.c
new file mode 100644
index 00000000000..c4d3e428f15
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr83750-1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target c99_runtime } */
+/* { dg-options "-O2 -ffast-math -fdump-tree-optimized" } */
+
+float f1(float x)
+{
+  float g1(float, float);
+
+  float r = __builtin_erff (x);
+  float t = __builtin_erfcf (x);
+  return g1 (r, t);
+}
+
+double f2(double x)
+{
+  double g2(double, double);
+
+  double r = __builtin_erf (x);
+  double t = __builtin_erfc (x);
+  return g2 (r, t);
+}
+
+long double f3(long double x)
+{
+  long double g3(long double, long double);
+
+  long double r = __builtin_erfl (x);
+  long double t = __builtin_erfcl (x);
+  return g3(r, t);
+}
+
+/* { dg-final { scan-tree-dump-not "erfc" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr83750-2.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr83750-2.c
new file mode 100644
index 00000000000..60417b38681
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr83750-2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target c99_runtime } */
+/* { dg-options "-O2 -ffast-math -fdump-tree-optimized" } */
+
+/* Check that the canonicalized form 1 - erf(x) is folded to erfc(x). */
+
+float f1(float x)
+{
+  return __builtin_erfcf (x);
+}
+
+double f2(double x)
+{
+  return __builtin_erfc (x);
+}
+
+long double f3(long double x)
+{
+  return __builtin_erfcl (x); 
+}
+
+/* { dg-final { scan-tree-dump-times "erfc" 3 "optimized" } } */

Reply via email to