aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-match-head.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2015-11-17 18:47:44 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2015-11-17 18:47:44 +0000
commitc9e926ce2bdc8bdce5fd9892443cf6147868e7f6 (patch)
tree85646c7ff97526585c06596877a86bf8c493a6b3 /gcc/gimple-match-head.c
parentb03ff92e67280a98ab1587e0460069eea0fd5a8b (diff)
downloadgcc-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.c186
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);