Commit 5d75ad95 by Richard Sandiford Committed by Richard Sandiford

Add a class to represent a gimple match result

Gimple match results are represented by a code_helper for the operation,
a tree for the type, and an array of three trees for the operands.
This patch wraps them up in a class so that they don't need to be
passed around individually.

The main reason for doing this is to make it easier to increase the
number of operands (for calls) or to support more complicated kinds
of operation.  But passing around fewer operands also helps to reduce
the size of gimple-match.o (about 7% for development builds and 4% for
release builds).

2018-05-24  Richard Sandiford  <richard.sandiford@linaro.org>

gcc/
	* gimple-match.h (gimple_match_op): New class.
	(mprts_hook): Replace parameters with a gimple_match_op *.
	(maybe_build_generic_op): Likewise.
	(gimple_simplified_result_is_gimple_val): Replace parameters with
	a const gimple_match_op *.
	(gimple_simplify): Replace code_helper * and tree * parameters with
	a gimple_match_op * parameter.
	(gimple_resimplify1): Replace code_helper *, tree and tree *
	parameters with a gimple_match_op * parameter.
	(gimple_resimplify2): Likewise.
	(gimple_resimplify3): Likewise.
	(maybe_push_res_to_seq): Replace code_helper, tree and tree *
	parameters with a gimple_match_op * parameter.
	* gimple-match-head.c (gimple_simplify): Change prototypes of
	auto-generated functions to take a gimple_match_op * instead of
	separate code_helper * and tree * parameters.  Make the same
	change in the top-level overload and update calls to the
	gimple_resimplify routines.  Update calls to the auto-generated
	functions and to maybe_push_res_to_seq in the publicly-facing
	operation-specific gimple_simplify overloads.
	(gimple_match_op::MAX_NUM_OPS): Define.
	(gimple_resimplify1): Replace rcode and ops with a single res_op
	parameter.  Update call to gimple_simplify.
	(gimple_resimplify2): Likewise.
	(gimple_resimplify3): Likewise.
	(mprts_hook): Replace parameters with a gimple_match_op *.
	(maybe_build_generic_op): Likewise.
	(build_call_internal): Replace type, nargs and ops with
	a gimple_match_op *.
	(maybe_push_res_to_seq): Replace res_code, type and ops parameters
	with a single gimple_match_op *.  Update calls to mprts_hook,
	build_call_internal and gimple_simplified_result_is_gimple_val.
	Factor out code that is common to the tree_code and combined_fn cases.
	* genmatch.c (expr::gen_transform): Replace tem_code and
	tem_ops with a gimple_match_op called tem_op.  Update calls
	to the gimple_resimplify functions and maybe_push_res_to_seq.
	(dt_simplify::gen_1): Manipulate res_op instead of res_code and
	res_ops.  Update call to the gimple_resimplify functions.
	(dt_simplify::gen): Pass res_op instead of res_code and res_ops.
	(decision_tree::gen): Make the functions take a gimple_match_op *
	called res_op instead of separate res_code and res_ops parameters.
	Update call accordingly.
	* gimple-fold.c (replace_stmt_with_simplification): Replace rcode
	and ops with a single res_op parameter.  Update calls to
	maybe_build_generic_op and maybe_push_res_to_seq.
	(fold_stmt_1): Update calls to gimple_simplify and
	replace_stmt_with_simplification.
	(gimple_fold_stmt_to_constant_1): Update calls to gimple_simplify
	and gimple_simplified_result_is_gimple_val.
	* tree-cfgcleanup.c (cleanup_control_expr_graph): Update call to
	gimple_simplify.
	* tree-ssa-sccvn.c (vn_lookup_simplify_result): Replace parameters
	with a gimple_match_op *.
	(vn_nary_build_or_lookup): Likewise.  Update call to
	vn_nary_build_or_lookup_1.
	(vn_nary_build_or_lookup_1): Replace rcode, type and ops with a
	gimple_match_op *.  Update calls to the gimple_resimplify routines
	and to gimple_simplified_result_is_gimple_val.
	(vn_nary_simplify): Update call to vn_nary_build_or_lookup_1.
	Use gimple_match_op::MAX_NUM_OPS instead of a hard-coded 3.
	(vn_reference_lookup_3): Update call to vn_nary_build_or_lookup.
	(visit_nary_op): Likewise.
	(visit_reference_op_load): Likewise.

From-SVN: r260634
parent e29ea483
2018-05-24 Richard Sandiford <richard.sandiford@linaro.org>
* gimple-match.h (gimple_match_op): New class.
(mprts_hook): Replace parameters with a gimple_match_op *.
(maybe_build_generic_op): Likewise.
(gimple_simplified_result_is_gimple_val): Replace parameters with
a const gimple_match_op *.
(gimple_simplify): Replace code_helper * and tree * parameters with
a gimple_match_op * parameter.
(gimple_resimplify1): Replace code_helper *, tree and tree *
parameters with a gimple_match_op * parameter.
(gimple_resimplify2): Likewise.
(gimple_resimplify3): Likewise.
(maybe_push_res_to_seq): Replace code_helper, tree and tree *
parameters with a gimple_match_op * parameter.
* gimple-match-head.c (gimple_simplify): Change prototypes of
auto-generated functions to take a gimple_match_op * instead of
separate code_helper * and tree * parameters. Make the same
change in the top-level overload and update calls to the
gimple_resimplify routines. Update calls to the auto-generated
functions and to maybe_push_res_to_seq in the publicly-facing
operation-specific gimple_simplify overloads.
(gimple_match_op::MAX_NUM_OPS): Define.
(gimple_resimplify1): Replace rcode and ops with a single res_op
parameter. Update call to gimple_simplify.
(gimple_resimplify2): Likewise.
(gimple_resimplify3): Likewise.
(mprts_hook): Replace parameters with a gimple_match_op *.
(maybe_build_generic_op): Likewise.
(build_call_internal): Replace type, nargs and ops with
a gimple_match_op *.
(maybe_push_res_to_seq): Replace res_code, type and ops parameters
with a single gimple_match_op *. Update calls to mprts_hook,
build_call_internal and gimple_simplified_result_is_gimple_val.
Factor out code that is common to the tree_code and combined_fn cases.
* genmatch.c (expr::gen_transform): Replace tem_code and
tem_ops with a gimple_match_op called tem_op. Update calls
to the gimple_resimplify functions and maybe_push_res_to_seq.
(dt_simplify::gen_1): Manipulate res_op instead of res_code and
res_ops. Update call to the gimple_resimplify functions.
(dt_simplify::gen): Pass res_op instead of res_code and res_ops.
(decision_tree::gen): Make the functions take a gimple_match_op *
called res_op instead of separate res_code and res_ops parameters.
Update call accordingly.
* gimple-fold.c (replace_stmt_with_simplification): Replace rcode
and ops with a single res_op parameter. Update calls to
maybe_build_generic_op and maybe_push_res_to_seq.
(fold_stmt_1): Update calls to gimple_simplify and
replace_stmt_with_simplification.
(gimple_fold_stmt_to_constant_1): Update calls to gimple_simplify
and gimple_simplified_result_is_gimple_val.
* tree-cfgcleanup.c (cleanup_control_expr_graph): Update call to
gimple_simplify.
* tree-ssa-sccvn.c (vn_lookup_simplify_result): Replace parameters
with a gimple_match_op *.
(vn_nary_build_or_lookup): Likewise. Update call to
vn_nary_build_or_lookup_1.
(vn_nary_build_or_lookup_1): Replace rcode, type and ops with a
gimple_match_op *. Update calls to the gimple_resimplify routines
and to gimple_simplified_result_is_gimple_val.
(vn_nary_simplify): Update call to vn_nary_build_or_lookup_1.
Use gimple_match_op::MAX_NUM_OPS instead of a hard-coded 3.
(vn_reference_lookup_3): Update call to vn_nary_build_or_lookup.
(visit_nary_op): Likewise.
(visit_reference_op_load): Likewise.
2018-05-23 Luis Machado <luis.machado@linaro.org> 2018-05-23 Luis Machado <luis.machado@linaro.org>
* tree-ssa-loop-prefetch.c (should_issue_prefetch_p): Use correct type * tree-ssa-loop-prefetch.c (should_issue_prefetch_p): Use correct type
......
...@@ -2484,17 +2484,16 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, ...@@ -2484,17 +2484,16 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
/* ??? Building a stmt can fail for various reasons here, seq being /* ??? Building a stmt can fail for various reasons here, seq being
NULL or the stmt referencing SSA names occuring in abnormal PHIs. NULL or the stmt referencing SSA names occuring in abnormal PHIs.
So if we fail here we should continue matching other patterns. */ So if we fail here we should continue matching other patterns. */
fprintf_indent (f, indent, "code_helper tem_code = %s;\n", opr_name); fprintf_indent (f, indent, "gimple_match_op tem_op (%s, %s",
fprintf_indent (f, indent, "tree tem_ops[3] = { "); opr_name, type);
for (unsigned i = 0; i < ops.length (); ++i) for (unsigned i = 0; i < ops.length (); ++i)
fprintf (f, "ops%d[%u]%s", depth, i, fprintf (f, ", ops%d[%u]", depth, i);
i == ops.length () - 1 ? " };\n" : ", "); fprintf (f, ");\n");
fprintf_indent (f, indent, fprintf_indent (f, indent,
"gimple_resimplify%d (lseq, &tem_code, %s, tem_ops, valueize);\n", "gimple_resimplify%d (lseq, &tem_op, valueize);\n",
ops.length (), type); ops.length ());
fprintf_indent (f, indent, fprintf_indent (f, indent,
"res = maybe_push_res_to_seq (tem_code, %s, tem_ops, lseq);\n", "res = maybe_push_res_to_seq (&tem_op, lseq);\n");
type);
fprintf_indent (f, indent, fprintf_indent (f, indent,
"if (!res) return false;\n"); "if (!res) return false;\n");
if (*opr == CONVERT_EXPR) if (*opr == CONVERT_EXPR)
...@@ -3322,17 +3321,22 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) ...@@ -3322,17 +3321,22 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
else if (is_a <predicate_id *> (opr)) else if (is_a <predicate_id *> (opr))
is_predicate = true; is_predicate = true;
if (!is_predicate) if (!is_predicate)
fprintf_indent (f, indent, "*res_code = %s;\n", fprintf_indent (f, indent, "res_op->set_op (%s, type, %d);\n",
*e->operation == CONVERT_EXPR *e->operation == CONVERT_EXPR
? "NOP_EXPR" : e->operation->id); ? "NOP_EXPR" : e->operation->id,
e->ops.length ());
for (unsigned j = 0; j < e->ops.length (); ++j) for (unsigned j = 0; j < e->ops.length (); ++j)
{ {
char dest[32]; char dest[32];
snprintf (dest, 32, "res_ops[%d]", j); if (is_predicate)
snprintf (dest, 32, "res_ops[%d]", j);
else
snprintf (dest, 32, "res_op->ops[%d]", j);
const char *optype const char *optype
= get_operand_type (opr, j, = get_operand_type (opr, j,
"type", e->expr_type, "type", e->expr_type,
j == 0 ? NULL : "TREE_TYPE (res_ops[0])"); j == 0 ? NULL
: "TREE_TYPE (res_op->ops[0])");
/* We need to expand GENERIC conditions we captured from /* We need to expand GENERIC conditions we captured from
COND_EXPRs and we need to unshare them when substituting COND_EXPRs and we need to unshare them when substituting
into COND_EXPRs. */ into COND_EXPRs. */
...@@ -3348,30 +3352,29 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) ...@@ -3348,30 +3352,29 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
gimple_build w/o actually building the stmt. */ gimple_build w/o actually building the stmt. */
if (!is_predicate) if (!is_predicate)
fprintf_indent (f, indent, fprintf_indent (f, indent,
"gimple_resimplify%d (lseq, res_code, type, " "gimple_resimplify%d (lseq, res_op,"
"res_ops, valueize);\n", e->ops.length ()); " valueize);\n", e->ops.length ());
} }
else if (result->type == operand::OP_CAPTURE else if (result->type == operand::OP_CAPTURE
|| result->type == operand::OP_C_EXPR) || result->type == operand::OP_C_EXPR)
{ {
result->gen_transform (f, indent, "res_ops[0]", true, 1, "type", fprintf_indent (f, indent, "tree tem;\n");
result->gen_transform (f, indent, "tem", true, 1, "type",
&cinfo, indexes); &cinfo, indexes);
fprintf_indent (f, indent, "*res_code = TREE_CODE (res_ops[0]);\n"); fprintf_indent (f, indent, "res_op->set_value (tem);\n");
if (is_a <capture *> (result) if (is_a <capture *> (result)
&& cinfo.info[as_a <capture *> (result)->where].cond_expr_cond_p) && cinfo.info[as_a <capture *> (result)->where].cond_expr_cond_p)
{ {
/* ??? Stupid tcc_comparison GENERIC trees in COND_EXPRs. Deal /* ??? Stupid tcc_comparison GENERIC trees in COND_EXPRs. Deal
with substituting a capture of that. */ with substituting a capture of that. */
fprintf_indent (f, indent, fprintf_indent (f, indent,
"if (COMPARISON_CLASS_P (res_ops[0]))\n"); "if (COMPARISON_CLASS_P (tem))\n");
fprintf_indent (f, indent, fprintf_indent (f, indent,
" {\n"); " {\n");
fprintf_indent (f, indent, fprintf_indent (f, indent,
" tree tem = res_ops[0];\n"); " res_op->ops[0] = TREE_OPERAND (tem, 0);\n");
fprintf_indent (f, indent,
" res_ops[0] = TREE_OPERAND (tem, 0);\n");
fprintf_indent (f, indent, fprintf_indent (f, indent,
" res_ops[1] = TREE_OPERAND (tem, 1);\n"); " res_op->ops[1] = TREE_OPERAND (tem, 1);\n");
fprintf_indent (f, indent, fprintf_indent (f, indent,
" }\n"); " }\n");
} }
...@@ -3529,7 +3532,7 @@ dt_simplify::gen (FILE *f, int indent, bool gimple) ...@@ -3529,7 +3532,7 @@ dt_simplify::gen (FILE *f, int indent, bool gimple)
{ {
if (gimple) if (gimple)
{ {
fprintf_indent (f, indent, "if (%s (res_code, res_ops, seq, " fprintf_indent (f, indent, "if (%s (res_op, seq, "
"valueize, type, captures", info->fname); "valueize, type, captures", info->fname);
for (unsigned i = 0; i < s->for_subst_vec.length (); ++i) for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
if (s->for_subst_vec[i].first->used) if (s->for_subst_vec[i].first->used)
...@@ -3697,9 +3700,8 @@ decision_tree::gen (FILE *f, bool gimple) ...@@ -3697,9 +3700,8 @@ decision_tree::gen (FILE *f, bool gimple)
fcnt++); fcnt++);
if (gimple) if (gimple)
fprintf (f, "\nstatic bool\n" fprintf (f, "\nstatic bool\n"
"%s (code_helper *res_code, tree *res_ops,\n" "%s (gimple_match_op *res_op, gimple_seq *seq,\n"
" gimple_seq *seq, tree (*valueize)(tree) " " tree (*valueize)(tree) ATTRIBUTE_UNUSED,\n"
"ATTRIBUTE_UNUSED,\n"
" const tree ARG_UNUSED (type), tree *ARG_UNUSED " " const tree ARG_UNUSED (type), tree *ARG_UNUSED "
"(captures)\n", "(captures)\n",
s->fname); s->fname);
...@@ -3753,8 +3755,9 @@ decision_tree::gen (FILE *f, bool gimple) ...@@ -3753,8 +3755,9 @@ decision_tree::gen (FILE *f, bool gimple)
if (gimple) if (gimple)
fprintf (f, "\nstatic bool\n" fprintf (f, "\nstatic bool\n"
"gimple_simplify_%s (code_helper *res_code, tree *res_ops,\n" "gimple_simplify_%s (gimple_match_op *res_op,"
" gimple_seq *seq, tree (*valueize)(tree) " " gimple_seq *seq,\n"
" tree (*valueize)(tree) "
"ATTRIBUTE_UNUSED,\n" "ATTRIBUTE_UNUSED,\n"
" code_helper ARG_UNUSED (code), tree " " code_helper ARG_UNUSED (code), tree "
"ARG_UNUSED (type)\n", "ARG_UNUSED (type)\n",
...@@ -3780,8 +3783,8 @@ decision_tree::gen (FILE *f, bool gimple) ...@@ -3780,8 +3783,8 @@ decision_tree::gen (FILE *f, bool gimple)
tail-calls to the split-out functions. */ tail-calls to the split-out functions. */
if (gimple) if (gimple)
fprintf (f, "\nstatic bool\n" fprintf (f, "\nstatic bool\n"
"gimple_simplify (code_helper *res_code, tree *res_ops,\n" "gimple_simplify (gimple_match_op *res_op, gimple_seq *seq,\n"
" gimple_seq *seq, tree (*valueize)(tree),\n" " tree (*valueize)(tree) ATTRIBUTE_UNUSED,\n"
" code_helper code, const tree type"); " code_helper code, const tree type");
else else
fprintf (f, "\ntree\n" fprintf (f, "\ntree\n"
...@@ -3819,7 +3822,7 @@ decision_tree::gen (FILE *f, bool gimple) ...@@ -3819,7 +3822,7 @@ decision_tree::gen (FILE *f, bool gimple)
is_a <fn_id *> (e->operation) ? "-" : "", is_a <fn_id *> (e->operation) ? "-" : "",
e->operation->id); e->operation->id);
if (gimple) if (gimple)
fprintf (f, " return gimple_simplify_%s (res_code, res_ops, " fprintf (f, " return gimple_simplify_%s (res_op, "
"seq, valueize, code, type", e->operation->id); "seq, valueize, code, type", e->operation->id);
else else
fprintf (f, " return generic_simplify_%s (loc, code, type", fprintf (f, " return generic_simplify_%s (loc, code, type",
......
...@@ -4360,34 +4360,29 @@ has_use_on_stmt (tree name, gimple *stmt) ...@@ -4360,34 +4360,29 @@ has_use_on_stmt (tree name, gimple *stmt)
static bool static bool
replace_stmt_with_simplification (gimple_stmt_iterator *gsi, replace_stmt_with_simplification (gimple_stmt_iterator *gsi,
code_helper rcode, tree *ops, gimple_match_op *res_op,
gimple_seq *seq, bool inplace) gimple_seq *seq, bool inplace)
{ {
gimple *stmt = gsi_stmt (*gsi); gimple *stmt = gsi_stmt (*gsi);
tree *ops = res_op->ops;
unsigned int num_ops = res_op->num_ops;
/* Play safe and do not allow abnormals to be mentioned in /* Play safe and do not allow abnormals to be mentioned in
newly created statements. See also maybe_push_res_to_seq. newly created statements. See also maybe_push_res_to_seq.
As an exception allow such uses if there was a use of the As an exception allow such uses if there was a use of the
same SSA name on the old stmt. */ same SSA name on the old stmt. */
if ((TREE_CODE (ops[0]) == SSA_NAME for (unsigned int i = 0; i < num_ops; ++i)
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0]) if (TREE_CODE (ops[i]) == SSA_NAME
&& !has_use_on_stmt (ops[0], stmt)) && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[i])
|| (ops[1] && !has_use_on_stmt (ops[i], stmt))
&& TREE_CODE (ops[1]) == SSA_NAME return false;
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1])
&& !has_use_on_stmt (ops[1], stmt)) if (num_ops > 0 && COMPARISON_CLASS_P (ops[0]))
|| (ops[2] for (unsigned int i = 0; i < 2; ++i)
&& TREE_CODE (ops[2]) == SSA_NAME if (TREE_CODE (TREE_OPERAND (ops[0], i)) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2]) && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND (ops[0], i))
&& !has_use_on_stmt (ops[2], stmt)) && !has_use_on_stmt (TREE_OPERAND (ops[0], i), stmt))
|| (COMPARISON_CLASS_P (ops[0]) return false;
&& ((TREE_CODE (TREE_OPERAND (ops[0], 0)) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND (ops[0], 0))
&& !has_use_on_stmt (TREE_OPERAND (ops[0], 0), stmt))
|| (TREE_CODE (TREE_OPERAND (ops[0], 1)) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND (ops[0], 1))
&& !has_use_on_stmt (TREE_OPERAND (ops[0], 1), stmt)))))
return false;
/* Don't insert new statements when INPLACE is true, even if we could /* Don't insert new statements when INPLACE is true, even if we could
reuse STMT for the final statement. */ reuse STMT for the final statement. */
...@@ -4396,19 +4391,19 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi, ...@@ -4396,19 +4391,19 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi,
if (gcond *cond_stmt = dyn_cast <gcond *> (stmt)) if (gcond *cond_stmt = dyn_cast <gcond *> (stmt))
{ {
gcc_assert (rcode.is_tree_code ()); gcc_assert (res_op->code.is_tree_code ());
if (TREE_CODE_CLASS ((enum tree_code)rcode) == tcc_comparison if (TREE_CODE_CLASS ((enum tree_code) res_op->code) == tcc_comparison
/* GIMPLE_CONDs condition may not throw. */ /* GIMPLE_CONDs condition may not throw. */
&& (!flag_exceptions && (!flag_exceptions
|| !cfun->can_throw_non_call_exceptions || !cfun->can_throw_non_call_exceptions
|| !operation_could_trap_p (rcode, || !operation_could_trap_p (res_op->code,
FLOAT_TYPE_P (TREE_TYPE (ops[0])), FLOAT_TYPE_P (TREE_TYPE (ops[0])),
false, NULL_TREE))) false, NULL_TREE)))
gimple_cond_set_condition (cond_stmt, rcode, ops[0], ops[1]); gimple_cond_set_condition (cond_stmt, res_op->code, ops[0], ops[1]);
else if (rcode == SSA_NAME) else if (res_op->code == SSA_NAME)
gimple_cond_set_condition (cond_stmt, NE_EXPR, ops[0], gimple_cond_set_condition (cond_stmt, NE_EXPR, ops[0],
build_zero_cst (TREE_TYPE (ops[0]))); build_zero_cst (TREE_TYPE (ops[0])));
else if (rcode == INTEGER_CST) else if (res_op->code == INTEGER_CST)
{ {
if (integer_zerop (ops[0])) if (integer_zerop (ops[0]))
gimple_cond_make_false (cond_stmt); gimple_cond_make_false (cond_stmt);
...@@ -4417,8 +4412,7 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi, ...@@ -4417,8 +4412,7 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi,
} }
else if (!inplace) else if (!inplace)
{ {
tree res = maybe_push_res_to_seq (rcode, boolean_type_node, tree res = maybe_push_res_to_seq (res_op, seq);
ops, seq);
if (!res) if (!res)
return false; return false;
gimple_cond_set_condition (cond_stmt, NE_EXPR, res, gimple_cond_set_condition (cond_stmt, NE_EXPR, res,
...@@ -4438,14 +4432,16 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi, ...@@ -4438,14 +4432,16 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi,
return true; return true;
} }
else if (is_gimple_assign (stmt) else if (is_gimple_assign (stmt)
&& rcode.is_tree_code ()) && res_op->code.is_tree_code ())
{ {
if (!inplace if (!inplace
|| gimple_num_ops (stmt) > get_gimple_rhs_num_ops (rcode)) || gimple_num_ops (stmt) > get_gimple_rhs_num_ops (res_op->code))
{ {
maybe_build_generic_op (rcode, maybe_build_generic_op (res_op);
TREE_TYPE (gimple_assign_lhs (stmt)), ops); gimple_assign_set_rhs_with_ops (gsi, res_op->code,
gimple_assign_set_rhs_with_ops (gsi, rcode, ops[0], ops[1], ops[2]); res_op->op_or_null (0),
res_op->op_or_null (1),
res_op->op_or_null (2));
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
fprintf (dump_file, "gimple_simplified to "); fprintf (dump_file, "gimple_simplified to ");
...@@ -4458,17 +4454,12 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi, ...@@ -4458,17 +4454,12 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi,
return true; return true;
} }
} }
else if (rcode.is_fn_code () else if (res_op->code.is_fn_code ()
&& gimple_call_combined_fn (stmt) == rcode) && gimple_call_combined_fn (stmt) == res_op->code)
{ {
unsigned i; gcc_assert (num_ops == gimple_call_num_args (stmt));
for (i = 0; i < gimple_call_num_args (stmt); ++i) for (unsigned int i = 0; i < num_ops; ++i)
{ gimple_call_set_arg (stmt, i, ops[i]);
gcc_assert (ops[i] != NULL_TREE);
gimple_call_set_arg (stmt, i, ops[i]);
}
if (i < 3)
gcc_assert (ops[i] == NULL_TREE);
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
fprintf (dump_file, "gimple_simplified to "); fprintf (dump_file, "gimple_simplified to ");
...@@ -4484,8 +4475,7 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi, ...@@ -4484,8 +4475,7 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi,
if (gimple_has_lhs (stmt)) if (gimple_has_lhs (stmt))
{ {
tree lhs = gimple_get_lhs (stmt); tree lhs = gimple_get_lhs (stmt);
if (!maybe_push_res_to_seq (rcode, TREE_TYPE (lhs), if (!maybe_push_res_to_seq (res_op, seq, lhs))
ops, seq, lhs))
return false; return false;
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
...@@ -4751,12 +4741,11 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, tree (*valueize) (tree)) ...@@ -4751,12 +4741,11 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, tree (*valueize) (tree))
|| gimple_code (stmt) == GIMPLE_COND) || gimple_code (stmt) == GIMPLE_COND)
{ {
gimple_seq seq = NULL; gimple_seq seq = NULL;
code_helper rcode; gimple_match_op res_op;
tree ops[3] = {}; if (gimple_simplify (stmt, &res_op, inplace ? NULL : &seq,
if (gimple_simplify (stmt, &rcode, ops, inplace ? NULL : &seq,
valueize, valueize)) valueize, valueize))
{ {
if (replace_stmt_with_simplification (gsi, rcode, ops, &seq, inplace)) if (replace_stmt_with_simplification (gsi, &res_op, &seq, inplace))
changed = true; changed = true;
else else
gimple_seq_discard (seq); gimple_seq_discard (seq);
...@@ -6106,19 +6095,18 @@ tree ...@@ -6106,19 +6095,18 @@ tree
gimple_fold_stmt_to_constant_1 (gimple *stmt, tree (*valueize) (tree), gimple_fold_stmt_to_constant_1 (gimple *stmt, tree (*valueize) (tree),
tree (*gvalueize) (tree)) tree (*gvalueize) (tree))
{ {
code_helper rcode; gimple_match_op res_op;
tree ops[3] = {};
/* ??? The SSA propagators do not correctly deal with following SSA use-def /* ??? The SSA propagators do not correctly deal with following SSA use-def
edges if there are intermediate VARYING defs. For this reason edges if there are intermediate VARYING defs. For this reason
do not follow SSA edges here even though SCCVN can technically do not follow SSA edges here even though SCCVN can technically
just deal fine with that. */ just deal fine with that. */
if (gimple_simplify (stmt, &rcode, ops, NULL, gvalueize, valueize)) if (gimple_simplify (stmt, &res_op, NULL, gvalueize, valueize))
{ {
tree res = NULL_TREE; tree res = NULL_TREE;
if (gimple_simplified_result_is_gimple_val (rcode, ops)) if (gimple_simplified_result_is_gimple_val (&res_op))
res = ops[0]; res = res_op.ops[0];
else if (mprts_hook) else if (mprts_hook)
res = mprts_hook (rcode, gimple_expr_type (stmt), ops); res = mprts_hook (&res_op);
if (res) if (res)
{ {
if (dump_file && dump_flags & TDF_DETAILS) if (dump_file && dump_flags & TDF_DETAILS)
......
...@@ -40,31 +40,165 @@ private: ...@@ -40,31 +40,165 @@ private:
int rep; int rep;
}; };
/* Return whether OPS[0] with CODE is a non-expression result and /* Represents an operation to be simplified, or the result of the
a gimple value. */ simplification. */
struct gimple_match_op
{
gimple_match_op () : type (NULL_TREE), num_ops (0) {}
gimple_match_op (code_helper, tree, unsigned int);
gimple_match_op (code_helper, tree, tree);
gimple_match_op (code_helper, tree, tree, tree);
gimple_match_op (code_helper, tree, tree, tree, tree);
void set_op (code_helper, tree, unsigned int);
void set_op (code_helper, tree, tree);
void set_op (code_helper, tree, tree, tree);
void set_op (code_helper, tree, tree, tree, tree);
void set_value (tree);
tree op_or_null (unsigned int) const;
/* The maximum value of NUM_OPS. */
static const unsigned int MAX_NUM_OPS = 3;
/* The operation being performed. */
code_helper code;
/* The type of the result. */
tree type;
/* The number of operands to CODE. */
unsigned int num_ops;
/* The operands to CODE. Only the first NUM_OPS entries are meaningful. */
tree ops[MAX_NUM_OPS];
};
/* Constructor that takes the code, type and number of operands, but leaves
the caller to fill in the operands. */
inline
gimple_match_op::gimple_match_op (code_helper code_in, tree type_in,
unsigned int num_ops_in)
: code (code_in), type (type_in), num_ops (num_ops_in)
{
}
/* Constructors for various numbers of operands. */
inline
gimple_match_op::gimple_match_op (code_helper code_in, tree type_in,
tree op0)
: code (code_in), type (type_in), num_ops (1)
{
ops[0] = op0;
}
inline
gimple_match_op::gimple_match_op (code_helper code_in, tree type_in,
tree op0, tree op1)
: code (code_in), type (type_in), num_ops (2)
{
ops[0] = op0;
ops[1] = op1;
}
inline
gimple_match_op::gimple_match_op (code_helper code_in, tree type_in,
tree op0, tree op1, tree op2)
: code (code_in), type (type_in), num_ops (3)
{
ops[0] = op0;
ops[1] = op1;
ops[2] = op2;
}
/* Change the operation performed to CODE_IN, the type of the result to
TYPE_IN, and the number of operands to NUM_OPS_IN. The caller needs
to set the operands itself. */
inline void
gimple_match_op::set_op (code_helper code_in, tree type_in,
unsigned int num_ops_in)
{
code = code_in;
type = type_in;
num_ops = num_ops_in;
}
/* Functions for changing the operation performed, for various numbers
of operands. */
inline void
gimple_match_op::set_op (code_helper code_in, tree type_in, tree op0)
{
code = code_in;
type = type_in;
num_ops = 1;
ops[0] = op0;
}
inline void
gimple_match_op::set_op (code_helper code_in, tree type_in, tree op0, tree op1)
{
code = code_in;
type = type_in;
num_ops = 2;
ops[0] = op0;
ops[1] = op1;
}
inline void
gimple_match_op::set_op (code_helper code_in, tree type_in,
tree op0, tree op1, tree op2)
{
code = code_in;
type = type_in;
num_ops = 3;
ops[0] = op0;
ops[1] = op1;
ops[2] = op2;
}
/* Set the "operation" to be the single value VALUE, such as a constant
or SSA_NAME. */
inline void
gimple_match_op::set_value (tree value)
{
set_op (TREE_CODE (value), TREE_TYPE (value), value);
}
/* Return the value of operand I, or null if there aren't that many
operands. */
inline tree
gimple_match_op::op_or_null (unsigned int i) const
{
return i < num_ops ? ops[i] : NULL_TREE;
}
/* Return whether OP is a non-expression result and a gimple value. */
inline bool inline bool
gimple_simplified_result_is_gimple_val (code_helper code, tree *ops) gimple_simplified_result_is_gimple_val (const gimple_match_op *op)
{ {
return (code.is_tree_code () return (op->code.is_tree_code ()
&& (TREE_CODE_LENGTH ((tree_code) code) == 0 && (TREE_CODE_LENGTH ((tree_code) op->code) == 0
|| ((tree_code) code) == ADDR_EXPR) || ((tree_code) op->code) == ADDR_EXPR)
&& is_gimple_val (ops[0])); && is_gimple_val (op->ops[0]));
} }
extern tree (*mprts_hook) (code_helper, tree, tree *); extern tree (*mprts_hook) (gimple_match_op *);
bool gimple_simplify (gimple *, code_helper *, tree *, gimple_seq *, bool gimple_simplify (gimple *, gimple_match_op *, gimple_seq *,
tree (*)(tree), tree (*)(tree)); tree (*)(tree), tree (*)(tree));
bool gimple_resimplify1 (gimple_seq *, code_helper *, tree, tree *, bool gimple_resimplify1 (gimple_seq *, gimple_match_op *, tree (*)(tree));
tree (*)(tree)); bool gimple_resimplify2 (gimple_seq *, gimple_match_op *, tree (*)(tree));
bool gimple_resimplify2 (gimple_seq *, code_helper *, tree, tree *, bool gimple_resimplify3 (gimple_seq *, gimple_match_op *, tree (*)(tree));
tree (*)(tree)); tree maybe_push_res_to_seq (gimple_match_op *, gimple_seq *,
bool gimple_resimplify3 (gimple_seq *, code_helper *, tree, tree *, tree res = NULL_TREE);
tree (*)(tree)); void maybe_build_generic_op (gimple_match_op *);
tree maybe_push_res_to_seq (code_helper, tree, tree *,
gimple_seq *, tree res = NULL_TREE);
void maybe_build_generic_op (enum tree_code, tree, tree *);
#endif /* GCC_GIMPLE_MATCH_H */ #endif /* GCC_GIMPLE_MATCH_H */
...@@ -146,12 +146,11 @@ cleanup_control_expr_graph (basic_block bb, gimple_stmt_iterator gsi) ...@@ -146,12 +146,11 @@ cleanup_control_expr_graph (basic_block bb, gimple_stmt_iterator gsi)
{ {
case GIMPLE_COND: case GIMPLE_COND:
{ {
code_helper rcode; gimple_match_op res_op;
tree ops[3] = {}; if (gimple_simplify (stmt, &res_op, NULL, no_follow_ssa_edges,
if (gimple_simplify (stmt, &rcode, ops, NULL, no_follow_ssa_edges,
no_follow_ssa_edges) no_follow_ssa_edges)
&& rcode == INTEGER_CST) && res_op.code == INTEGER_CST)
val = ops[0]; val = res_op.ops[0];
} }
break; break;
......
...@@ -1655,25 +1655,25 @@ static unsigned mprts_hook_cnt; ...@@ -1655,25 +1655,25 @@ static unsigned mprts_hook_cnt;
/* Hook for maybe_push_res_to_seq, lookup the expression in the VN tables. */ /* Hook for maybe_push_res_to_seq, lookup the expression in the VN tables. */
static tree static tree
vn_lookup_simplify_result (code_helper rcode, tree type, tree *ops_) vn_lookup_simplify_result (gimple_match_op *res_op)
{ {
if (!rcode.is_tree_code ()) if (!res_op->code.is_tree_code ())
return NULL_TREE; return NULL_TREE;
tree *ops = ops_; tree *ops = res_op->ops;
unsigned int length = TREE_CODE_LENGTH ((tree_code) rcode); unsigned int length = res_op->num_ops;
if (rcode == CONSTRUCTOR if (res_op->code == CONSTRUCTOR
/* ??? We're arriving here with SCCVNs view, decomposed CONSTRUCTOR /* ??? We're arriving here with SCCVNs view, decomposed CONSTRUCTOR
and GIMPLEs / match-and-simplifies, CONSTRUCTOR as GENERIC tree. */ and GIMPLEs / match-and-simplifies, CONSTRUCTOR as GENERIC tree. */
&& TREE_CODE (ops_[0]) == CONSTRUCTOR) && TREE_CODE (res_op->ops[0]) == CONSTRUCTOR)
{ {
length = CONSTRUCTOR_NELTS (ops_[0]); length = CONSTRUCTOR_NELTS (res_op->ops[0]);
ops = XALLOCAVEC (tree, length); ops = XALLOCAVEC (tree, length);
for (unsigned i = 0; i < length; ++i) for (unsigned i = 0; i < length; ++i)
ops[i] = CONSTRUCTOR_ELT (ops_[0], i)->value; ops[i] = CONSTRUCTOR_ELT (res_op->ops[0], i)->value;
} }
vn_nary_op_t vnresult = NULL; vn_nary_op_t vnresult = NULL;
tree res = vn_nary_op_lookup_pieces (length, (tree_code) rcode, tree res = vn_nary_op_lookup_pieces (length, (tree_code) res_op->code,
type, ops, &vnresult); res_op->type, ops, &vnresult);
/* We can end up endlessly recursing simplifications if the lookup above /* We can end up endlessly recursing simplifications if the lookup above
presents us with a def-use chain that mirrors the original simplification. presents us with a def-use chain that mirrors the original simplification.
See PR80887 for an example. Limit successful lookup artificially See PR80887 for an example. Limit successful lookup artificially
...@@ -1695,8 +1695,7 @@ vn_lookup_simplify_result (code_helper rcode, tree type, tree *ops_) ...@@ -1695,8 +1695,7 @@ vn_lookup_simplify_result (code_helper rcode, tree type, tree *ops_)
INSERT is true. */ INSERT is true. */
static tree static tree
vn_nary_build_or_lookup_1 (code_helper rcode, tree type, tree *ops, vn_nary_build_or_lookup_1 (gimple_match_op *res_op, bool insert)
bool insert)
{ {
tree result = NULL_TREE; tree result = NULL_TREE;
/* We will be creating a value number for /* We will be creating a value number for
...@@ -1706,31 +1705,31 @@ vn_nary_build_or_lookup_1 (code_helper rcode, tree type, tree *ops, ...@@ -1706,31 +1705,31 @@ vn_nary_build_or_lookup_1 (code_helper rcode, tree type, tree *ops,
mprts_hook = vn_lookup_simplify_result; mprts_hook = vn_lookup_simplify_result;
mprts_hook_cnt = 9; mprts_hook_cnt = 9;
bool res = false; bool res = false;
switch (TREE_CODE_LENGTH ((tree_code) rcode)) switch (TREE_CODE_LENGTH ((tree_code) res_op->code))
{ {
case 1: case 1:
res = gimple_resimplify1 (NULL, &rcode, type, ops, vn_valueize); res = gimple_resimplify1 (NULL, res_op, vn_valueize);
break; break;
case 2: case 2:
res = gimple_resimplify2 (NULL, &rcode, type, ops, vn_valueize); res = gimple_resimplify2 (NULL, res_op, vn_valueize);
break; break;
case 3: case 3:
res = gimple_resimplify3 (NULL, &rcode, type, ops, vn_valueize); res = gimple_resimplify3 (NULL, res_op, vn_valueize);
break; break;
} }
mprts_hook = NULL; mprts_hook = NULL;
gimple *new_stmt = NULL; gimple *new_stmt = NULL;
if (res if (res
&& gimple_simplified_result_is_gimple_val (rcode, ops)) && gimple_simplified_result_is_gimple_val (res_op))
/* The expression is already available. */ /* The expression is already available. */
result = ops[0]; result = res_op->ops[0];
else else
{ {
tree val = vn_lookup_simplify_result (rcode, type, ops); tree val = vn_lookup_simplify_result (res_op);
if (!val && insert) if (!val && insert)
{ {
gimple_seq stmts = NULL; gimple_seq stmts = NULL;
result = maybe_push_res_to_seq (rcode, type, ops, &stmts); result = maybe_push_res_to_seq (res_op, &stmts);
if (result) if (result)
{ {
gcc_assert (gimple_seq_singleton_p (stmts)); gcc_assert (gimple_seq_singleton_p (stmts));
...@@ -1792,9 +1791,9 @@ vn_nary_build_or_lookup_1 (code_helper rcode, tree type, tree *ops, ...@@ -1792,9 +1791,9 @@ vn_nary_build_or_lookup_1 (code_helper rcode, tree type, tree *ops,
value-number for the simplified result or by inserting the operation. */ value-number for the simplified result or by inserting the operation. */
static tree static tree
vn_nary_build_or_lookup (code_helper rcode, tree type, tree *ops) vn_nary_build_or_lookup (gimple_match_op *res_op)
{ {
return vn_nary_build_or_lookup_1 (rcode, type, ops, true); return vn_nary_build_or_lookup_1 (res_op, true);
} }
/* Try to simplify the expression RCODE OPS... of type TYPE and return /* Try to simplify the expression RCODE OPS... of type TYPE and return
...@@ -1803,11 +1802,11 @@ vn_nary_build_or_lookup (code_helper rcode, tree type, tree *ops) ...@@ -1803,11 +1802,11 @@ vn_nary_build_or_lookup (code_helper rcode, tree type, tree *ops)
tree tree
vn_nary_simplify (vn_nary_op_t nary) vn_nary_simplify (vn_nary_op_t nary)
{ {
if (nary->length > 3) if (nary->length > gimple_match_op::MAX_NUM_OPS)
return NULL_TREE; return NULL_TREE;
tree ops[3]; gimple_match_op op (nary->opcode, nary->type, nary->length);
memcpy (ops, nary->op, sizeof (tree) * nary->length); memcpy (op.ops, nary->op, sizeof (tree) * nary->length);
return vn_nary_build_or_lookup_1 (nary->opcode, nary->type, ops, false); return vn_nary_build_or_lookup_1 (&op, false);
} }
...@@ -2032,10 +2031,9 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_, ...@@ -2032,10 +2031,9 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
else if (INTEGRAL_TYPE_P (vr->type) else if (INTEGRAL_TYPE_P (vr->type)
&& known_eq (ref->size, 8)) && known_eq (ref->size, 8))
{ {
code_helper rcode = NOP_EXPR; gimple_match_op res_op (NOP_EXPR, vr->type,
tree ops[3] = {}; gimple_call_arg (def_stmt, 1));
ops[0] = gimple_call_arg (def_stmt, 1); val = vn_nary_build_or_lookup (&res_op);
val = vn_nary_build_or_lookup (rcode, vr->type, ops);
if (!val if (!val
|| (TREE_CODE (val) == SSA_NAME || (TREE_CODE (val) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val))) && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val)))
...@@ -2174,12 +2172,11 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_, ...@@ -2174,12 +2172,11 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
|| known_eq (ref->size, TYPE_PRECISION (vr->type))) || known_eq (ref->size, TYPE_PRECISION (vr->type)))
&& multiple_p (ref->size, BITS_PER_UNIT)) && multiple_p (ref->size, BITS_PER_UNIT))
{ {
code_helper rcode = BIT_FIELD_REF; gimple_match_op op (BIT_FIELD_REF, vr->type,
tree ops[3]; SSA_VAL (gimple_assign_rhs1 (def_stmt)),
ops[0] = SSA_VAL (gimple_assign_rhs1 (def_stmt)); bitsize_int (ref->size),
ops[1] = bitsize_int (ref->size); bitsize_int (offset - offset2));
ops[2] = bitsize_int (offset - offset2); tree val = vn_nary_build_or_lookup (&op);
tree val = vn_nary_build_or_lookup (rcode, vr->type, ops);
if (val if (val
&& (TREE_CODE (val) != SSA_NAME && (TREE_CODE (val) != SSA_NAME
|| ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val))) || ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val)))
...@@ -3704,9 +3701,8 @@ visit_nary_op (tree lhs, gassign *stmt) ...@@ -3704,9 +3701,8 @@ visit_nary_op (tree lhs, gassign *stmt)
unsigned rhs_prec = TYPE_PRECISION (TREE_TYPE (rhs1)); unsigned rhs_prec = TYPE_PRECISION (TREE_TYPE (rhs1));
if (lhs_prec == rhs_prec) if (lhs_prec == rhs_prec)
{ {
ops[1] = NULL_TREE; gimple_match_op match_op (NOP_EXPR, type, ops[0]);
result = vn_nary_build_or_lookup (NOP_EXPR, result = vn_nary_build_or_lookup (&match_op);
type, ops);
if (result) if (result)
{ {
bool changed = set_ssa_val_to (lhs, result); bool changed = set_ssa_val_to (lhs, result);
...@@ -3716,12 +3712,12 @@ visit_nary_op (tree lhs, gassign *stmt) ...@@ -3716,12 +3712,12 @@ visit_nary_op (tree lhs, gassign *stmt)
} }
else else
{ {
ops[1] = wide_int_to_tree (type, tree mask = wide_int_to_tree
wi::mask (rhs_prec, false, (type, wi::mask (rhs_prec, false, lhs_prec));
lhs_prec)); gimple_match_op match_op (BIT_AND_EXPR,
result = vn_nary_build_or_lookup (BIT_AND_EXPR, TREE_TYPE (lhs),
TREE_TYPE (lhs), ops[0], mask);
ops); result = vn_nary_build_or_lookup (&match_op);
if (result) if (result)
{ {
bool changed = set_ssa_val_to (lhs, result); bool changed = set_ssa_val_to (lhs, result);
...@@ -3842,9 +3838,8 @@ visit_reference_op_load (tree lhs, tree op, gimple *stmt) ...@@ -3842,9 +3838,8 @@ visit_reference_op_load (tree lhs, tree op, gimple *stmt)
of VIEW_CONVERT_EXPR <TREE_TYPE (result)> (result). of VIEW_CONVERT_EXPR <TREE_TYPE (result)> (result).
So first simplify and lookup this expression to see if it So first simplify and lookup this expression to see if it
is already available. */ is already available. */
code_helper rcode = VIEW_CONVERT_EXPR; gimple_match_op res_op (VIEW_CONVERT_EXPR, TREE_TYPE (op), result);
tree ops[3] = { result }; result = vn_nary_build_or_lookup (&res_op);
result = vn_nary_build_or_lookup (rcode, TREE_TYPE (op), ops);
} }
if (result) if (result)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment