aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-vect-patterns.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2018-02-13 09:34:42 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2018-02-13 09:34:42 +0100
commit848bb6fc0e502345536b25e1a110eb7f01eccbc1 (patch)
treed7abb7ffececb36706b28e05151701a372dc8cc5 /gcc/tree-vect-patterns.c
parentf4b29321048fa82c754f04814dbd46d92773e72a (diff)
downloadgcc-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.c107
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. */