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 <[email protected]>
* 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" } } */