Hi, Please find attached the patch "simplify-1.patch" that moves some "flag_unsafe_math_optimizations" from fold-const.c to simplify and match.
However, I am facing some issues with cbrt, exp2, pow10 and exp10 functions. Please review the patch and let me know whether its the right way to implement them. Pointers on solving the unimplemented patterns issues will be very helpful. Regression tested on X86_64. gcc.dg/torture/builtin-power-1.c FAIL's due to unimplemented exp10 and pow10 optimizations. AArch64 : Along with these cbrt and exp2 also has issues. Thanks, Naveen
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 6c65fe1..4171691 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -9947,128 +9947,6 @@ fold_binary_loc (location_t loc, if (flag_unsafe_math_optimizations) { - enum built_in_function fcode0 = builtin_mathfn_code (arg0); - enum built_in_function fcode1 = builtin_mathfn_code (arg1); - - /* Optimizations of root(...)*root(...). */ - if (fcode0 == fcode1 && BUILTIN_ROOT_P (fcode0)) - { - tree rootfn, arg; - tree arg00 = CALL_EXPR_ARG (arg0, 0); - tree arg10 = CALL_EXPR_ARG (arg1, 0); - - /* Optimize sqrt(x)*sqrt(x) as x. */ - if (BUILTIN_SQRT_P (fcode0) - && operand_equal_p (arg00, arg10, 0) - && ! HONOR_SNANS (element_mode (type))) - return arg00; - - /* Optimize root(x)*root(y) as root(x*y). */ - rootfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0); - arg = fold_build2_loc (loc, MULT_EXPR, type, arg00, arg10); - return build_call_expr_loc (loc, rootfn, 1, arg); - } - - /* Optimize expN(x)*expN(y) as expN(x+y). */ - if (fcode0 == fcode1 && BUILTIN_EXPONENT_P (fcode0)) - { - tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0); - tree arg = fold_build2_loc (loc, PLUS_EXPR, type, - CALL_EXPR_ARG (arg0, 0), - CALL_EXPR_ARG (arg1, 0)); - return build_call_expr_loc (loc, expfn, 1, arg); - } - - /* Optimizations of pow(...)*pow(...). */ - if ((fcode0 == BUILT_IN_POW && fcode1 == BUILT_IN_POW) - || (fcode0 == BUILT_IN_POWF && fcode1 == BUILT_IN_POWF) - || (fcode0 == BUILT_IN_POWL && fcode1 == BUILT_IN_POWL)) - { - tree arg00 = CALL_EXPR_ARG (arg0, 0); - tree arg01 = CALL_EXPR_ARG (arg0, 1); - tree arg10 = CALL_EXPR_ARG (arg1, 0); - tree arg11 = CALL_EXPR_ARG (arg1, 1); - - /* Optimize pow(x,y)*pow(z,y) as pow(x*z,y). */ - if (operand_equal_p (arg01, arg11, 0)) - { - tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0); - tree arg = fold_build2_loc (loc, MULT_EXPR, type, - arg00, arg10); - return build_call_expr_loc (loc, powfn, 2, arg, arg01); - } - - /* Optimize pow(x,y)*pow(x,z) as pow(x,y+z). */ - if (operand_equal_p (arg00, arg10, 0)) - { - tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0); - tree arg = fold_build2_loc (loc, PLUS_EXPR, type, - arg01, arg11); - return build_call_expr_loc (loc, powfn, 2, arg00, arg); - } - } - - /* Optimize tan(x)*cos(x) as sin(x). */ - if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_COS) - || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_COSF) - || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_COSL) - || (fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_TAN) - || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_TANF) - || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_TANL)) - && operand_equal_p (CALL_EXPR_ARG (arg0, 0), - CALL_EXPR_ARG (arg1, 0), 0)) - { - tree sinfn = mathfn_built_in (type, BUILT_IN_SIN); - - if (sinfn != NULL_TREE) - return build_call_expr_loc (loc, sinfn, 1, - CALL_EXPR_ARG (arg0, 0)); - } - - /* Optimize x*pow(x,c) as pow(x,c+1). */ - if (fcode1 == BUILT_IN_POW - || fcode1 == BUILT_IN_POWF - || fcode1 == BUILT_IN_POWL) - { - tree arg10 = CALL_EXPR_ARG (arg1, 0); - tree arg11 = CALL_EXPR_ARG (arg1, 1); - if (TREE_CODE (arg11) == REAL_CST - && !TREE_OVERFLOW (arg11) - && operand_equal_p (arg0, arg10, 0)) - { - tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0); - REAL_VALUE_TYPE c; - tree arg; - - c = TREE_REAL_CST (arg11); - real_arithmetic (&c, PLUS_EXPR, &c, &dconst1); - arg = build_real (type, c); - return build_call_expr_loc (loc, powfn, 2, arg0, arg); - } - } - - /* Optimize pow(x,c)*x as pow(x,c+1). */ - if (fcode0 == BUILT_IN_POW - || fcode0 == BUILT_IN_POWF - || fcode0 == BUILT_IN_POWL) - { - tree arg00 = CALL_EXPR_ARG (arg0, 0); - tree arg01 = CALL_EXPR_ARG (arg0, 1); - if (TREE_CODE (arg01) == REAL_CST - && !TREE_OVERFLOW (arg01) - && operand_equal_p (arg1, arg00, 0)) - { - tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0); - REAL_VALUE_TYPE c; - tree arg; - - c = TREE_REAL_CST (arg01); - real_arithmetic (&c, PLUS_EXPR, &c, &dconst1); - arg = build_real (type, c); - return build_call_expr_loc (loc, powfn, 2, arg1, arg); - } - } - /* Canonicalize x*x as pow(x,2.0), which is expanded as x*x. */ if (!in_gimple_form && optimize @@ -10479,152 +10357,6 @@ fold_binary_loc (location_t loc, TREE_OPERAND (arg1, 0)); } - if (flag_unsafe_math_optimizations) - { - enum built_in_function fcode0 = builtin_mathfn_code (arg0); - enum built_in_function fcode1 = builtin_mathfn_code (arg1); - - /* Optimize sin(x)/cos(x) as tan(x). */ - if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_COS) - || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_COSF) - || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_COSL)) - && operand_equal_p (CALL_EXPR_ARG (arg0, 0), - CALL_EXPR_ARG (arg1, 0), 0)) - { - tree tanfn = mathfn_built_in (type, BUILT_IN_TAN); - - if (tanfn != NULL_TREE) - return build_call_expr_loc (loc, tanfn, 1, CALL_EXPR_ARG (arg0, 0)); - } - - /* Optimize cos(x)/sin(x) as 1.0/tan(x). */ - if (((fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_SIN) - || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_SINF) - || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_SINL)) - && operand_equal_p (CALL_EXPR_ARG (arg0, 0), - CALL_EXPR_ARG (arg1, 0), 0)) - { - tree tanfn = mathfn_built_in (type, BUILT_IN_TAN); - - if (tanfn != NULL_TREE) - { - tree tmp = build_call_expr_loc (loc, tanfn, 1, - CALL_EXPR_ARG (arg0, 0)); - return fold_build2_loc (loc, RDIV_EXPR, type, - build_real (type, dconst1), tmp); - } - } - - /* Optimize sin(x)/tan(x) as cos(x) if we don't care about - NaNs or Infinities. */ - if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_TAN) - || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_TANF) - || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_TANL))) - { - tree arg00 = CALL_EXPR_ARG (arg0, 0); - tree arg01 = CALL_EXPR_ARG (arg1, 0); - - if (! HONOR_NANS (arg00) - && ! HONOR_INFINITIES (element_mode (arg00)) - && operand_equal_p (arg00, arg01, 0)) - { - tree cosfn = mathfn_built_in (type, BUILT_IN_COS); - - if (cosfn != NULL_TREE) - return build_call_expr_loc (loc, cosfn, 1, arg00); - } - } - - /* Optimize tan(x)/sin(x) as 1.0/cos(x) if we don't care about - NaNs or Infinities. */ - if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_SIN) - || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_SINF) - || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_SINL))) - { - tree arg00 = CALL_EXPR_ARG (arg0, 0); - tree arg01 = CALL_EXPR_ARG (arg1, 0); - - if (! HONOR_NANS (arg00) - && ! HONOR_INFINITIES (element_mode (arg00)) - && operand_equal_p (arg00, arg01, 0)) - { - tree cosfn = mathfn_built_in (type, BUILT_IN_COS); - - if (cosfn != NULL_TREE) - { - tree tmp = build_call_expr_loc (loc, cosfn, 1, arg00); - return fold_build2_loc (loc, RDIV_EXPR, type, - build_real (type, dconst1), - tmp); - } - } - } - - /* Optimize pow(x,c)/x as pow(x,c-1). */ - if (fcode0 == BUILT_IN_POW - || fcode0 == BUILT_IN_POWF - || fcode0 == BUILT_IN_POWL) - { - tree arg00 = CALL_EXPR_ARG (arg0, 0); - tree arg01 = CALL_EXPR_ARG (arg0, 1); - if (TREE_CODE (arg01) == REAL_CST - && !TREE_OVERFLOW (arg01) - && operand_equal_p (arg1, arg00, 0)) - { - tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0); - REAL_VALUE_TYPE c; - tree arg; - - c = TREE_REAL_CST (arg01); - real_arithmetic (&c, MINUS_EXPR, &c, &dconst1); - arg = build_real (type, c); - return build_call_expr_loc (loc, powfn, 2, arg1, arg); - } - } - - /* Optimize a/root(b/c) into a*root(c/b). */ - if (BUILTIN_ROOT_P (fcode1)) - { - tree rootarg = CALL_EXPR_ARG (arg1, 0); - - if (TREE_CODE (rootarg) == RDIV_EXPR) - { - tree rootfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0); - tree b = TREE_OPERAND (rootarg, 0); - tree c = TREE_OPERAND (rootarg, 1); - - tree tmp = fold_build2_loc (loc, RDIV_EXPR, type, c, b); - - tmp = build_call_expr_loc (loc, rootfn, 1, tmp); - return fold_build2_loc (loc, MULT_EXPR, type, arg0, tmp); - } - } - - /* Optimize x/expN(y) into x*expN(-y). */ - if (BUILTIN_EXPONENT_P (fcode1)) - { - tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0); - tree arg = negate_expr (CALL_EXPR_ARG (arg1, 0)); - arg1 = build_call_expr_loc (loc, - expfn, 1, - fold_convert_loc (loc, type, arg)); - return fold_build2_loc (loc, MULT_EXPR, type, arg0, arg1); - } - - /* Optimize x/pow(y,z) into x*pow(y,-z). */ - if (fcode1 == BUILT_IN_POW - || fcode1 == BUILT_IN_POWF - || fcode1 == BUILT_IN_POWL) - { - tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0); - tree arg10 = CALL_EXPR_ARG (arg1, 0); - tree arg11 = CALL_EXPR_ARG (arg1, 1); - tree neg11 = fold_convert_loc (loc, type, - negate_expr (arg11)); - arg1 = build_call_expr_loc (loc, powfn, 2, arg10, neg11); - return fold_build2_loc (loc, MULT_EXPR, type, arg0, arg1); - } - } return NULL_TREE; case TRUNC_DIV_EXPR: diff --git a/gcc/match.pd b/gcc/match.pd index 4230f9a..dc5d6d7 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -55,7 +55,9 @@ along with GCC; see the file COPYING3. If not see (define_operator_list POW10 BUILT_IN_POW10F BUILT_IN_POW10 BUILT_IN_POW10L) (define_operator_list SQRT BUILT_IN_SQRTF BUILT_IN_SQRT BUILT_IN_SQRTL) (define_operator_list CBRT BUILT_IN_CBRTF BUILT_IN_CBRT BUILT_IN_CBRTL) - +(define_operator_list SIN BUILT_IN_SIN BUILT_IN_SINL BUILT_IN_SINF) +(define_operator_list COS BUILT_IN_COS BUILT_IN_COSL BUILT_IN_COSF) +(define_operator_list TAN BUILT_IN_TAN BUILT_IN_TANL BUILT_IN_TANF) /* Simplifications of operations with one constant operand and simplifications to constants or single values. */ @@ -1989,6 +1991,99 @@ along with GCC; see the file COPYING3. If not see /* fold_builtin_logarithm */ (if (flag_unsafe_math_optimizations) + +/* Simplify sqrt(x) * sqrt(x) -> x. */ +(simplify + (mult:c (SQRT @0) (SQRT @0)) + (if (!HONOR_SNANS (element_mode (type))) + @0)) + +/* Simplify root(x) * root(y) -> root(x*y). */ +/* FIXME : cbrt ICE's with AArch64. */ +(for root (SQRT CBRT) +(simplify + (mult:c (root @0) (root @1)) + (root (mult @0 @1)))) + +/* Simplify expN(x) * expN(y) -> expN(x+y). */ +(for exps (EXP EXP2) +/* FIXME : exp2 ICE's with AArch64. */ +(simplify + (mult:c (exps @0) (exps @1)) + (exps (plus @0 @1)))) + +/* Simplify pow(x,y) * pow(x,z) -> pow(x,y+z). */ +(simplify + (mult:c (POW @0 @1) (POW @0 @2)) + (POW @0 (plus @1 @2))) + +/* Simplify pow(x,y) * pow(z,y) -> pow(x*z,y). */ +(simplify + (mult:c (POW @0 @1) (POW @2 @1)) + (POW (mult @0 @2) @1)) + +/* Simplify tan(x) * cos(x) -> sin(x). */ +(simplify + (mult:c (TAN @0) (COS @0)) + (SIN @0)) + +/* Simplify x * pow(x,c) -> pow(x,c+1). */ +(simplify + (mult:c @0 (POW @0 @1)) + (if (TREE_CODE (@1) == REAL_CST + && !TREE_OVERFLOW (@1)) + (POW @0 (plus @1 { build_one_cst (type); })))) + +/* Simplify sin(x) / cos(x) -> tan(x). */ +(simplify + (rdiv (SIN @0) (COS @0)) + (TAN @0)) + +/* Simplify cos(x) / sin(x) -> 1 / tan(x). */ +(simplify + (rdiv (COS @0) (SIN @0)) + (rdiv { build_one_cst (type); } (TAN @0))) + +/* Simplify sin(x) / tan(x) -> cos(x). */ +(simplify + (rdiv (SIN @0) (TAN @0)) + (if (! HONOR_NANS (@0) + && ! HONOR_INFINITIES (element_mode (@0))) + (cos @0))) + +/* Simplify tan(x) / sin(x) -> 1.0 / cos(x). */ +(simplify + (rdiv (TAN @0) (SIN @0)) + (if (! HONOR_NANS (@0) + && ! HONOR_INFINITIES (element_mode (@0))) + (rdiv { build_one_cst (type); } (COS @0)))) + +/* Simplify pow(x,c) / x -> pow(x,c-1). */ +(simplify + (rdiv (POW @0 @1) @0) + (if (TREE_CODE (@1) == REAL_CST + && !TREE_OVERFLOW (@1)) + (POW @0 (minus @1 { build_one_cst (type); })))) + +/* Simplify a/root(b/c) into a*root(c/b). */ +/* FIXME : cbrt ICE's with AArch64. */ +(for root (SQRT CBRT) +(simplify + (rdiv @0 (root (rdiv @1 @2))) + (mult @0 (root (rdiv @2 @1))))) + +/* Simplify x / expN(y) into x*expN(-y). */ +/* FIXME : exp2 ICE's with AArch64. */ +(for exps (EXP EXP2) +(simplify + (rdiv @0 (exps @1)) + (mult @0 (exps (negate @1))))) + +/* Simplify x / pow (y,z) -> x * pow(y,-z). */ +(simplify + (rdiv @0 (POW @1 @2)) + (mult @0 (POW @1 (negate @2)))) + /* Special case, optimize logN(expN(x)) = x. */ (for logs (LOG LOG2 LOG10) exps (EXP EXP2 EXP10)