Add a class to represent a gimple match result

Message ID 8736ykm9v1.fsf@linaro.org
State New
Headers show
Series
  • Add a class to represent a gimple match result
Related show

Commit Message

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

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

2018-05-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.

Comments

Richard Biener May 23, 2018, 11:09 a.m. | #1
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);

Patch

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);
       break;
     case 3:
-      res = gimple_resimplify3 (NULL, &rcode, type, ops, vn_valueize);
+      res = gimple_resimplify3 (NULL, res_op, vn_valueize);
       break;
     }
   mprts_hook = NULL;
   gimple *new_stmt = NULL;
   if (res
-      && gimple_simplified_result_is_gimple_val (rcode, ops))
+      && gimple_simplified_result_is_gimple_val (res_op))
     /* The expression is already available.  */
-    result = ops[0];
+    result = res_op->ops[0];
   else
     {
-      tree val = vn_lookup_simplify_result (rcode, type, ops);
+      tree val = vn_lookup_simplify_result (res_op);
       if (!val && insert)
 	{
 	  gimple_seq stmts = NULL;
-	  result = maybe_push_res_to_seq (rcode, type, ops, &stmts);
+	  result = maybe_push_res_to_seq (res_op, &stmts);
 	  if (result)
 	    {
 	      gcc_assert (gimple_seq_singleton_p (stmts));
@@ -1792,9 +1791,9 @@  vn_nary_build_or_lookup_1 (code_helper r
    value-number for the simplified result or by inserting the operation.  */
 
 static tree
-vn_nary_build_or_lookup (code_helper rcode, tree type, tree *ops)
+vn_nary_build_or_lookup (gimple_match_op *res_op)
 {
-  return vn_nary_build_or_lookup_1 (rcode, type, ops, true);
+  return vn_nary_build_or_lookup_1 (res_op, true);
 }
 
 /* Try to simplify the expression RCODE OPS... of type TYPE and return
@@ -1803,11 +1802,11 @@  vn_nary_build_or_lookup (code_helper rco
 tree
 vn_nary_simplify (vn_nary_op_t nary)
 {
-  if (nary->length > 3)
+  if (nary->length > gimple_match_op::MAX_NUM_OPS)
     return NULL_TREE;
-  tree ops[3];
-  memcpy (ops, nary->op, sizeof (tree) * nary->length);
-  return vn_nary_build_or_lookup_1 (nary->opcode, nary->type, ops, false);
+  gimple_match_op op (nary->opcode, nary->type, nary->length);
+  memcpy (op.ops, nary->op, sizeof (tree) * nary->length);
+  return vn_nary_build_or_lookup_1 (&op, false);
 }
 
 
@@ -2150,12 +2149,11 @@  vn_reference_lookup_3 (ao_ref *ref, tree
 	      || known_eq (ref->size, TYPE_PRECISION (vr->type)))
 	  && multiple_p (ref->size, BITS_PER_UNIT))
 	{
-	  code_helper rcode = BIT_FIELD_REF;
-	  tree ops[3];
-	  ops[0] = SSA_VAL (gimple_assign_rhs1 (def_stmt));
-	  ops[1] = bitsize_int (ref->size);
-	  ops[2] = bitsize_int (offset - offset2);
-	  tree val = vn_nary_build_or_lookup (rcode, vr->type, ops);
+	  gimple_match_op op (BIT_FIELD_REF, vr->type,
+			      SSA_VAL (gimple_assign_rhs1 (def_stmt)),
+			      bitsize_int (ref->size),
+			      bitsize_int (offset - offset2));
+	  tree val = vn_nary_build_or_lookup (&op);
 	  if (val
 	      && (TREE_CODE (val) != SSA_NAME
 		  || ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val)))
@@ -3680,9 +3678,8 @@  visit_nary_op (tree lhs, gassign *stmt)
 		      unsigned rhs_prec = TYPE_PRECISION (TREE_TYPE (rhs1));
 		      if (lhs_prec == rhs_prec)
 			{
-			  ops[1] = NULL_TREE;
-			  result = vn_nary_build_or_lookup (NOP_EXPR,
-							    type, ops);
+			  gimple_match_op match_op (NOP_EXPR, type, ops[0]);
+			  result = vn_nary_build_or_lookup (&match_op);
 			  if (result)
 			    {
 			      bool changed = set_ssa_val_to (lhs, result);
@@ -3692,12 +3689,12 @@  visit_nary_op (tree lhs, gassign *stmt)
 			}
 		      else
 			{
-			  ops[1] = wide_int_to_tree (type,
-						     wi::mask (rhs_prec, false,
-							       lhs_prec));
-			  result = vn_nary_build_or_lookup (BIT_AND_EXPR,
-							    TREE_TYPE (lhs),
-							    ops);
+			  tree mask = wide_int_to_tree
+			    (type, wi::mask (rhs_prec, false, lhs_prec));
+			  gimple_match_op match_op (BIT_AND_EXPR,
+						    TREE_TYPE (lhs),
+						    ops[0], mask);
+			  result = vn_nary_build_or_lookup (&match_op);
 			  if (result)
 			    {
 			      bool changed = set_ssa_val_to (lhs, result);
@@ -3818,9 +3815,8 @@  visit_reference_op_load (tree lhs, tree
 	 of VIEW_CONVERT_EXPR <TREE_TYPE (result)> (result).
 	 So first simplify and lookup this expression to see if it
 	 is already available.  */
-      code_helper rcode = VIEW_CONVERT_EXPR;
-      tree ops[3] = { result };
-      result = vn_nary_build_or_lookup (rcode, TREE_TYPE (op), ops);
+      gimple_match_op res_op (VIEW_CONVERT_EXPR, TREE_TYPE (op), result);
+      result = vn_nary_build_or_lookup (&res_op);
     }
 
   if (result)