This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Add a class to represent a gimple match result


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);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]