This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Add a class to represent a gimple match result
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>, Richard Sandiford <richard dot sandiford at linaro dot org>
- Date: Wed, 23 May 2018 13:09:49 +0200
- Subject: Re: Add a class to represent a gimple match result
- References: <8736ykm9v1.fsf@linaro.org>
On Tue, May 22, 2018 at 9:25 AM Richard Sandiford <
richard.sandiford@linaro.org> wrote:
> 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).
Looks great!
Thanks and OK.
Richard.
> 2018-05-21 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.
> Index: gcc/gimple-match.h
> ===================================================================
> --- gcc/gimple-match.h 2018-05-22 08:22:40.094593327 +0100
> +++ gcc/gimple-match.h 2018-05-22 08:22:40.324588555 +0100
> @@ -40,31 +40,165 @@ #define GCC_GIMPLE_MATCH_H
> int rep;
> };
> -/* Return whether OPS[0] with CODE is a non-expression result and
> - a gimple value. */
> +/* Represents an operation to be simplified, or the result of the
> + 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
> -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 ()
> - && (TREE_CODE_LENGTH ((tree_code) code) == 0
> - || ((tree_code) code) == ADDR_EXPR)
> - && is_gimple_val (ops[0]));
> + return (op->code.is_tree_code ()
> + && (TREE_CODE_LENGTH ((tree_code) op->code) == 0
> + || ((tree_code) op->code) == ADDR_EXPR)
> + && 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));
> -bool gimple_resimplify1 (gimple_seq *, code_helper *, tree, tree *,
> - tree (*)(tree));
> -bool gimple_resimplify2 (gimple_seq *, code_helper *, tree, tree *,
> - tree (*)(tree));
> -bool gimple_resimplify3 (gimple_seq *, code_helper *, tree, tree *,
> - tree (*)(tree));
> -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 *);
> +bool gimple_resimplify1 (gimple_seq *, gimple_match_op *, tree
(*)(tree));
> +bool gimple_resimplify2 (gimple_seq *, gimple_match_op *, tree
(*)(tree));
> +bool gimple_resimplify3 (gimple_seq *, gimple_match_op *, tree
(*)(tree));
> +tree maybe_push_res_to_seq (gimple_match_op *, gimple_seq *,
> + tree res = NULL_TREE);
> +void maybe_build_generic_op (gimple_match_op *);
> #endif /* GCC_GIMPLE_MATCH_H */
> Index: gcc/gimple-match-head.c
> ===================================================================
> --- gcc/gimple-match-head.c 2018-05-22 08:22:40.094593327 +0100
> +++ gcc/gimple-match-head.c 2018-05-22 08:22:40.324588555 +0100
> @@ -45,16 +45,14 @@ Software Foundation; either version 3, o
> /* Forward declarations of the private auto-generated matchers.
> They expect valueized operands in canonical order and do not
> perform simplification of all-constant operands. */
> -static bool gimple_simplify (code_helper *, tree *,
> - gimple_seq *, tree (*)(tree),
> +static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree
(*)(tree),
> code_helper, tree, tree);
> -static bool gimple_simplify (code_helper *, tree *,
> - gimple_seq *, tree (*)(tree),
> +static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree
(*)(tree),
> code_helper, tree, tree, tree);
> -static bool gimple_simplify (code_helper *, tree *,
> - gimple_seq *, tree (*)(tree),
> +static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree
(*)(tree),
> code_helper, tree, tree, tree, tree);
> +const unsigned int gimple_match_op::MAX_NUM_OPS;
> /* Return whether T is a constant that we'll dispatch to fold to
> evaluate fully constant expressions. */
> @@ -72,43 +70,36 @@ constant_for_folding (tree t)
> /* Helper that matches and simplifies the toplevel result from
> a gimple_simplify run (where we don't want to build
> a stmt in case it's used in in-place folding). Replaces
> - *RES_CODE and *RES_OPS with a simplified and/or canonicalized
> - result and returns whether any change was made. */
> + RES_OP with a simplified and/or canonicalized result and
> + returns whether any change was made. */
> bool
> -gimple_resimplify1 (gimple_seq *seq,
> - code_helper *res_code, tree type, tree *res_ops,
> +gimple_resimplify1 (gimple_seq *seq, gimple_match_op *res_op,
> tree (*valueize)(tree))
> {
> - if (constant_for_folding (res_ops[0]))
> + if (constant_for_folding (res_op->ops[0]))
> {
> tree tem = NULL_TREE;
> - if (res_code->is_tree_code ())
> - tem = const_unop (*res_code, type, res_ops[0]);
> + if (res_op->code.is_tree_code ())
> + tem = const_unop (res_op->code, res_op->type, res_op->ops[0]);
> else
> - tem = fold_const_call (combined_fn (*res_code), type, res_ops[0]);
> + tem = fold_const_call (combined_fn (res_op->code), res_op->type,
> + res_op->ops[0]);
> if (tem != NULL_TREE
> && CONSTANT_CLASS_P (tem))
> {
> if (TREE_OVERFLOW_P (tem))
> tem = drop_tree_overflow (tem);
> - res_ops[0] = tem;
> - res_ops[1] = NULL_TREE;
> - res_ops[2] = NULL_TREE;
> - *res_code = TREE_CODE (res_ops[0]);
> + res_op->set_value (tem);
> return true;
> }
> }
> - code_helper res_code2;
> - tree res_ops2[3] = {};
> - if (gimple_simplify (&res_code2, res_ops2, seq, valueize,
> - *res_code, type, res_ops[0]))
> - {
> - *res_code = res_code2;
> - res_ops[0] = res_ops2[0];
> - res_ops[1] = res_ops2[1];
> - res_ops[2] = res_ops2[2];
> + gimple_match_op res_op2 (*res_op);
> + if (gimple_simplify (&res_op2, seq, valueize,
> + res_op->code, res_op->type, res_op->ops[0]))
> + {
> + *res_op = res_op2;
> return true;
> }
> @@ -118,57 +109,52 @@ gimple_resimplify1 (gimple_seq *seq,
> /* Helper that matches and simplifies the toplevel result from
> a gimple_simplify run (where we don't want to build
> a stmt in case it's used in in-place folding). Replaces
> - *RES_CODE and *RES_OPS with a simplified and/or canonicalized
> - result and returns whether any change was made. */
> + RES_OP with a simplified and/or canonicalized result and
> + returns whether any change was made. */
> bool
> -gimple_resimplify2 (gimple_seq *seq,
> - code_helper *res_code, tree type, tree *res_ops,
> +gimple_resimplify2 (gimple_seq *seq, gimple_match_op *res_op,
> tree (*valueize)(tree))
> {
> - if (constant_for_folding (res_ops[0]) && constant_for_folding
(res_ops[1]))
> + if (constant_for_folding (res_op->ops[0])
> + && constant_for_folding (res_op->ops[1]))
> {
> tree tem = NULL_TREE;
> - if (res_code->is_tree_code ())
> - tem = const_binop (*res_code, type, res_ops[0], res_ops[1]);
> + if (res_op->code.is_tree_code ())
> + tem = const_binop (res_op->code, res_op->type,
> + res_op->ops[0], res_op->ops[1]);
> else
> - tem = fold_const_call (combined_fn (*res_code), type,
> - res_ops[0], res_ops[1]);
> + tem = fold_const_call (combined_fn (res_op->code), res_op->type,
> + res_op->ops[0], res_op->ops[1]);
> if (tem != NULL_TREE
> && CONSTANT_CLASS_P (tem))
> {
> if (TREE_OVERFLOW_P (tem))
> tem = drop_tree_overflow (tem);
> - res_ops[0] = tem;
> - res_ops[1] = NULL_TREE;
> - res_ops[2] = NULL_TREE;
> - *res_code = TREE_CODE (res_ops[0]);
> + res_op->set_value (tem);
> return true;
> }
> }
> /* Canonicalize operand order. */
> bool canonicalized = false;
> - if (res_code->is_tree_code ()
> - && (TREE_CODE_CLASS ((enum tree_code) *res_code) == tcc_comparison
> - || commutative_tree_code (*res_code))
> - && tree_swap_operands_p (res_ops[0], res_ops[1]))
> - {
> - std::swap (res_ops[0], res_ops[1]);
> - if (TREE_CODE_CLASS ((enum tree_code) *res_code) == tcc_comparison)
> - *res_code = swap_tree_comparison (*res_code);
> + if (res_op->code.is_tree_code ()
> + && (TREE_CODE_CLASS ((enum tree_code) res_op->code) ==
tcc_comparison
> + || commutative_tree_code (res_op->code))
> + && tree_swap_operands_p (res_op->ops[0], res_op->ops[1]))
> + {
> + std::swap (res_op->ops[0], res_op->ops[1]);
> + if (TREE_CODE_CLASS ((enum tree_code) res_op->code) ==
tcc_comparison)
> + res_op->code = swap_tree_comparison (res_op->code);
> canonicalized = true;
> }
> - code_helper res_code2;
> - tree res_ops2[3] = {};
> - if (gimple_simplify (&res_code2, res_ops2, seq, valueize,
> - *res_code, type, res_ops[0], res_ops[1]))
> - {
> - *res_code = res_code2;
> - res_ops[0] = res_ops2[0];
> - res_ops[1] = res_ops2[1];
> - res_ops[2] = res_ops2[2];
> + gimple_match_op res_op2 (*res_op);
> + if (gimple_simplify (&res_op2, seq, valueize,
> + res_op->code, res_op->type,
> + res_op->ops[0], res_op->ops[1]))
> + {
> + *res_op = res_op2;
> return true;
> }
> @@ -178,57 +164,51 @@ gimple_resimplify2 (gimple_seq *seq,
> /* Helper that matches and simplifies the toplevel result from
> a gimple_simplify run (where we don't want to build
> a stmt in case it's used in in-place folding). Replaces
> - *RES_CODE and *RES_OPS with a simplified and/or canonicalized
> - result and returns whether any change was made. */
> + RES_OP with a simplified and/or canonicalized result and
> + returns whether any change was made. */
> bool
> -gimple_resimplify3 (gimple_seq *seq,
> - code_helper *res_code, tree type, tree *res_ops,
> +gimple_resimplify3 (gimple_seq *seq, gimple_match_op *res_op,
> tree (*valueize)(tree))
> {
> - if (constant_for_folding (res_ops[0]) && constant_for_folding
(res_ops[1])
> - && constant_for_folding (res_ops[2]))
> + if (constant_for_folding (res_op->ops[0])
> + && constant_for_folding (res_op->ops[1])
> + && constant_for_folding (res_op->ops[2]))
> {
> tree tem = NULL_TREE;
> - if (res_code->is_tree_code ())
> - tem = fold_ternary/*_to_constant*/ (*res_code, type, res_ops[0],
> - res_ops[1], res_ops[2]);
> + if (res_op->code.is_tree_code ())
> + tem = fold_ternary/*_to_constant*/ (res_op->code, res_op->type,
> + res_op->ops[0],
res_op->ops[1],
> + res_op->ops[2]);
> else
> - tem = fold_const_call (combined_fn (*res_code), type,
> - res_ops[0], res_ops[1], res_ops[2]);
> + tem = fold_const_call (combined_fn (res_op->code), res_op->type,
> + res_op->ops[0], res_op->ops[1],
res_op->ops[2]);
> if (tem != NULL_TREE
> && CONSTANT_CLASS_P (tem))
> {
> if (TREE_OVERFLOW_P (tem))
> tem = drop_tree_overflow (tem);
> - res_ops[0] = tem;
> - res_ops[1] = NULL_TREE;
> - res_ops[2] = NULL_TREE;
> - *res_code = TREE_CODE (res_ops[0]);
> + res_op->set_value (tem);
> return true;
> }
> }
> /* Canonicalize operand order. */
> bool canonicalized = false;
> - if (res_code->is_tree_code ()
> - && commutative_ternary_tree_code (*res_code)
> - && tree_swap_operands_p (res_ops[0], res_ops[1]))
> + if (res_op->code.is_tree_code ()
> + && commutative_ternary_tree_code (res_op->code)
> + && tree_swap_operands_p (res_op->ops[0], res_op->ops[1]))
> {
> - std::swap (res_ops[0], res_ops[1]);
> + std::swap (res_op->ops[0], res_op->ops[1]);
> canonicalized = true;
> }
> - code_helper res_code2;
> - tree res_ops2[3] = {};
> - if (gimple_simplify (&res_code2, res_ops2, seq, valueize,
> - *res_code, type,
> - res_ops[0], res_ops[1], res_ops[2]))
> - {
> - *res_code = res_code2;
> - res_ops[0] = res_ops2[0];
> - res_ops[1] = res_ops2[1];
> - res_ops[2] = res_ops2[2];
> + gimple_match_op res_op2 (*res_op);
> + if (gimple_simplify (&res_op2, seq, valueize,
> + res_op->code, res_op->type,
> + res_op->ops[0], res_op->ops[1], res_op->ops[2]))
> + {
> + *res_op = res_op2;
> return true;
> }
> @@ -236,122 +216,117 @@ gimple_resimplify3 (gimple_seq *seq,
> }
> -/* If in GIMPLE expressions with CODE go as single-rhs build
> - a GENERIC tree for that expression into *OP0. */
> +/* If in GIMPLE the operation described by RES_OP should be single-rhs,
> + build a GENERIC tree for that expression and update RES_OP
accordingly. */
> void
> -maybe_build_generic_op (enum tree_code code, tree type, tree *ops)
> +maybe_build_generic_op (gimple_match_op *res_op)
> {
> + tree_code code = (tree_code) res_op->code;
> switch (code)
> {
> case REALPART_EXPR:
> case IMAGPART_EXPR:
> case VIEW_CONVERT_EXPR:
> - ops[0] = build1 (code, type, ops[0]);
> + res_op->set_value (build1 (code, res_op->type, res_op->ops[0]));
> break;
> case BIT_FIELD_REF:
> - ops[0] = build3 (code, type, ops[0], ops[1], ops[2]);
> - ops[1] = ops[2] = NULL_TREE;
> + res_op->set_value (build3 (code, res_op->type, res_op->ops[0],
> + res_op->ops[1], res_op->ops[2]));
> break;
> default:;
> }
> }
> -tree (*mprts_hook) (code_helper, tree, tree *);
> +tree (*mprts_hook) (gimple_match_op *);
> -/* 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. */
> +/* Try to build RES_OP, which is known to be a call to FN. 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)
> +build_call_internal (internal_fn fn, gimple_match_op *res_op)
> {
> if (direct_internal_fn_p (fn))
> {
> - tree_pair types = direct_internal_fn_types (fn, type, ops);
> + tree_pair types = direct_internal_fn_types (fn, res_op->type,
> + res_op->ops);
> if (!direct_internal_fn_supported_p (fn, types, OPTIMIZE_FOR_BOTH))
> return NULL;
> }
> - return gimple_build_call_internal (fn, nargs, ops[0], ops[1], ops[2]);
> + return gimple_build_call_internal (fn, res_op->num_ops,
> + res_op->op_or_null (0),
> + res_op->op_or_null (1),
> + res_op->op_or_null (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
> - then the result will be always RES and even gimple values are
> - pushed to SEQ. */
> +/* Push the exploded expression described by RES_OP as a statement to
> + SEQ if necessary and return a gimple value denoting the value of the
> + expression. If RES is not NULL then the result will be always RES
> + and even gimple values are pushed to SEQ. */
> tree
> -maybe_push_res_to_seq (code_helper rcode, tree type, tree *ops,
> - gimple_seq *seq, tree res)
> +maybe_push_res_to_seq (gimple_match_op *res_op, gimple_seq *seq, tree
res)
> {
> - if (rcode.is_tree_code ())
> + tree *ops = res_op->ops;
> + unsigned num_ops = res_op->num_ops;
> +
> + if (res_op->code.is_tree_code ())
> {
> if (!res
> - && gimple_simplified_result_is_gimple_val (rcode, ops))
> + && gimple_simplified_result_is_gimple_val (res_op))
> return ops[0];
> if (mprts_hook)
> {
> - tree tem = mprts_hook (rcode, type, ops);
> + tree tem = mprts_hook (res_op);
> if (tem)
> return tem;
> }
> - if (!seq)
> - return NULL_TREE;
> - /* Play safe and do not allow abnormals to be mentioned in
> - newly created statements. */
> - if ((TREE_CODE (ops[0]) == SSA_NAME
> - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0]))
> - || (ops[1]
> - && TREE_CODE (ops[1]) == SSA_NAME
> - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1]))
> - || (ops[2]
> - && TREE_CODE (ops[2]) == SSA_NAME
> - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2]))
> - || (COMPARISON_CLASS_P (ops[0])
> - && ((TREE_CODE (TREE_OPERAND (ops[0], 0)) == SSA_NAME
> - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND
(ops[0],
> - 0)))
> - || (TREE_CODE (TREE_OPERAND (ops[0], 1)) == SSA_NAME
> - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND
(ops[0],
> -
1))))))
> + }
> +
> + if (!seq)
> + return NULL_TREE;
> +
> + /* Play safe and do not allow abnormals to be mentioned in
> + newly created statements. */
> + for (unsigned int i = 0; i < num_ops; ++i)
> + if (TREE_CODE (ops[i]) == SSA_NAME
> + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[i]))
> + return NULL_TREE;
> +
> + if (num_ops > 0 && COMPARISON_CLASS_P (ops[0]))
> + for (unsigned int i = 0; i < 2; ++i)
> + if (TREE_CODE (TREE_OPERAND (ops[0], i)) == SSA_NAME
> + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND (ops[0], i)))
> return NULL_TREE;
> - if (!res)
> - {
> - if (gimple_in_ssa_p (cfun))
> - res = make_ssa_name (type);
> - else
> - res = create_tmp_reg (type);
> - }
> - maybe_build_generic_op (rcode, type, ops);
> - gimple *new_stmt = gimple_build_assign (res, rcode,
> - ops[0], ops[1], ops[2]);
> +
> + if (!res)
> + {
> + if (gimple_in_ssa_p (cfun))
> + res = make_ssa_name (res_op->type);
> + else
> + res = create_tmp_reg (res_op->type);
> + }
> +
> + if (res_op->code.is_tree_code ())
> + {
> + maybe_build_generic_op (res_op);
> + gimple *new_stmt = gimple_build_assign (res, res_op->code,
> + res_op->op_or_null (0),
> + res_op->op_or_null (1),
> + res_op->op_or_null (2));
> gimple_seq_add_stmt_without_update (seq, new_stmt);
> return res;
> }
> else
> {
> - if (!seq)
> - return NULL_TREE;
> - combined_fn fn = rcode;
> - /* Play safe and do not allow abnormals to be mentioned in
> - newly created statements. */
> - unsigned nargs;
> - for (nargs = 0; nargs < 3; ++nargs)
> - {
> - if (!ops[nargs])
> - break;
> - if (TREE_CODE (ops[nargs]) == SSA_NAME
> - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[nargs]))
> - return NULL_TREE;
> - }
> - gcc_assert (nargs != 0);
> + gcc_assert (num_ops != 0);
> + combined_fn fn = res_op->code;
> 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);
> + new_stmt = build_call_internal (ifn, res_op);
> if (!new_stmt)
> return NULL_TREE;
> }
> @@ -366,14 +341,10 @@ maybe_push_res_to_seq (code_helper rcode
> 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))
> - res = make_ssa_name (type);
> - else
> - res = create_tmp_reg (type);
> + new_stmt = gimple_build_call (decl, num_ops,
> + res_op->op_or_null (0),
> + res_op->op_or_null (1),
> + res_op->op_or_null (2));
> }
> gimple_call_set_lhs (new_stmt, res);
> gimple_seq_add_stmt_without_update (seq, new_stmt);
> @@ -406,12 +377,10 @@ gimple_simplify (enum tree_code code, tr
> return res;
> }
> - code_helper rcode;
> - tree ops[3] = {};
> - if (!gimple_simplify (&rcode, ops, seq, valueize,
> - code, type, op0))
> + gimple_match_op res_op;
> + if (!gimple_simplify (&res_op, seq, valueize, code, type, op0))
> return NULL_TREE;
> - return maybe_push_res_to_seq (rcode, type, ops, seq);
> + return maybe_push_res_to_seq (&res_op, seq);
> }
> /* Binary ops. */
> @@ -440,12 +409,10 @@ gimple_simplify (enum tree_code code, tr
> code = swap_tree_comparison (code);
> }
> - code_helper rcode;
> - tree ops[3] = {};
> - if (!gimple_simplify (&rcode, ops, seq, valueize,
> - code, type, op0, op1))
> + gimple_match_op res_op;
> + if (!gimple_simplify (&res_op, seq, valueize, code, type, op0, op1))
> return NULL_TREE;
> - return maybe_push_res_to_seq (rcode, type, ops, seq);
> + return maybe_push_res_to_seq (&res_op, seq);
> }
> /* Ternary ops. */
> @@ -470,12 +437,10 @@ gimple_simplify (enum tree_code code, tr
> && tree_swap_operands_p (op0, op1))
> std::swap (op0, op1);
> - code_helper rcode;
> - tree ops[3] = {};
> - if (!gimple_simplify (&rcode, ops, seq, valueize,
> - code, type, op0, op1, op2))
> + gimple_match_op res_op;
> + if (!gimple_simplify (&res_op, seq, valueize, code, type, op0, op1,
op2))
> return NULL_TREE;
> - return maybe_push_res_to_seq (rcode, type, ops, seq);
> + return maybe_push_res_to_seq (&res_op, seq);
> }
> /* Builtin or internal function with one argument. */
> @@ -492,11 +457,10 @@ gimple_simplify (combined_fn fn, tree ty
> return res;
> }
> - code_helper rcode;
> - tree ops[3] = {};
> - if (!gimple_simplify (&rcode, ops, seq, valueize, fn, type, arg0))
> + gimple_match_op res_op;
> + if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0))
> return NULL_TREE;
> - return maybe_push_res_to_seq (rcode, type, ops, seq);
> + return maybe_push_res_to_seq (&res_op, seq);
> }
> /* Builtin or internal function with two arguments. */
> @@ -514,11 +478,10 @@ gimple_simplify (combined_fn fn, tree ty
> return res;
> }
> - code_helper rcode;
> - tree ops[3] = {};
> - if (!gimple_simplify (&rcode, ops, seq, valueize, fn, type, arg0,
arg1))
> + gimple_match_op res_op;
> + if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0, arg1))
> return NULL_TREE;
> - return maybe_push_res_to_seq (rcode, type, ops, seq);
> + return maybe_push_res_to_seq (&res_op, seq);
> }
> /* Builtin or internal function with three arguments. */
> @@ -537,12 +500,10 @@ gimple_simplify (combined_fn fn, tree ty
> return res;
> }
> - code_helper rcode;
> - tree ops[3] = {};
> - if (!gimple_simplify (&rcode, ops, seq, valueize,
> - fn, type, arg0, arg1, arg2))
> + gimple_match_op res_op;
> + if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0, arg1,
arg2))
> return NULL_TREE;
> - return maybe_push_res_to_seq (rcode, type, ops, seq);
> + return maybe_push_res_to_seq (&res_op, seq);
> }
> /* Helper for gimple_simplify valueizing OP using VALUEIZE and setting
> @@ -567,9 +528,7 @@ do_valueize (tree op, tree (*valueize)(t
> and the fold_stmt_to_constant APIs. */
> bool
> -gimple_simplify (gimple *stmt,
> - code_helper *rcode, tree *ops,
> - gimple_seq *seq,
> +gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq,
> tree (*valueize)(tree), tree (*top_valueize)(tree))
> {
> switch (gimple_code (stmt))
> @@ -588,9 +547,8 @@ gimple_simplify (gimple *stmt,
> tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
> bool valueized = false;
> op0 = do_valueize (op0, top_valueize, valueized);
> - *rcode = code;
> - ops[0] = op0;
> - return (gimple_resimplify1 (seq, rcode, type, ops,
valueize)
> + res_op->set_op (code, type, op0);
> + return (gimple_resimplify1 (seq, res_op, valueize)
> || valueized);
> }
> else if (code == BIT_FIELD_REF)
> @@ -599,11 +557,10 @@ gimple_simplify (gimple *stmt,
> tree op0 = TREE_OPERAND (rhs1, 0);
> bool valueized = false;
> op0 = do_valueize (op0, top_valueize, valueized);
> - *rcode = code;
> - ops[0] = op0;
> - ops[1] = TREE_OPERAND (rhs1, 1);
> - ops[2] = TREE_OPERAND (rhs1, 2);
> - return (gimple_resimplify3 (seq, rcode, type, ops,
valueize)
> + res_op->set_op (code, type, op0,
> + TREE_OPERAND (rhs1, 1),
> + TREE_OPERAND (rhs1, 2));
> + return (gimple_resimplify3 (seq, res_op, valueize)
> || valueized);
> }
> else if (code == SSA_NAME
> @@ -613,8 +570,7 @@ gimple_simplify (gimple *stmt,
> tree valueized = top_valueize (op0);
> if (!valueized || op0 == valueized)
> return false;
> - ops[0] = valueized;
> - *rcode = TREE_CODE (op0);
> + res_op->set_op (TREE_CODE (op0), type, valueized);
> return true;
> }
> break;
> @@ -623,9 +579,8 @@ gimple_simplify (gimple *stmt,
> tree rhs1 = gimple_assign_rhs1 (stmt);
> bool valueized = false;
> rhs1 = do_valueize (rhs1, top_valueize, valueized);
> - *rcode = code;
> - ops[0] = rhs1;
> - return (gimple_resimplify1 (seq, rcode, type, ops, valueize)
> + res_op->set_op (code, type, rhs1);
> + return (gimple_resimplify1 (seq, res_op, valueize)
> || valueized);
> }
> case GIMPLE_BINARY_RHS:
> @@ -635,10 +590,8 @@ gimple_simplify (gimple *stmt,
> bool valueized = false;
> rhs1 = do_valueize (rhs1, top_valueize, valueized);
> rhs2 = do_valueize (rhs2, top_valueize, valueized);
> - *rcode = code;
> - ops[0] = rhs1;
> - ops[1] = rhs2;
> - return (gimple_resimplify2 (seq, rcode, type, ops, valueize)
> + res_op->set_op (code, type, rhs1, rhs2);
> + return (gimple_resimplify2 (seq, res_op, valueize)
> || valueized);
> }
> case GIMPLE_TERNARY_RHS:
> @@ -656,24 +609,21 @@ gimple_simplify (gimple *stmt,
> tree rhs = TREE_OPERAND (rhs1, 1);
> lhs = do_valueize (lhs, top_valueize, valueized);
> rhs = do_valueize (rhs, top_valueize, valueized);
> - code_helper rcode2 = TREE_CODE (rhs1);
> - tree ops2[3] = {};
> - ops2[0] = lhs;
> - ops2[1] = rhs;
> - if ((gimple_resimplify2 (seq, &rcode2, TREE_TYPE
(rhs1),
> - ops2, valueize)
> + gimple_match_op res_op2 (TREE_CODE (rhs1),
> + TREE_TYPE (rhs1), lhs,
rhs);
> + if ((gimple_resimplify2 (seq, &res_op2, valueize)
> || valueized)
> - && rcode2.is_tree_code ())
> + && res_op2.code.is_tree_code ())
> {
> valueized = true;
> - if (TREE_CODE_CLASS ((enum tree_code)rcode2)
> + if (TREE_CODE_CLASS ((enum tree_code)
res_op2.code)
> == tcc_comparison)
> - rhs1 = build2 (rcode2, TREE_TYPE (rhs1),
> - ops2[0], ops2[1]);
> - else if (rcode2 == SSA_NAME
> - || rcode2 == INTEGER_CST
> - || rcode2 == VECTOR_CST)
> - rhs1 = ops2[0];
> + rhs1 = build2 (res_op2.code, TREE_TYPE (rhs1),
> + res_op2.ops[0],
res_op2.ops[1]);
> + else if (res_op2.code == SSA_NAME
> + || res_op2.code == INTEGER_CST
> + || res_op2.code == VECTOR_CST)
> + rhs1 = res_op2.ops[0];
> else
> valueized = false;
> }
> @@ -684,11 +634,8 @@ gimple_simplify (gimple *stmt,
> rhs1 = do_valueize (rhs1, top_valueize, valueized);
> rhs2 = do_valueize (rhs2, top_valueize, valueized);
> rhs3 = do_valueize (rhs3, top_valueize, valueized);
> - *rcode = code;
> - ops[0] = rhs1;
> - ops[1] = rhs2;
> - ops[2] = rhs3;
> - return (gimple_resimplify3 (seq, rcode, type, ops, valueize)
> + res_op->set_op (code, type, rhs1, rhs2, rhs3);
> + return (gimple_resimplify3 (seq, res_op, valueize)
> || valueized);
> }
> default:
> @@ -704,8 +651,9 @@ gimple_simplify (gimple *stmt,
> && gimple_call_num_args (stmt) <= 3)
> {
> bool valueized = false;
> + combined_fn cfn;
> if (gimple_call_internal_p (stmt))
> - *rcode = as_combined_fn (gimple_call_internal_fn (stmt));
> + cfn = as_combined_fn (gimple_call_internal_fn (stmt));
> else
> {
> tree fn = gimple_call_fn (stmt);
> @@ -722,25 +670,26 @@ gimple_simplify (gimple *stmt,
> || !gimple_builtin_call_types_compatible_p (stmt, decl))
> return false;
> - *rcode = as_combined_fn (DECL_FUNCTION_CODE (decl));
> + cfn = as_combined_fn (DECL_FUNCTION_CODE (decl));
> }
> - tree type = TREE_TYPE (gimple_call_lhs (stmt));
> - for (unsigned i = 0; i < gimple_call_num_args (stmt); ++i)
> + unsigned int num_args = gimple_call_num_args (stmt);
> + res_op->set_op (cfn, TREE_TYPE (gimple_call_lhs (stmt)),
num_args);
> + for (unsigned i = 0; i < num_args; ++i)
> {
> tree arg = gimple_call_arg (stmt, i);
> - ops[i] = do_valueize (arg, top_valueize, valueized);
> + res_op->ops[i] = do_valueize (arg, top_valueize, valueized);
> }
> - switch (gimple_call_num_args (stmt))
> + switch (num_args)
> {
> case 1:
> - return (gimple_resimplify1 (seq, rcode, type, ops, valueize)
> + return (gimple_resimplify1 (seq, res_op, valueize)
> || valueized);
> case 2:
> - return (gimple_resimplify2 (seq, rcode, type, ops, valueize)
> + return (gimple_resimplify2 (seq, res_op, valueize)
> || valueized);
> case 3:
> - return (gimple_resimplify3 (seq, rcode, type, ops, valueize)
> + return (gimple_resimplify3 (seq, res_op, valueize)
> || valueized);
> default:
> gcc_unreachable ();
> @@ -755,11 +704,8 @@ gimple_simplify (gimple *stmt,
> bool valueized = false;
> lhs = do_valueize (lhs, top_valueize, valueized);
> rhs = do_valueize (rhs, top_valueize, valueized);
> - *rcode = gimple_cond_code (stmt);
> - ops[0] = lhs;
> - ops[1] = rhs;
> - return (gimple_resimplify2 (seq, rcode,
> - boolean_type_node, ops, valueize)
> + res_op->set_op (gimple_cond_code (stmt), boolean_type_node, lhs,
rhs);
> + return (gimple_resimplify2 (seq, res_op, valueize)
> || valueized);
> }
> Index: gcc/genmatch.c
> ===================================================================
> --- gcc/genmatch.c 2018-05-22 08:22:40.094593327 +0100
> +++ gcc/genmatch.c 2018-05-22 08:22:40.322588597 +0100
> @@ -2484,17 +2484,16 @@ expr::gen_transform (FILE *f, int indent
> /* ??? Building a stmt can fail for various reasons here, seq
being
> NULL or the stmt referencing SSA names occuring in abnormal
PHIs.
> 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, "tree tem_ops[3] = { ");
> + fprintf_indent (f, indent, "gimple_match_op tem_op (%s, %s",
> + opr_name, type);
> for (unsigned i = 0; i < ops.length (); ++i)
> - fprintf (f, "ops%d[%u]%s", depth, i,
> - i == ops.length () - 1 ? " };\n" : ", ");
> + fprintf (f, ", ops%d[%u]", depth, i);
> + fprintf (f, ");\n");
> fprintf_indent (f, indent,
> - "gimple_resimplify%d (lseq, &tem_code, %s, tem_ops,
valueize);\n",
> - ops.length (), type);
> + "gimple_resimplify%d (lseq, &tem_op, valueize);\n",
> + ops.length ());
> fprintf_indent (f, indent,
> - "res = maybe_push_res_to_seq (tem_code, %s,
tem_ops, lseq);\n",
> - type);
> + "res = maybe_push_res_to_seq (&tem_op, lseq);\n");
> fprintf_indent (f, indent,
> "if (!res) return false;\n");
> if (*opr == CONVERT_EXPR)
> @@ -3322,17 +3321,22 @@ dt_simplify::gen_1 (FILE *f, int indent,
> else if (is_a <predicate_id *> (opr))
> is_predicate = true;
> 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
> - ? "NOP_EXPR" : e->operation->id);
> + ? "NOP_EXPR" : e->operation->id,
> + e->ops.length ());
> for (unsigned j = 0; j < e->ops.length (); ++j)
> {
> 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
> = get_operand_type (opr, j,
> "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
> COND_EXPRs and we need to unshare them when substituting
> into COND_EXPRs. */
> @@ -3348,30 +3352,29 @@ dt_simplify::gen_1 (FILE *f, int indent,
> gimple_build w/o actually building the stmt. */
> if (!is_predicate)
> fprintf_indent (f, indent,
> - "gimple_resimplify%d (lseq, res_code, type, "
> - "res_ops, valueize);\n", e->ops.length ());
> + "gimple_resimplify%d (lseq, res_op,"
> + " valueize);\n", e->ops.length ());
> }
> else if (result->type == operand::OP_CAPTURE
> || 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);
> - 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)
> && cinfo.info[as_a <capture *>
(result)->where].cond_expr_cond_p)
> {
> /* ??? Stupid tcc_comparison GENERIC trees in COND_EXPRs.
Deal
> with substituting a capture of that. */
> fprintf_indent (f, indent,
> - "if (COMPARISON_CLASS_P (res_ops[0]))\n");
> + "if (COMPARISON_CLASS_P (tem))\n");
> fprintf_indent (f, indent,
> " {\n");
> fprintf_indent (f, indent,
> - " tree tem = res_ops[0];\n");
> - fprintf_indent (f, indent,
> - " res_ops[0] = TREE_OPERAND (tem,
0);\n");
> + " res_op->ops[0] = TREE_OPERAND (tem,
0);\n");
> 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,
> " }\n");
> }
> @@ -3529,7 +3532,7 @@ dt_simplify::gen (FILE *f, int indent, b
> {
> 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);
> for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
> if (s->for_subst_vec[i].first->used)
> @@ -3697,9 +3700,8 @@ decision_tree::gen (FILE *f, bool gimple
> fcnt++);
> if (gimple)
> fprintf (f, "\nstatic bool\n"
> - "%s (code_helper *res_code, tree *res_ops,\n"
> - " gimple_seq *seq, tree
(*valueize)(tree) "
> - "ATTRIBUTE_UNUSED,\n"
> + "%s (gimple_match_op *res_op, gimple_seq *seq,\n"
> + " tree (*valueize)(tree)
ATTRIBUTE_UNUSED,\n"
> " const tree ARG_UNUSED (type), tree
*ARG_UNUSED "
> "(captures)\n",
> s->fname);
> @@ -3753,8 +3755,9 @@ decision_tree::gen (FILE *f, bool gimple
> if (gimple)
> fprintf (f, "\nstatic bool\n"
> - "gimple_simplify_%s (code_helper *res_code, tree
*res_ops,\n"
> - " gimple_seq *seq, tree
(*valueize)(tree) "
> + "gimple_simplify_%s (gimple_match_op *res_op,"
> + " gimple_seq *seq,\n"
> + " tree (*valueize)(tree) "
> "ATTRIBUTE_UNUSED,\n"
> " code_helper ARG_UNUSED (code),
tree "
> "ARG_UNUSED (type)\n",
> @@ -3780,8 +3783,8 @@ decision_tree::gen (FILE *f, bool gimple
> tail-calls to the split-out functions. */
> if (gimple)
> fprintf (f, "\nstatic bool\n"
> - "gimple_simplify (code_helper *res_code, tree
*res_ops,\n"
> - " gimple_seq *seq, tree
(*valueize)(tree),\n"
> + "gimple_simplify (gimple_match_op *res_op, gimple_seq
*seq,\n"
> + " tree (*valueize)(tree)
ATTRIBUTE_UNUSED,\n"
> " code_helper code, const tree type");
> else
> fprintf (f, "\ntree\n"
> @@ -3819,7 +3822,7 @@ decision_tree::gen (FILE *f, bool gimple
> is_a <fn_id *> (e->operation) ? "-" : "",
> e->operation->id);
> 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);
> else
> fprintf (f, " return generic_simplify_%s (loc, code,
type",
> Index: gcc/gimple-fold.c
> ===================================================================
> --- gcc/gimple-fold.c 2018-05-22 08:22:40.094593327 +0100
> +++ gcc/gimple-fold.c 2018-05-22 08:22:40.322588597 +0100
> @@ -4360,34 +4360,29 @@ has_use_on_stmt (tree name, gimple *stmt
> static bool
> replace_stmt_with_simplification (gimple_stmt_iterator *gsi,
> - code_helper rcode, tree *ops,
> + gimple_match_op *res_op,
> gimple_seq *seq, bool inplace)
> {
> 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
> newly created statements. See also maybe_push_res_to_seq.
> As an exception allow such uses if there was a use of the
> same SSA name on the old stmt. */
> - if ((TREE_CODE (ops[0]) == SSA_NAME
> - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0])
> - && !has_use_on_stmt (ops[0], stmt))
> - || (ops[1]
> - && TREE_CODE (ops[1]) == SSA_NAME
> - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1])
> - && !has_use_on_stmt (ops[1], stmt))
> - || (ops[2]
> - && TREE_CODE (ops[2]) == SSA_NAME
> - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2])
> - && !has_use_on_stmt (ops[2], stmt))
> - || (COMPARISON_CLASS_P (ops[0])
> - && ((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;
> + for (unsigned int i = 0; i < num_ops; ++i)
> + if (TREE_CODE (ops[i]) == SSA_NAME
> + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[i])
> + && !has_use_on_stmt (ops[i], stmt))
> + return false;
> +
> + if (num_ops > 0 && COMPARISON_CLASS_P (ops[0]))
> + for (unsigned int i = 0; i < 2; ++i)
> + if (TREE_CODE (TREE_OPERAND (ops[0], i)) == SSA_NAME
> + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND (ops[0], i))
> + && !has_use_on_stmt (TREE_OPERAND (ops[0], i), stmt))
> + return false;
> /* Don't insert new statements when INPLACE is true, even if we could
> reuse STMT for the final statement. */
> @@ -4396,19 +4391,19 @@ replace_stmt_with_simplification (gimple
> if (gcond *cond_stmt = dyn_cast <gcond *> (stmt))
> {
> - gcc_assert (rcode.is_tree_code ());
> - if (TREE_CODE_CLASS ((enum tree_code)rcode) == tcc_comparison
> + gcc_assert (res_op->code.is_tree_code ());
> + if (TREE_CODE_CLASS ((enum tree_code) res_op->code) ==
tcc_comparison
> /* GIMPLE_CONDs condition may not throw. */
> && (!flag_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])),
> false, NULL_TREE)))
> - gimple_cond_set_condition (cond_stmt, rcode, ops[0], ops[1]);
> - else if (rcode == SSA_NAME)
> + gimple_cond_set_condition (cond_stmt, res_op->code, ops[0],
ops[1]);
> + else if (res_op->code == SSA_NAME)
> gimple_cond_set_condition (cond_stmt, NE_EXPR, 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]))
> gimple_cond_make_false (cond_stmt);
> @@ -4417,8 +4412,7 @@ replace_stmt_with_simplification (gimple
> }
> else if (!inplace)
> {
> - tree res = maybe_push_res_to_seq (rcode, boolean_type_node,
> - ops, seq);
> + tree res = maybe_push_res_to_seq (res_op, seq);
> if (!res)
> return false;
> gimple_cond_set_condition (cond_stmt, NE_EXPR, res,
> @@ -4438,14 +4432,16 @@ replace_stmt_with_simplification (gimple
> return true;
> }
> else if (is_gimple_assign (stmt)
> - && rcode.is_tree_code ())
> + && res_op->code.is_tree_code ())
> {
> 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,
> - TREE_TYPE (gimple_assign_lhs (stmt)),
ops);
> - gimple_assign_set_rhs_with_ops (gsi, rcode, ops[0], ops[1],
ops[2]);
> + maybe_build_generic_op (res_op);
> + gimple_assign_set_rhs_with_ops (gsi, res_op->code,
> + 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))
> {
> fprintf (dump_file, "gimple_simplified to ");
> @@ -4458,17 +4454,12 @@ replace_stmt_with_simplification (gimple
> return true;
> }
> }
> - else if (rcode.is_fn_code ()
> - && gimple_call_combined_fn (stmt) == rcode)
> + else if (res_op->code.is_fn_code ()
> + && gimple_call_combined_fn (stmt) == res_op->code)
> {
> - unsigned i;
> - for (i = 0; i < gimple_call_num_args (stmt); ++i)
> - {
> - gcc_assert (ops[i] != NULL_TREE);
> - gimple_call_set_arg (stmt, i, ops[i]);
> - }
> - if (i < 3)
> - gcc_assert (ops[i] == NULL_TREE);
> + gcc_assert (num_ops == gimple_call_num_args (stmt));
> + for (unsigned int i = 0; i < num_ops; ++i)
> + gimple_call_set_arg (stmt, i, ops[i]);
> if (dump_file && (dump_flags & TDF_DETAILS))
> {
> fprintf (dump_file, "gimple_simplified to ");
> @@ -4484,8 +4475,7 @@ replace_stmt_with_simplification (gimple
> if (gimple_has_lhs (stmt))
> {
> tree lhs = gimple_get_lhs (stmt);
> - if (!maybe_push_res_to_seq (rcode, TREE_TYPE (lhs),
> - ops, seq, lhs))
> + if (!maybe_push_res_to_seq (res_op, seq, lhs))
> return false;
> if (dump_file && (dump_flags & TDF_DETAILS))
> {
> @@ -4751,12 +4741,11 @@ fold_stmt_1 (gimple_stmt_iterator *gsi,
> || gimple_code (stmt) == GIMPLE_COND)
> {
> gimple_seq seq = NULL;
> - code_helper rcode;
> - tree ops[3] = {};
> - if (gimple_simplify (stmt, &rcode, ops, inplace ? NULL : &seq,
> + gimple_match_op res_op;
> + if (gimple_simplify (stmt, &res_op, inplace ? NULL : &seq,
> valueize, valueize))
> {
> - if (replace_stmt_with_simplification (gsi, rcode, ops, &seq,
inplace))
> + if (replace_stmt_with_simplification (gsi, &res_op, &seq,
inplace))
> changed = true;
> else
> gimple_seq_discard (seq);
> @@ -6106,19 +6095,18 @@ maybe_fold_or_comparisons (enum tree_cod
> gimple_fold_stmt_to_constant_1 (gimple *stmt, tree (*valueize) (tree),
> tree (*gvalueize) (tree))
> {
> - code_helper rcode;
> - tree ops[3] = {};
> + gimple_match_op res_op;
> /* ??? The SSA propagators do not correctly deal with following SSA
use-def
> edges if there are intermediate VARYING defs. For this reason
> do not follow SSA edges here even though SCCVN can technically
> 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;
> - if (gimple_simplified_result_is_gimple_val (rcode, ops))
> - res = ops[0];
> + if (gimple_simplified_result_is_gimple_val (&res_op))
> + res = res_op.ops[0];
> else if (mprts_hook)
> - res = mprts_hook (rcode, gimple_expr_type (stmt), ops);
> + res = mprts_hook (&res_op);
> if (res)
> {
> if (dump_file && dump_flags & TDF_DETAILS)
> Index: gcc/tree-cfgcleanup.c
> ===================================================================
> --- gcc/tree-cfgcleanup.c 2018-05-22 08:22:40.094593327 +0100
> +++ gcc/tree-cfgcleanup.c 2018-05-22 08:22:40.324588555 +0100
> @@ -146,12 +146,11 @@ cleanup_control_expr_graph (basic_block
> {
> case GIMPLE_COND:
> {
> - code_helper rcode;
> - tree ops[3] = {};
> - if (gimple_simplify (stmt, &rcode, ops, NULL,
no_follow_ssa_edges,
> + gimple_match_op res_op;
> + if (gimple_simplify (stmt, &res_op, NULL, no_follow_ssa_edges,
> no_follow_ssa_edges)
> - && rcode == INTEGER_CST)
> - val = ops[0];
> + && res_op.code == INTEGER_CST)
> + val = res_op.ops[0];
> }
> break;
> Index: gcc/tree-ssa-sccvn.c
> ===================================================================
> --- gcc/tree-ssa-sccvn.c 2018-05-22 08:22:40.094593327 +0100
> +++ gcc/tree-ssa-sccvn.c 2018-05-22 08:22:40.324588555 +0100
> @@ -1655,25 +1655,25 @@ static vn_nary_op_t vn_nary_op_insert_st
> /* Hook for maybe_push_res_to_seq, lookup the expression in the VN
tables. */
> 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;
> - tree *ops = ops_;
> - unsigned int length = TREE_CODE_LENGTH ((tree_code) rcode);
> - if (rcode == CONSTRUCTOR
> + tree *ops = res_op->ops;
> + unsigned int length = res_op->num_ops;
> + if (res_op->code == CONSTRUCTOR
> /* ??? We're arriving here with SCCVNs view, decomposed
CONSTRUCTOR
> 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);
> 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;
> - tree res = vn_nary_op_lookup_pieces (length, (tree_code) rcode,
> - type, ops, &vnresult);
> + tree res = vn_nary_op_lookup_pieces (length, (tree_code) res_op->code,
> + res_op->type, ops, &vnresult);
> /* We can end up endlessly recursing simplifications if the lookup
above
> presents us with a def-use chain that mirrors the original
simplification.
> See PR80887 for an example. Limit successful lookup artificially
> @@ -1695,8 +1695,7 @@ vn_lookup_simplify_result (code_helper r
> INSERT is true. */
> static tree
> -vn_nary_build_or_lookup_1 (code_helper rcode, tree type, tree *ops,
> - bool insert)
> +vn_nary_build_or_lookup_1 (gimple_match_op *res_op, bool insert)
> {
> tree result = NULL_TREE;
> /* We will be creating a value number for
> @@ -1706,31 +1705,31 @@ vn_nary_build_or_lookup_1 (code_helper r
> mprts_hook = vn_lookup_simplify_result;
> mprts_hook_cnt = 9;
> bool res = false;
> - switch (TREE_CODE_LENGTH ((tree_code) rcode))
> + switch (TREE_CODE_LENGTH ((tree_code) res_op->code))
> {
> case 1:
> - res = gimple_resimplify1 (NULL, &rcode, type, ops, vn_valueize);
> + res = gimple_resimplify1 (NULL, res_op, vn_valueize);
> break;
> case 2:
> - res = gimple_resimplify2 (NULL, &rcode, type, ops, vn_valueize);
> + res = gimple_resimplify2 (NULL, res_op, vn_valueize);