On Tue, May 22, 2018 at 9:25 AM Richard Sandiford < richard.sandif...@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.sandif...@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);