diff options
author | Jakub Jelinek <jakub@redhat.com> | 2018-02-13 09:34:42 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2018-02-13 09:34:42 +0100 |
commit | 848bb6fc0e502345536b25e1a110eb7f01eccbc1 (patch) | |
tree | d7abb7ffececb36706b28e05151701a372dc8cc5 /gcc/tree-vect-patterns.c | |
parent | f4b29321048fa82c754f04814dbd46d92773e72a (diff) | |
download | gcc-848bb6fc0e502345536b25e1a110eb7f01eccbc1.zip gcc-848bb6fc0e502345536b25e1a110eb7f01eccbc1.tar.gz gcc-848bb6fc0e502345536b25e1a110eb7f01eccbc1.tar.bz2 |
re PR middle-end/84309 (Wrong-code with -ffast-math)
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.
* generic-match-head.c (canonicalize_math_after_vectorization_p): New
inline function.
* gimple-match-head.c (canonicalize_math_after_vectorization_p): New
inline function.
* omp-simd-clone.h: New file.
* omp-simd-clone.c: Include omp-simd-clone.h.
(expand_simd_clones): No longer static.
* tree-vect-patterns.c: Include fold-const-call.h, attribs.h,
cgraph.h and omp-simd-clone.h.
(vect_recog_pow_pattern): Optimize pow(C,x) to exp(log(C)*x).
(vect_recog_widen_shift_pattern): Formatting fix.
(vect_pattern_recog_1): Don't check optab for calls.
* gcc.dg/pr84309.c: New test.
* gcc.target/i386/pr84309.c: New test.
From-SVN: r257617
Diffstat (limited to 'gcc/tree-vect-patterns.c')
-rw-r--r-- | gcc/tree-vect-patterns.c | 107 |
1 files changed, 83 insertions, 24 deletions
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 1279352..25a2efb 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -41,6 +41,10 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "internal-fn.h" #include "case-cfn-macros.h" +#include "fold-const-call.h" +#include "attribs.h" +#include "cgraph.h" +#include "omp-simd-clone.h" /* Pattern recognition functions */ static gimple *vect_recog_widen_sum_pattern (vec<gimple *> *, tree *, @@ -1049,7 +1053,7 @@ vect_recog_pow_pattern (vec<gimple *> *stmts, tree *type_in, tree *type_out) { gimple *last_stmt = (*stmts)[0]; - tree base, exp = NULL; + tree base, exp; gimple *stmt; tree var; @@ -1060,17 +1064,77 @@ vect_recog_pow_pattern (vec<gimple *> *stmts, tree *type_in, { CASE_CFN_POW: CASE_CFN_POWI: - base = gimple_call_arg (last_stmt, 0); - exp = gimple_call_arg (last_stmt, 1); - if (TREE_CODE (exp) != REAL_CST - && TREE_CODE (exp) != INTEGER_CST) - return NULL; break; default: return NULL; } + base = gimple_call_arg (last_stmt, 0); + exp = gimple_call_arg (last_stmt, 1); + if (TREE_CODE (exp) != REAL_CST + && TREE_CODE (exp) != INTEGER_CST) + { + if (flag_unsafe_math_optimizations + && TREE_CODE (base) == REAL_CST + && !gimple_call_internal_p (last_stmt)) + { + combined_fn log_cfn; + built_in_function exp_bfn; + switch (DECL_FUNCTION_CODE (gimple_call_fndecl (last_stmt))) + { + case BUILT_IN_POW: + log_cfn = CFN_BUILT_IN_LOG; + exp_bfn = BUILT_IN_EXP; + break; + case BUILT_IN_POWF: + log_cfn = CFN_BUILT_IN_LOGF; + exp_bfn = BUILT_IN_EXPF; + break; + case BUILT_IN_POWL: + log_cfn = CFN_BUILT_IN_LOGL; + exp_bfn = BUILT_IN_EXPL; + break; + default: + return NULL; + } + tree logc = fold_const_call (log_cfn, TREE_TYPE (base), base); + tree exp_decl = builtin_decl_implicit (exp_bfn); + /* Optimize pow (C, x) as exp (log (C) * x). Normally match.pd + does that, but if C is a power of 2, we want to use + exp2 (log2 (C) * x) in the non-vectorized version, but for + vectorization we don't have vectorized exp2. */ + if (logc + && TREE_CODE (logc) == REAL_CST + && exp_decl + && lookup_attribute ("omp declare simd", + DECL_ATTRIBUTES (exp_decl))) + { + cgraph_node *node = cgraph_node::get_create (exp_decl); + if (node->simd_clones == NULL) + { + if (node->definition) + return NULL; + expand_simd_clones (node); + if (node->simd_clones == NULL) + return NULL; + } + stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt); + tree def = vect_recog_temp_ssa_var (TREE_TYPE (base), NULL); + gimple *g = gimple_build_assign (def, MULT_EXPR, exp, logc); + new_pattern_def_seq (stmt_vinfo, g); + *type_in = TREE_TYPE (base); + *type_out = NULL_TREE; + tree res = vect_recog_temp_ssa_var (TREE_TYPE (base), NULL); + g = gimple_build_call (exp_decl, 1, def); + gimple_call_set_lhs (g, res); + return g; + } + } + + return NULL; + } + /* We now have a pow or powi builtin function call with a constant exponent. */ @@ -1744,8 +1808,8 @@ vect_recog_widen_shift_pattern (vec<gimple *> *stmts, /* Pattern supported. Create a stmt to be used to replace the pattern. */ var = vect_recog_temp_ssa_var (type, NULL); - pattern_stmt = - gimple_build_assign (var, WIDEN_LSHIFT_EXPR, oprnd0, oprnd1); + pattern_stmt + = gimple_build_assign (var, WIDEN_LSHIFT_EXPR, oprnd0, oprnd1); if (wstmt) { stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt); @@ -4439,10 +4503,6 @@ vect_pattern_recog_1 (vect_recog_func *recog_func, } else { - machine_mode vec_mode; - enum insn_code icode; - optab optab; - /* Check target support */ type_in = get_vectype_for_scalar_type (type_in); if (!type_in) @@ -4456,19 +4516,18 @@ vect_pattern_recog_1 (vect_recog_func *recog_func, pattern_vectype = type_out; if (is_gimple_assign (pattern_stmt)) - code = gimple_assign_rhs_code (pattern_stmt); - else - { - gcc_assert (is_gimple_call (pattern_stmt)); - code = CALL_EXPR; + { + enum insn_code icode; + code = gimple_assign_rhs_code (pattern_stmt); + optab optab = optab_for_tree_code (code, type_in, optab_default); + machine_mode vec_mode = TYPE_MODE (type_in); + if (!optab + || (icode = optab_handler (optab, vec_mode)) == CODE_FOR_nothing + || (insn_data[icode].operand[0].mode != TYPE_MODE (type_out))) + return false; } - - optab = optab_for_tree_code (code, type_in, optab_default); - vec_mode = TYPE_MODE (type_in); - if (!optab - || (icode = optab_handler (optab, vec_mode)) == CODE_FOR_nothing - || (insn_data[icode].operand[0].mode != TYPE_MODE (type_out))) - return false; + else + gcc_assert (is_gimple_call (pattern_stmt)); } /* Found a vectorizable pattern. */ |