diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2015-11-17 18:47:44 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2015-11-17 18:47:44 +0000 |
commit | c9e926ce2bdc8bdce5fd9892443cf6147868e7f6 (patch) | |
tree | 85646c7ff97526585c06596877a86bf8c493a6b3 /gcc/gimple-match-head.c | |
parent | b03ff92e67280a98ab1587e0460069eea0fd5a8b (diff) | |
download | gcc-c9e926ce2bdc8bdce5fd9892443cf6147868e7f6.zip gcc-c9e926ce2bdc8bdce5fd9892443cf6147868e7f6.tar.gz gcc-c9e926ce2bdc8bdce5fd9892443cf6147868e7f6.tar.bz2 |
Add genmatch support for internal functions
This patch makes genmatch match calls based on combined_fn rather
than built_in_function and extends the matching to internal functions.
It also uses fold_const_call to fold the calls to a constant, rather
than going through fold_builtin_n.
In order to slightly simplify the code and remove potential
ambiguity, the patch enforces lower case for tree codes
(foo->FOO_EXPR), caps for functions (no built_in_hypot->BUILT_IN_HYPOT)
and requires an exact match for user-defined identifiers. The first two
were already met in practice but there were a couple of cases where
operator lists were defined in one case and used in another.
Tested on x86_64-linux-gnu, aarch64-linux-gnu and arm-linux-gnueabi.
gcc/
* match.pd: Use HYPOT and COS rather than hypot and cos.
Use CASE_CFN_* macros. Guard log/exp folds with
SCALAR_FLOAT_TYPE_P.
* genmatch.c (internal_fn): New enum.
(fn_id::fn): Change to an unsigned int.
(fn_id::fn_id): Accept internal_fn too.
(add_builtin): Rename to...
(add_function): ...this and turn into a template.
(get_operator): Only try one variation if the original name fails.
Only add _EXPR if the original name was all lower case.
Try converting internal and built-in function names to their
CFN equivalents.
(expr::gen_transform): Use maybe_build_call_expr_loc for generic.
(dt_simplify::gen_1): Likewise.
(dt_node::gen_kids_1): Use gimple_call_combined_fn for gimple
and get_call_combined_fn for generic.
(dt_simplify::gen): Use combined_fn as the type of fn_ids.
(decision_tree::gen): Likewise.
(main): Use lower case in the strings for {VIEW_,}CONVERT[012].
Use add_function rather than add_builtin. Register internal
functions too.
* generic-match-head.c: Include case-cfn-macros.h.
* gimple-fold.c (replace_stmt_with_simplification): Use
gimple_call_combined_fn to test whether we can keep an
existing call.
* gimple-match.h (code_helper): Replace built_in_function
with combined_fn.
* gimple-match-head.c: Include fold-const-call.h, internal-fn.h
and case-fn-macros.h.
(gimple_resimplify1): Use fold_const_call.
(gimple_resimplify2, gimple_resimplify3): Likewise.
(build_call_internal, build_call): New functions.
(maybe_push_res_to_seq): Use them.
(gimple_simplify): Use fold_const_call. Set *rcode to a combined_fn
rather than a built-in function.
* tree.h (build_call_expr_internal_loc): Declare.
(maybe_build_call_expr_loc): Likewise.
* tree.c (build_call_expr_internal_loc_array): New function.
(maybe_build_call_expr_loc): Likewise.
From-SVN: r230484
Diffstat (limited to 'gcc/gimple-match-head.c')
-rw-r--r-- | gcc/gimple-match-head.c | 186 |
1 files changed, 78 insertions, 108 deletions
diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c index 030cc74..bdc1f98 100644 --- a/gcc/gimple-match-head.c +++ b/gcc/gimple-match-head.c @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see #include "ssa.h" #include "cgraph.h" #include "fold-const.h" +#include "fold-const-call.h" #include "stor-layout.h" #include "gimple-fold.h" #include "calls.h" @@ -35,6 +36,8 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "gimple-match.h" #include "tree-pass.h" +#include "internal-fn.h" +#include "case-cfn-macros.h" /* Forward declarations of the private auto-generated matchers. @@ -81,19 +84,7 @@ gimple_resimplify1 (gimple_seq *seq, if (res_code->is_tree_code ()) tem = const_unop (*res_code, type, res_ops[0]); else - { - tree decl = builtin_decl_implicit (*res_code); - if (decl) - { - tem = fold_builtin_n (UNKNOWN_LOCATION, decl, res_ops, 1, false); - if (tem) - { - /* fold_builtin_n wraps the result inside a NOP_EXPR. */ - STRIP_NOPS (tem); - tem = fold_convert (type, tem); - } - } - } + tem = fold_const_call (combined_fn (*res_code), type, res_ops[0]); if (tem != NULL_TREE && CONSTANT_CLASS_P (tem)) { @@ -137,19 +128,8 @@ gimple_resimplify2 (gimple_seq *seq, if (res_code->is_tree_code ()) tem = const_binop (*res_code, type, res_ops[0], res_ops[1]); else - { - tree decl = builtin_decl_implicit (*res_code); - if (decl) - { - tem = fold_builtin_n (UNKNOWN_LOCATION, decl, res_ops, 2, false); - if (tem) - { - /* fold_builtin_n wraps the result inside a NOP_EXPR. */ - STRIP_NOPS (tem); - tem = fold_convert (type, tem); - } - } - } + tem = fold_const_call (combined_fn (*res_code), type, + res_ops[0], res_ops[1]); if (tem != NULL_TREE && CONSTANT_CLASS_P (tem)) { @@ -208,19 +188,8 @@ gimple_resimplify3 (gimple_seq *seq, tem = fold_ternary/*_to_constant*/ (*res_code, type, res_ops[0], res_ops[1], res_ops[2]); else - { - tree decl = builtin_decl_implicit (*res_code); - if (decl) - { - tem = fold_builtin_n (UNKNOWN_LOCATION, decl, res_ops, 3, false); - if (tem) - { - /* fold_builtin_n wraps the result inside a NOP_EXPR. */ - STRIP_NOPS (tem); - tem = fold_convert (type, tem); - } - } - } + tem = fold_const_call (combined_fn (*res_code), type, + res_ops[0], res_ops[1], res_ops[2]); if (tem != NULL_TREE && CONSTANT_CLASS_P (tem)) { @@ -282,6 +251,22 @@ maybe_build_generic_op (enum tree_code code, tree type, tree (*mprts_hook) (code_helper, tree, tree *); +/* Try to build a call to FN with return type TYPE and the NARGS + arguments given in OPS. Return null if the target doesn't support + the function. */ + +static gcall * +build_call_internal (internal_fn fn, tree type, unsigned int nargs, tree *ops) +{ + if (direct_internal_fn_p (fn)) + { + tree_pair types = direct_internal_fn_types (fn, type, ops); + if (!direct_internal_fn_supported_p (fn, types)) + return NULL; + } + return gimple_build_call_internal (fn, nargs, ops[0], ops[1], ops[2]); +} + /* Push the exploded expression described by RCODE, TYPE and OPS as a statement to SEQ if necessary and return a gimple value denoting the value of the expression. If RES is not NULL @@ -333,12 +318,7 @@ maybe_push_res_to_seq (code_helper rcode, tree type, tree *ops, { if (!seq) return NULL_TREE; - tree decl = builtin_decl_implicit (rcode); - if (!decl) - return NULL_TREE; - /* We can't and should not emit calls to non-const functions. */ - if (!(flags_from_decl_or_type (decl) & ECF_CONST)) - return NULL_TREE; + combined_fn fn = rcode; /* Play safe and do not allow abnormals to be mentioned in newly created statements. */ unsigned nargs; @@ -351,6 +331,28 @@ maybe_push_res_to_seq (code_helper rcode, tree type, tree *ops, return NULL_TREE; } gcc_assert (nargs != 0); + gcall *new_stmt = NULL; + if (internal_fn_p (fn)) + { + /* Generate the given function if we can. */ + internal_fn ifn = as_internal_fn (fn); + new_stmt = build_call_internal (ifn, type, nargs, ops); + if (!new_stmt) + return NULL_TREE; + } + else + { + /* Find the function we want to call. */ + tree decl = builtin_decl_implicit (as_builtin_fn (fn)); + if (!decl) + return NULL; + + /* We can't and should not emit calls to non-const functions. */ + if (!(flags_from_decl_or_type (decl) & ECF_CONST)) + return NULL; + + new_stmt = gimple_build_call (decl, nargs, ops[0], ops[1], ops[2]); + } if (!res) { if (gimple_in_ssa_p (cfun)) @@ -358,7 +360,6 @@ maybe_push_res_to_seq (code_helper rcode, tree type, tree *ops, else res = create_tmp_reg (type); } - gimple *new_stmt = gimple_build_call (decl, nargs, ops[0], ops[1], ops[2]); gimple_call_set_lhs (new_stmt, res); gimple_seq_add_stmt_without_update (seq, new_stmt); return res; @@ -471,25 +472,15 @@ gimple_simplify (enum built_in_function fn, tree type, { if (constant_for_folding (arg0)) { - tree decl = builtin_decl_implicit (fn); - if (decl) - { - tree res = fold_builtin_n (UNKNOWN_LOCATION, decl, &arg0, 1, false); - if (res) - { - /* fold_builtin_n wraps the result inside a NOP_EXPR. */ - STRIP_NOPS (res); - res = fold_convert (type, res); - if (CONSTANT_CLASS_P (res)) - return res; - } - } + tree res = fold_const_call (as_combined_fn (fn), type, arg0); + if (res && CONSTANT_CLASS_P (res)) + return res; } code_helper rcode; tree ops[3] = {}; if (!gimple_simplify (&rcode, ops, seq, valueize, - fn, type, arg0)) + as_combined_fn (fn), type, arg0)) return NULL_TREE; return maybe_push_res_to_seq (rcode, type, ops, seq); } @@ -504,28 +495,15 @@ gimple_simplify (enum built_in_function fn, tree type, if (constant_for_folding (arg0) && constant_for_folding (arg1)) { - tree decl = builtin_decl_implicit (fn); - if (decl) - { - tree args[2]; - args[0] = arg0; - args[1] = arg1; - tree res = fold_builtin_n (UNKNOWN_LOCATION, decl, args, 2, false); - if (res) - { - /* fold_builtin_n wraps the result inside a NOP_EXPR. */ - STRIP_NOPS (res); - res = fold_convert (type, res); - if (CONSTANT_CLASS_P (res)) - return res; - } - } + tree res = fold_const_call (as_combined_fn (fn), type, arg0, arg1); + if (res && CONSTANT_CLASS_P (res)) + return res; } code_helper rcode; tree ops[3] = {}; if (!gimple_simplify (&rcode, ops, seq, valueize, - fn, type, arg0, arg1)) + as_combined_fn (fn), type, arg0, arg1)) return NULL_TREE; return maybe_push_res_to_seq (rcode, type, ops, seq); } @@ -541,29 +519,15 @@ gimple_simplify (enum built_in_function fn, tree type, && constant_for_folding (arg1) && constant_for_folding (arg2)) { - tree decl = builtin_decl_implicit (fn); - if (decl) - { - tree args[3]; - args[0] = arg0; - args[1] = arg1; - args[2] = arg2; - tree res = fold_builtin_n (UNKNOWN_LOCATION, decl, args, 3, false); - if (res) - { - /* fold_builtin_n wraps the result inside a NOP_EXPR. */ - STRIP_NOPS (res); - res = fold_convert (type, res); - if (CONSTANT_CLASS_P (res)) - return res; - } - } + tree res = fold_const_call (as_combined_fn (fn), type, arg0, arg1, arg2); + if (res && CONSTANT_CLASS_P (res)) + return res; } code_helper rcode; tree ops[3] = {}; if (!gimple_simplify (&rcode, ops, seq, valueize, - fn, type, arg0, arg1, arg2)) + as_combined_fn (fn), type, arg0, arg1, arg2)) return NULL_TREE; return maybe_push_res_to_seq (rcode, type, ops, seq); } @@ -726,23 +690,29 @@ gimple_simplify (gimple *stmt, && gimple_call_num_args (stmt) >= 1 && gimple_call_num_args (stmt) <= 3) { - tree fn = gimple_call_fn (stmt); - /* ??? Internal function support missing. */ - if (!fn) - return false; bool valueized = false; - fn = do_valueize (fn, top_valueize, valueized); - if (TREE_CODE (fn) != ADDR_EXPR - || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL) - return false; + if (gimple_call_internal_p (stmt)) + *rcode = as_combined_fn (gimple_call_internal_fn (stmt)); + else + { + tree fn = gimple_call_fn (stmt); + if (!fn) + return false; - tree decl = TREE_OPERAND (fn, 0); - if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL - || !gimple_builtin_call_types_compatible_p (stmt, decl)) - return false; + fn = do_valueize (fn, top_valueize, valueized); + if (TREE_CODE (fn) != ADDR_EXPR + || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL) + return false; + + tree decl = TREE_OPERAND (fn, 0); + if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL + || !gimple_builtin_call_types_compatible_p (stmt, decl)) + return false; + + *rcode = as_combined_fn (DECL_FUNCTION_CODE (decl)); + } tree type = TREE_TYPE (gimple_call_lhs (stmt)); - *rcode = DECL_FUNCTION_CODE (decl); for (unsigned i = 0; i < gimple_call_num_args (stmt); ++i) { tree arg = gimple_call_arg (stmt, i); |