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" } } */