]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/genmatch.c
c++: Handle multiple aggregate overloads [PR95319].
[thirdparty/gcc.git] / gcc / genmatch.c
index f5aa29b72f5e205959eb12617ccd923bc65c76d7..0a8cba62e0cc1d5e928df39ba961c1a33bf9185e 100644 (file)
@@ -1,7 +1,7 @@
 /* Generate pattern matching and transform code shared between
    GENERIC and GIMPLE folding code from match-and-simplify description.
 
-   Copyright (C) 2014-2016 Free Software Foundation, Inc.
+   Copyright (C) 2014-2020 Free Software Foundation, Inc.
    Contributed by Richard Biener <rguenther@suse.de>
    and Prathamesh Kulkarni  <bilbotheelffriend@gmail.com>
 
@@ -50,10 +50,10 @@ unsigned verbose;
 
 /* libccp helpers.  */
 
-static struct line_maps *line_table;
+static class line_maps *line_table;
 
 /* The rich_location class within libcpp requires a way to expand
-   source_location instances, and relies on the client code
+   location_t instances, and relies on the client code
    providing a symbol named
      linemap_client_expand_location_to_spelling_point
    to do this.
@@ -61,7 +61,8 @@ static struct line_maps *line_table;
    This is the implementation for genmatch.  */
 
 expanded_location
-linemap_client_expand_location_to_spelling_point (source_location loc)
+linemap_client_expand_location_to_spelling_point (location_t loc,
+                                                 enum location_aspect)
 {
   const struct line_map_ordinary *map;
   loc = linemap_resolve_location (line_table, loc, LRK_SPELLING_LOCATION, &map);
@@ -72,11 +73,12 @@ static bool
 #if GCC_VERSION >= 4001
 __attribute__((format (printf, 5, 0)))
 #endif
-error_cb (cpp_reader *, int errtype, int, rich_location *richloc,
-         const char *msg, va_list *ap)
+diagnostic_cb (cpp_reader *, enum cpp_diagnostic_level errtype,
+              enum cpp_warning_reason, rich_location *richloc,
+              const char *msg, va_list *ap)
 {
   const line_map_ordinary *map;
-  source_location location = richloc->get_loc ();
+  location_t location = richloc->get_loc ();
   linemap_resolve_location (line_table, location, LRK_SPELLING_LOCATION, &map);
   expanded_location loc = linemap_expand_location (line_table, map, location);
   fprintf (stderr, "%s:%d:%d %s: ", loc.file, loc.line, loc.column,
@@ -121,7 +123,7 @@ fatal_at (const cpp_token *tk, const char *msg, ...)
   rich_location richloc (line_table, tk->src_loc);
   va_list ap;
   va_start (ap, msg);
-  error_cb (NULL, CPP_DL_FATAL, 0, &richloc, msg, &ap);
+  diagnostic_cb (NULL, CPP_DL_FATAL, CPP_W_NONE, &richloc, msg, &ap);
   va_end (ap);
 }
 
@@ -129,12 +131,12 @@ static void
 #if GCC_VERSION >= 4001
 __attribute__((format (printf, 2, 3)))
 #endif
-fatal_at (source_location loc, const char *msg, ...)
+fatal_at (location_t loc, const char *msg, ...)
 {
   rich_location richloc (line_table, loc);
   va_list ap;
   va_start (ap, msg);
-  error_cb (NULL, CPP_DL_FATAL, 0, &richloc, msg, &ap);
+  diagnostic_cb (NULL, CPP_DL_FATAL, CPP_W_NONE, &richloc, msg, &ap);
   va_end (ap);
 }
 
@@ -147,7 +149,7 @@ warning_at (const cpp_token *tk, const char *msg, ...)
   rich_location richloc (line_table, tk->src_loc);
   va_list ap;
   va_start (ap, msg);
-  error_cb (NULL, CPP_DL_WARNING, 0, &richloc, msg, &ap);
+  diagnostic_cb (NULL, CPP_DL_WARNING, CPP_W_NONE, &richloc, msg, &ap);
   va_end (ap);
 }
 
@@ -155,12 +157,12 @@ static void
 #if GCC_VERSION >= 4001
 __attribute__((format (printf, 2, 3)))
 #endif
-warning_at (source_location loc, const char *msg, ...)
+warning_at (location_t loc, const char *msg, ...)
 {
   rich_location richloc (line_table, loc);
   va_list ap;
   va_start (ap, msg);
-  error_cb (NULL, CPP_DL_WARNING, 0, &richloc, msg, &ap);
+  diagnostic_cb (NULL, CPP_DL_WARNING, CPP_W_NONE, &richloc, msg, &ap);
   va_end (ap);
 }
 
@@ -182,8 +184,8 @@ fprintf_indent (FILE *f, unsigned int indent, const char *format, ...)
 }
 
 static void
-output_line_directive (FILE *f, source_location location,
-                      bool dumpfile = false)
+output_line_directive (FILE *f, location_t location,
+                      bool dumpfile = false, bool fnargs = false)
 {
   const line_map_ordinary *map;
   linemap_resolve_location (line_table, location, LRK_SPELLING_LOCATION, &map);
@@ -192,11 +194,20 @@ output_line_directive (FILE *f, source_location location,
     {
       /* When writing to a dumpfile only dump the filename.  */
       const char *file = strrchr (loc.file, DIR_SEPARATOR);
+#if defined(DIR_SEPARATOR_2)
+      const char *pos2 = strrchr (loc.file, DIR_SEPARATOR_2);
+      if (pos2 && (!file || (pos2 > file)))
+       file = pos2;
+#endif
       if (!file)
        file = loc.file;
       else
        ++file;
-      fprintf (f, "%s:%d", file, loc.line);
+
+      if (fnargs)
+       fprintf (f, "\"%s\", %d", file, loc.line);
+      else
+       fprintf (f, "%s:%d", file, loc.line);
     }
   else
     /* Other gen programs really output line directives here, at least for
@@ -213,12 +224,6 @@ output_line_directive (FILE *f, source_location location,
 #define DEFTREECODE(SYM, STRING, TYPE, NARGS)   SYM,
 enum tree_code {
 #include "tree.def"
-CONVERT0,
-CONVERT1,
-CONVERT2,
-VIEW_CONVERT0,
-VIEW_CONVERT1,
-VIEW_CONVERT2,
 MAX_TREE_CODES
 };
 #undef DEFTREECODE
@@ -235,6 +240,20 @@ enum internal_fn {
   IFN_LAST
 };
 
+enum combined_fn {
+#define DEF_BUILTIN(ENUM, N, C, T, LT, B, F, NA, AT, IM, COND) \
+  CFN_##ENUM = int (ENUM),
+#include "builtins.def"
+
+#define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
+  CFN_##CODE = int (END_BUILTINS) + int (IFN_##CODE),
+#include "internal-fn.def"
+
+  CFN_LAST
+};
+
+#include "case-cfn-macros.h"
+
 /* Return true if CODE represents a commutative tree code.  Otherwise
    return false.  */
 bool
@@ -282,7 +301,6 @@ commutative_ternary_tree_code (enum tree_code code)
     case WIDEN_MULT_PLUS_EXPR:
     case WIDEN_MULT_MINUS_EXPR:
     case DOT_PROD_EXPR:
-    case FMA_EXPR:
       return true;
 
     default:
@@ -323,8 +341,9 @@ comparison_code_p (enum tree_code code)
 
 /* Base class for all identifiers the parser knows.  */
 
-struct id_base : nofree_ptr_hash<id_base>
+class id_base : public nofree_ptr_hash<id_base>
 {
+public:
   enum id_kind { CODE, FN, PREDICATE, USER, NULL_ID } kind;
 
   id_base (id_kind, const char *, int = -1);
@@ -369,8 +388,9 @@ id_base::id_base (id_kind kind_, const char *id_, int nargs_)
 
 /* Identifier that maps to a tree code.  */
 
-struct operator_id : public id_base
+class operator_id : public id_base
 {
+public:
   operator_id (enum tree_code code_, const char *id_, unsigned nargs_,
               const char *tcc_)
       : id_base (id_base::CODE, id_, nargs_), code (code_), tcc (tcc_) {}
@@ -380,8 +400,9 @@ struct operator_id : public id_base
 
 /* Identifier that maps to a builtin or internal function code.  */
 
-struct fn_id : public id_base
+class fn_id : public id_base
 {
+public:
   fn_id (enum built_in_function fn_, const char *id_)
       : id_base (id_base::FN, id_), fn (fn_) {}
   fn_id (enum internal_fn fn_, const char *id_)
@@ -389,12 +410,13 @@ struct fn_id : public id_base
   unsigned int fn;
 };
 
-struct simplify;
+class simplify;
 
 /* Identifier that maps to a user-defined predicate.  */
 
-struct predicate_id : public id_base
+class predicate_id : public id_base
 {
+public:
   predicate_id (const char *id_)
     : id_base (id_base::PREDICATE, id_), matchers (vNULL) {}
   vec<simplify *> matchers;
@@ -402,8 +424,9 @@ struct predicate_id : public id_base
 
 /* Identifier that maps to a operator defined by a 'for' directive.  */
 
-struct user_id : public id_base
+class user_id : public id_base
 {
+public:
   user_id (const char *id_, bool is_oper_list_ = false)
     : id_base (id_base::USER, id_), substitutes (vNULL),
       used (false), is_oper_list (is_oper_list_) {}
@@ -444,6 +467,44 @@ is_a_helper <user_id *>::test (id_base *id)
   return id->kind == id_base::USER;
 }
 
+/* If ID has a pair of consecutive, commutative operands, return the
+   index of the first, otherwise return -1.  */
+
+static int
+commutative_op (id_base *id)
+{
+  if (operator_id *code = dyn_cast <operator_id *> (id))
+    {
+      if (commutative_tree_code (code->code)
+         || commutative_ternary_tree_code (code->code))
+       return 0;
+      return -1;
+    }
+  if (fn_id *fn = dyn_cast <fn_id *> (id))
+    switch (fn->fn)
+      {
+      CASE_CFN_FMA:
+      case CFN_FMS:
+      case CFN_FNMA:
+      case CFN_FNMS:
+       return 0;
+
+      default:
+       return -1;
+      }
+  if (user_id *uid = dyn_cast<user_id *> (id))
+    {
+      int res = commutative_op (uid->substitutes[0]);
+      if (res < 0)
+       return 0;
+      for (unsigned i = 1; i < uid->substitutes.length (); ++i)
+       if (res != commutative_op (uid->substitutes[i]))
+         return -1;
+      return res;
+    }
+  return -1;
+}
+
 /* Add a predicate identifier to the hash.  */
 
 static predicate_id *
@@ -598,17 +659,18 @@ typedef hash_map<nofree_string_hash, unsigned> cid_map_t;
 
 /* The AST produced by parsing of the pattern definitions.  */
 
-struct dt_operand;
-struct capture_info;
+class dt_operand;
+class capture_info;
 
 /* The base class for operands.  */
 
-struct operand {
+class operand {
+public:
   enum op_type { OP_PREDICATE, OP_EXPR, OP_CAPTURE, OP_C_EXPR, OP_IF, OP_WITH };
-  operand (enum op_type type_, source_location loc_)
+  operand (enum op_type type_, location_t loc_)
     : type (type_), location (loc_) {}
   enum op_type type;
-  source_location location;
+  location_t location;
   virtual void gen_transform (FILE *, int, const char *, bool, int,
                              const char *, capture_info *,
                              dt_operand ** = 0,
@@ -618,9 +680,10 @@ struct operand {
 
 /* A predicate operand.  Predicates are leafs in the AST.  */
 
-struct predicate : public operand
+class predicate : public operand
 {
-  predicate (predicate_id *p_, source_location loc)
+public:
+  predicate (predicate_id *p_, location_t loc)
     : operand (OP_PREDICATE, loc), p (p_) {}
   predicate_id *p;
 };
@@ -628,16 +691,18 @@ struct predicate : public operand
 /* An operand that constitutes an expression.  Expressions include
    function calls and user-defined predicate invocations.  */
 
-struct expr : public operand
+class expr : public operand
 {
-  expr (id_base *operation_, source_location loc, bool is_commutative_ = false)
+public:
+  expr (id_base *operation_, location_t loc, bool is_commutative_ = false)
     : operand (OP_EXPR, loc), operation (operation_),
       ops (vNULL), expr_type (NULL), is_commutative (is_commutative_),
-      is_generic (false), force_single_use (false) {}
+      is_generic (false), force_single_use (false), opt_grp (0) {}
   expr (expr *e)
     : operand (OP_EXPR, e->location), operation (e->operation),
       ops (vNULL), expr_type (e->expr_type), is_commutative (e->is_commutative),
-      is_generic (e->is_generic), force_single_use (e->force_single_use) {}
+      is_generic (e->is_generic), force_single_use (e->force_single_use),
+      opt_grp (e->opt_grp) {}
   void append_op (operand *op) { ops.safe_push (op); }
   /* The operator and its operands.  */
   id_base *operation;
@@ -652,6 +717,8 @@ struct expr : public operand
   /* Whether pushing any stmt to the sequence should be conditional
      on this expression having a single-use.  */
   bool force_single_use;
+  /* If non-zero, the group for optional handling.  */
+  unsigned char opt_grp;
   virtual void gen_transform (FILE *f, int, const char *, bool, int,
                              const char *, capture_info *,
                              dt_operand ** = 0, int = 0);
@@ -661,17 +728,19 @@ struct expr : public operand
    a leaf operand in the AST.  This class is also used to represent
    the code to be generated for 'if' and 'with' expressions.  */
 
-struct c_expr : public operand
+class c_expr : public operand
 {
+public:
   /* A mapping of an identifier and its replacement.  Used to apply
      'for' lowering.  */
-  struct id_tab {
+  class id_tab {
+  public:
     const char *id;
     const char *oper;
     id_tab (const char *id_, const char *oper_): id (id_), oper (oper_) {}
   };
 
-  c_expr (cpp_reader *r_, source_location loc,
+  c_expr (cpp_reader *r_, location_t loc,
          vec<cpp_token> code_, unsigned nr_stmts_,
          vec<id_tab> ids_, cid_map_t *capture_ids_)
     : operand (OP_C_EXPR, loc), r (r_), code (code_),
@@ -691,12 +760,18 @@ struct c_expr : public operand
 
 /* A wrapper around another operand that captures its value.  */
 
-struct capture : public operand
+class capture : public operand
 {
-  capture (source_location loc, unsigned where_, operand *what_)
-      : operand (OP_CAPTURE, loc), where (where_), what (what_) {}
+public:
+  capture (location_t loc, unsigned where_, operand *what_, bool value_)
+      : operand (OP_CAPTURE, loc), where (where_), value_match (value_),
+        what (what_) {}
   /* Identifier index for the value.  */
   unsigned where;
+  /* Whether in a match of two operands the compare should be for
+     equal values rather than equal atoms (boils down to a type
+     check or not).  */
+  bool value_match;
   /* The captured value.  */
   operand *what;
   virtual void gen_transform (FILE *f, int, const char *, bool, int,
@@ -706,9 +781,10 @@ struct capture : public operand
 
 /* if expression.  */
 
-struct if_expr : public operand
+class if_expr : public operand
 {
-  if_expr (source_location loc)
+public:
+  if_expr (location_t loc)
     : operand (OP_IF, loc), cond (NULL), trueexpr (NULL), falseexpr (NULL) {}
   c_expr *cond;
   operand *trueexpr;
@@ -717,9 +793,10 @@ struct if_expr : public operand
 
 /* with expression.  */
 
-struct with_expr : public operand
+class with_expr : public operand
 {
-  with_expr (source_location loc)
+public:
+  with_expr (location_t loc)
     : operand (OP_WITH, loc), with (NULL), subexpr (NULL) {}
   c_expr *with;
   operand *subexpr;
@@ -778,24 +855,29 @@ is_a_helper <with_expr *>::test (operand *op)
    duplicates all outer 'if' and 'for' expressions here so each
    simplify can exist in isolation.  */
 
-struct simplify
+class simplify
 {
+public:
   enum simplify_kind { SIMPLIFY, MATCH };
 
-  simplify (simplify_kind kind_, operand *match_, operand *result_,
-           vec<vec<user_id *> > for_vec_, cid_map_t *capture_ids_)
-      : kind (kind_), match (match_), result (result_),
+  simplify (simplify_kind kind_, unsigned id_, operand *match_,
+           operand *result_, vec<vec<user_id *> > for_vec_,
+           cid_map_t *capture_ids_)
+      : kind (kind_), id (id_), match (match_), result (result_),
       for_vec (for_vec_), for_subst_vec (vNULL),
       capture_ids (capture_ids_), capture_max (capture_ids_->elements () - 1) {}
 
   simplify_kind kind;
+  /* ID.  This is kept to easily associate related simplifies expanded
+     from the same original one.  */
+  unsigned id;
   /* The expression that is matched against the GENERIC or GIMPLE IL.  */
   operand *match;
   /* For a (simplify ...) an expression with ifs and withs with the expression
      produced when the pattern applies in the leafs.
      For a (match ...) the leafs are either empty if it is a simple predicate
      or the single expression specifying the matched operands.  */
-  struct operand *result;
+  class operand *result;
   /* Collected 'for' expression operators that have to be replaced
      in the lowering phase.  */
   vec<vec<user_id *> > for_vec;
@@ -848,7 +930,7 @@ print_operand (operand *o, FILE *f = stderr, bool flattened = false)
 }
 
 DEBUG_FUNCTION void
-print_matches (struct simplify *s, FILE *f = stderr)
+print_matches (class simplify *s, FILE *f = stderr)
 {
   fprintf (f, "for expression: ");
   print_operand (s->match, f);
@@ -895,7 +977,8 @@ commutate (operand *op, vec<vec<user_id *> > &for_vec)
       vec<operand *> v = commutate (c->what, for_vec);
       for (unsigned i = 0; i < v.length (); ++i)
        {
-         capture *nc = new capture (c->location, c->where, v[i]);
+         capture *nc = new capture (c->location, c->where, v[i],
+                                    c->value_match);
          ret.safe_push (nc);
        }
       return ret;
@@ -930,13 +1013,16 @@ commutate (operand *op, vec<vec<user_id *> > &for_vec)
   if (!e->is_commutative)
     return ret;
 
+  /* The operation is always binary if it isn't inherently commutative.  */
+  int natural_opno = commutative_op (e->operation);
+  unsigned int opno = natural_opno >= 0 ? natural_opno : 0;
   for (unsigned i = 0; i < result.length (); ++i)
     {
       expr *ne = new expr (e);
-      if (operator_id *p = dyn_cast <operator_id *> (ne->operation))
+      if (operator_id *r = dyn_cast <operator_id *> (ne->operation))
        {
-         if (comparison_code_p (p->code))
-           ne->operation = swap_tree_comparison (p);
+         if (comparison_code_p (r->code))
+           ne->operation = swap_tree_comparison (r);
        }
       else if (user_id *p = dyn_cast <user_id *> (ne->operation))
        {
@@ -978,9 +1064,11 @@ commutate (operand *op, vec<vec<user_id *> > &for_vec)
            }
        }
       ne->is_commutative = false;
-      // result[i].length () is 2 since e->operation is binary
-      for (unsigned j = result[i].length (); j; --j)
-       ne->append_op (result[i][j-1]);
+      for (unsigned j = 0; j < result[i].length (); ++j)
+       {
+         int old_j = (j == opno ? opno + 1 : j == opno + 1 ? opno : j);
+         ne->append_op (result[i][old_j]);
+       }
       ret.safe_push (ne);
     }
 
@@ -996,24 +1084,24 @@ lower_commutative (simplify *s, vec<simplify *>& simplifiers)
   vec<operand *> matchers = commutate (s->match, s->for_vec);
   for (unsigned i = 0; i < matchers.length (); ++i)
     {
-      simplify *ns = new simplify (s->kind, matchers[i], s->result,
+      simplify *ns = new simplify (s->kind, s->id, matchers[i], s->result,
                                   s->for_vec, s->capture_ids);
       simplifiers.safe_push (ns);
     }
 }
 
-/* Strip conditional conversios using operator OPER from O and its
-   children if STRIP, else replace them with an unconditional convert.  */
+/* Strip conditional operations using group GRP from O and its
+   children if STRIP, else replace them with an unconditional operation.  */
 
 operand *
-lower_opt_convert (operand *o, enum tree_code oper,
-                  enum tree_code to_oper, bool strip)
+lower_opt (operand *o, unsigned char grp, bool strip)
 {
   if (capture *c = dyn_cast<capture *> (o))
     {
       if (c->what)
        return new capture (c->location, c->where,
-                           lower_opt_convert (c->what, oper, to_oper, strip));
+                           lower_opt (c->what, grp, strip),
+                           c->value_match);
       else
        return c;
     }
@@ -1022,36 +1110,34 @@ lower_opt_convert (operand *o, enum tree_code oper,
   if (!e)
     return o;
 
-  if (*e->operation == oper)
+  if (e->opt_grp == grp)
     {
       if (strip)
-       return lower_opt_convert (e->ops[0], oper, to_oper, strip);
+       return lower_opt (e->ops[0], grp, strip);
 
       expr *ne = new expr (e);
-      ne->operation = (to_oper == CONVERT_EXPR
-                      ? get_operator ("CONVERT_EXPR")
-                      : get_operator ("VIEW_CONVERT_EXPR"));
-      ne->append_op (lower_opt_convert (e->ops[0], oper, to_oper, strip));
+      ne->opt_grp = 0;
+      ne->append_op (lower_opt (e->ops[0], grp, strip));
       return ne;
     }
 
   expr *ne = new expr (e);
   for (unsigned i = 0; i < e->ops.length (); ++i)
-    ne->append_op (lower_opt_convert (e->ops[i], oper, to_oper, strip));
+    ne->append_op (lower_opt (e->ops[i], grp, strip));
 
   return ne;
 }
 
-/* Determine whether O or its children uses the conditional conversion
-   operator OPER.  */
+/* Determine whether O or its children uses the conditional operation 
+   group GRP.  */
 
 static bool
-has_opt_convert (operand *o, enum tree_code oper)
+has_opt (operand *o, unsigned char grp)
 {
   if (capture *c = dyn_cast<capture *> (o))
     {
       if (c->what)
-       return has_opt_convert (c->what, oper);
+       return has_opt (c->what, grp);
       else
        return false;
     }
@@ -1060,11 +1146,11 @@ has_opt_convert (operand *o, enum tree_code oper)
   if (!e)
     return false;
 
-  if (*e->operation == oper)
+  if (e->opt_grp == grp)
     return true;
 
   for (unsigned i = 0; i < e->ops.length (); ++i)
-    if (has_opt_convert (e->ops[i], oper))
+    if (has_opt (e->ops[i], grp))
       return true;
 
   return false;
@@ -1074,34 +1160,24 @@ has_opt_convert (operand *o, enum tree_code oper)
    if required.  */
 
 static vec<operand *>
-lower_opt_convert (operand *o)
+lower_opt (operand *o)
 {
   vec<operand *> v1 = vNULL, v2;
 
   v1.safe_push (o);
 
-  enum tree_code opers[]
-    = { CONVERT0, CONVERT_EXPR,
-       CONVERT1, CONVERT_EXPR,
-       CONVERT2, CONVERT_EXPR,
-       VIEW_CONVERT0, VIEW_CONVERT_EXPR,
-       VIEW_CONVERT1, VIEW_CONVERT_EXPR,
-       VIEW_CONVERT2, VIEW_CONVERT_EXPR };
-
-  /* Conditional converts are lowered to a pattern with the
-     conversion and one without.  The three different conditional
-     convert codes are lowered separately.  */
+  /* Conditional operations are lowered to a pattern with the
+     operation and one without.  All different conditional operation
+     groups are lowered separately.  */
 
-  for (unsigned i = 0; i < sizeof (opers) / sizeof (enum tree_code); i += 2)
+  for (unsigned i = 1; i <= 10; ++i)
     {
       v2 = vNULL;
       for (unsigned j = 0; j < v1.length (); ++j)
-       if (has_opt_convert (v1[j], opers[i]))
+       if (has_opt (v1[j], i))
          {
-           v2.safe_push (lower_opt_convert (v1[j],
-                                            opers[i], opers[i+1], false));
-           v2.safe_push (lower_opt_convert (v1[j],
-                                            opers[i], opers[i+1], true));
+           v2.safe_push (lower_opt (v1[j], i, false));
+           v2.safe_push (lower_opt (v1[j], i, true));
          }
 
       if (v2 != vNULL)
@@ -1119,12 +1195,12 @@ lower_opt_convert (operand *o)
    the resulting multiple patterns to SIMPLIFIERS.  */
 
 static void
-lower_opt_convert (simplify *s, vec<simplify *>& simplifiers)
+lower_opt (simplify *s, vec<simplify *>& simplifiers)
 {
-  vec<operand *> matchers = lower_opt_convert (s->match);
+  vec<operand *> matchers = lower_opt (s->match);
   for (unsigned i = 0; i < matchers.length (); ++i)
     {
-      simplify *ns = new simplify (s->kind, matchers[i], s->result,
+      simplify *ns = new simplify (s->kind, s->id, matchers[i], s->result,
                                   s->for_vec, s->capture_ids);
       simplifiers.safe_push (ns);
     }
@@ -1146,7 +1222,8 @@ lower_cond (operand *o)
          lop = lower_cond (c->what);
 
          for (unsigned i = 0; i < lop.length (); ++i)
-           ro.safe_push (new capture (c->location, c->where, lop[i]));
+           ro.safe_push (new capture (c->location, c->where, lop[i],
+                                      c->value_match));
          return ro;
        }
     }
@@ -1186,7 +1263,7 @@ lower_cond (operand *o)
              || (is_a <expr *> (e->ops[0])
                  && as_a <expr *> (e->ops[0])->ops.length () == 2)))
        {
-         expr *ne = new expr (e);
+         ne = new expr (e);
          for (unsigned j = 0; j < result[i].length (); ++j)
            ne->append_op (result[i][j]);
          if (capture *c = dyn_cast <capture *> (ne->ops[0]))
@@ -1196,7 +1273,8 @@ lower_cond (operand *o)
              for (unsigned j = 0; j < ocmp->ops.length (); ++j)
                cmp->append_op (ocmp->ops[j]);
              cmp->is_generic = true;
-             ne->ops[0] = new capture (c->location, c->where, cmp);
+             ne->ops[0] = new capture (c->location, c->where, cmp,
+                                       c->value_match);
            }
          else
            {
@@ -1223,7 +1301,7 @@ lower_cond (simplify *s, vec<simplify *>& simplifiers)
   vec<operand *> matchers = lower_cond (s->match);
   for (unsigned i = 0; i < matchers.length (); ++i)
     {
-      simplify *ns = new simplify (s->kind, matchers[i], s->result,
+      simplify *ns = new simplify (s->kind, s->id, matchers[i], s->result,
                                   s->for_vec, s->capture_ids);
       simplifiers.safe_push (ns);
     }
@@ -1275,7 +1353,7 @@ replace_id (operand *o, user_id *id, id_base *with)
       if (!c->what)
        return c;
       return new capture (c->location, c->where,
-                         replace_id (c->what, id, with));
+                         replace_id (c->what, id, with), c->value_match);
     }
   else if (expr *e = dyn_cast<expr *> (o))
     {
@@ -1416,8 +1494,7 @@ lower_for (simplify *sin, vec<simplify *>& simplifiers)
            {
              operand *match_op = s->match;
              operand *result_op = s->result;
-             vec<std::pair<user_id *, id_base *> > subst;
-             subst.create (n_ids);
+             auto_vec<std::pair<user_id *, id_base *> > subst (n_ids);
              bool skip = false;
              for (unsigned i = 0; i < n_ids; ++i)
                {
@@ -1437,18 +1514,15 @@ lower_for (simplify *sin, vec<simplify *>& simplifiers)
                    result_op = replace_id (result_op, id, oper);
                }
              if (skip)
-               {
-                 subst.release ();
-                 continue;
-               }
-             simplify *ns = new simplify (s->kind, match_op, result_op,
+               continue;
+
+             simplify *ns = new simplify (s->kind, s->id, match_op, result_op,
                                           vNULL, s->capture_ids);
              ns->for_subst_vec.safe_splice (s->for_subst_vec);
              if (result_op
                  && can_delay_subst)
                ns->for_subst_vec.safe_splice (subst);
-             else
-               subst.release ();
+
              worklist.safe_push (ns);
            }
        }
@@ -1467,7 +1541,7 @@ lower (vec<simplify *>& simplifiers, bool gimple)
 {
   auto_vec<simplify *> out_simplifiers;
   for (unsigned i = 0; i < simplifiers.length (); ++i)
-    lower_opt_convert (simplifiers[i], out_simplifiers);
+    lower_opt (simplifiers[i], out_simplifiers);
 
   simplifiers.truncate (0);
   for (unsigned i = 0; i < out_simplifiers.length (); ++i)
@@ -1493,7 +1567,7 @@ lower (vec<simplify *>& simplifiers, bool gimple)
    matching code.  It represents the 'match' expression of all
    simplifies and has those as its leafs.  */
 
-struct dt_simplify;
+class dt_simplify;
 
 /* A hash-map collecting semantically equivalent leafs in the decision
    tree for splitting out to separate functions.  */
@@ -1516,15 +1590,20 @@ struct sinfo_hashmap_traits : simple_hashmap_traits<pointer_hash<dt_simplify>,
 typedef hash_map<void * /* unused */, sinfo *, sinfo_hashmap_traits>
   sinfo_map_t;
 
+/* Current simplifier ID we are processing during insertion into the
+   decision tree.  */
+static unsigned current_id;
 
-/* Decision tree base class, used for DT_TRUE and DT_NODE.  */
+/* Decision tree base class, used for DT_NODE.  */
 
-struct dt_node
+class dt_node
 {
+public:
   enum dt_type { DT_NODE, DT_OPERAND, DT_TRUE, DT_MATCH, DT_SIMPLIFY };
 
   enum dt_type type;
   unsigned level;
+  dt_node *parent;
   vec<dt_node *> kids;
 
   /* Statistics.  */
@@ -1532,43 +1611,47 @@ struct dt_node
   unsigned total_size;
   unsigned max_level;
 
-  dt_node (enum dt_type type_): type (type_), level (0), kids (vNULL) {}
+  dt_node (enum dt_type type_, dt_node *parent_)
+    : type (type_), level (0), parent (parent_), kids (vNULL) {}
 
   dt_node *append_node (dt_node *);
-  dt_node *append_op (operand *, dt_node *parent = 0, unsigned pos = 0);
-  dt_node *append_true_op (dt_node *parent = 0, unsigned pos = 0);
-  dt_node *append_match_op (dt_operand *, dt_node *parent = 0, unsigned pos = 0);
+  dt_node *append_op (operand *, dt_node *parent, unsigned pos);
+  dt_node *append_true_op (operand *, dt_node *parent, unsigned pos);
+  dt_node *append_match_op (operand *, dt_operand *, dt_node *parent,
+                           unsigned pos);
   dt_node *append_simplify (simplify *, unsigned, dt_operand **);
 
-  virtual void gen (FILE *, int, bool) {}
+  virtual void gen (FILE *, int, bool, int) {}
 
-  void gen_kids (FILE *, int, bool);
-  void gen_kids_1 (FILE *, int, bool,
+  void gen_kids (FILE *, int, bool, int);
+  void gen_kids_1 (FILE *, int, bool, int,
                   vec<dt_operand *>, vec<dt_operand *>, vec<dt_operand *>,
                   vec<dt_operand *>, vec<dt_operand *>, vec<dt_node *>);
 
   void analyze (sinfo_map_t &);
 };
 
-/* Generic decision tree node used for DT_OPERAND and DT_MATCH.  */
+/* Generic decision tree node used for DT_OPERAND, DT_MATCH and DT_TRUE.  */
 
-struct dt_operand : public dt_node
+class dt_operand : public dt_node
 {
+public:
   operand *op;
   dt_operand *match_dop;
-  dt_operand *parent;
   unsigned pos;
+  bool value_match;
+  unsigned for_id;
 
   dt_operand (enum dt_type type, operand *op_, dt_operand *match_dop_,
-             dt_operand *parent_ = 0, unsigned pos_ = 0)
-      : dt_node (type), op (op_), match_dop (match_dop_),
-      parent (parent_), pos (pos_) {}
+             dt_operand *parent_, unsigned pos_)
+      : dt_node (type, parent_), op (op_), match_dop (match_dop_),
+      pos (pos_), value_match (false), for_id (current_id) {}
 
-  void gen (FILE *, int, bool);
+  void gen (FILE *, int, bool, int);
   unsigned gen_predicate (FILE *, int, const char *, bool);
-  unsigned gen_match_op (FILE *, int, const char *);
+  unsigned gen_match_op (FILE *, int, const char *, bool);
 
-  unsigned gen_gimple_expr (FILE *, int);
+  unsigned gen_gimple_expr (FILE *, int, int);
   unsigned gen_generic_expr (FILE *, int, const char *);
 
   char *get_name (char *);
@@ -1577,19 +1660,20 @@ struct dt_operand : public dt_node
 
 /* Leaf node of the decision tree, used for DT_SIMPLIFY.  */
 
-struct dt_simplify : public dt_node
+class dt_simplify : public dt_node
 {
+public:
   simplify *s;
   unsigned pattern_no;
   dt_operand **indexes;
   sinfo *info;
 
   dt_simplify (simplify *s_, unsigned pattern_no_, dt_operand **indexes_)
-       : dt_node (DT_SIMPLIFY), s (s_), pattern_no (pattern_no_),
+       : dt_node (DT_SIMPLIFY, NULL), s (s_), pattern_no (pattern_no_),
          indexes (indexes_), info (NULL)  {}
 
   void gen_1 (FILE *, int, bool, operand *);
-  void gen (FILE *f, int, bool);
+  void gen (FILE *f, int, bool, int);
 };
 
 template<>
@@ -1598,7 +1682,8 @@ inline bool
 is_a_helper <dt_operand *>::test (dt_node *n)
 {
   return (n->type == dt_node::DT_OPERAND
-         || n->type == dt_node::DT_MATCH);
+         || n->type == dt_node::DT_MATCH
+         || n->type == dt_node::DT_TRUE);
 }
 
 template<>
@@ -1613,15 +1698,16 @@ is_a_helper <dt_simplify *>::test (dt_node *n)
 
 /* A container for the actual decision tree.  */
 
-struct decision_tree
+class decision_tree
 {
+public:
   dt_node *root;
 
-  void insert (struct simplify *, unsigned);
+  void insert (class simplify *, unsigned);
   void gen (FILE *f, bool gimple);
   void print (FILE *f = stderr);
 
-  decision_tree () { root = new dt_node (dt_node::DT_NODE); }
+  decision_tree () { root = new dt_node (dt_node::DT_NODE, NULL); }
 
   static dt_node *insert_operand (dt_node *, operand *, dt_operand **indexes,
                                  unsigned pos = 0, dt_node *parent = 0);
@@ -1674,8 +1760,10 @@ decision_tree::cmp_node (dt_node *n1, dt_node *n2)
     return cmp_operand ((as_a<dt_operand *> (n1))->op,
                        (as_a<dt_operand *> (n2))->op);
   else if (n1->type == dt_node::DT_MATCH)
-    return ((as_a<dt_operand *> (n1))->match_dop
-           == (as_a<dt_operand *> (n2))->match_dop);
+    return (((as_a<dt_operand *> (n1))->match_dop
+            == (as_a<dt_operand *> (n2))->match_dop)
+           && ((as_a<dt_operand *> (n1))->value_match
+               == (as_a<dt_operand *> (n2))->value_match));
   return false;
 }
 
@@ -1689,15 +1777,48 @@ decision_tree::find_node (vec<dt_node *>& ops, dt_node *p)
       && !ops.is_empty ()
       && ops.last ()->type == dt_node::DT_TRUE)
     return ops.last ();
+  dt_operand *true_node = NULL;
   for (int i = ops.length () - 1; i >= 0; --i)
     {
       /* But we can't merge across DT_TRUE nodes as they serve as
          pattern order barriers to make sure that patterns apply
         in order of appearance in case multiple matches are possible.  */
       if (ops[i]->type == dt_node::DT_TRUE)
-       return NULL;
+       {
+         if (! true_node
+             || as_a <dt_operand *> (ops[i])->for_id > true_node->for_id)
+           true_node = as_a <dt_operand *> (ops[i]);
+       }
       if (decision_tree::cmp_node (ops[i], p))
-       return ops[i];
+       {
+         /* Unless we are processing the same pattern or the blocking
+            pattern is before the one we are going to merge with.  */
+         if (true_node
+             && true_node->for_id != current_id
+             && true_node->for_id > as_a <dt_operand *> (ops[i])->for_id)
+           {
+             if (verbose >= 1)
+               {
+                 location_t p_loc = 0;
+                 if (p->type == dt_node::DT_OPERAND)
+                   p_loc = as_a <dt_operand *> (p)->op->location;
+                 location_t op_loc = 0;
+                 if (ops[i]->type == dt_node::DT_OPERAND)
+                   op_loc = as_a <dt_operand *> (ops[i])->op->location;
+                 location_t true_loc = 0;
+                 true_loc = true_node->op->location;
+                 warning_at (p_loc,
+                             "failed to merge decision tree node");
+                 warning_at (op_loc,
+                             "with the following");
+                 warning_at (true_loc,
+                             "because of the following which serves as ordering "
+                             "barrier");
+               }
+             return NULL;
+           }
+         return ops[i];
+       }
     }
   return NULL;
 }
@@ -1733,20 +1854,21 @@ dt_node::append_op (operand *op, dt_node *parent, unsigned pos)
 /* Append a DT_TRUE decision tree node.  */
 
 dt_node *
-dt_node::append_true_op (dt_node *parent, unsigned pos)
+dt_node::append_true_op (operand *op, dt_node *parent, unsigned pos)
 {
   dt_operand *parent_ = safe_as_a<dt_operand *> (parent);
-  dt_operand *n = new dt_operand (DT_TRUE, 0, 0, parent_, pos);
+  dt_operand *n = new dt_operand (DT_TRUE, op, 0, parent_, pos);
   return append_node (n);
 }
 
 /* Append a DT_MATCH decision tree node.  */
 
 dt_node *
-dt_node::append_match_op (dt_operand *match_dop, dt_node *parent, unsigned pos)
+dt_node::append_match_op (operand *op, dt_operand *match_dop,
+                         dt_node *parent, unsigned pos)
 {
   dt_operand *parent_ = as_a<dt_operand *> (parent);
-  dt_operand *n = new dt_operand (DT_MATCH, 0, match_dop, parent_, pos);
+  dt_operand *n = new dt_operand (DT_MATCH, op, match_dop, parent_, pos);
   return append_node (n);
 }
 
@@ -1756,10 +1878,15 @@ dt_node *
 dt_node::append_simplify (simplify *s, unsigned pattern_no,
                          dt_operand **indexes)
 {
+  dt_simplify *s2;
   dt_simplify *n = new dt_simplify (s, pattern_no, indexes);
   for (unsigned i = 0; i < kids.length (); ++i)
-    if (dt_simplify *s2 = dyn_cast <dt_simplify *> (kids[i]))
+    if ((s2 = dyn_cast <dt_simplify *> (kids[i]))
+       && (verbose >= 1
+           || s->match->location != s2->s->match->location))
       {
+       /* With a nested patters, it's hard to avoid these in order
+          to keep match.pd rules relatively small.  */
        warning_at (s->match->location, "duplicate pattern");
        warning_at (s2->s->match->location, "previous pattern defined here");
        print_operand (s->match, stderr);
@@ -1825,7 +1952,7 @@ decision_tree::insert_operand (dt_node *p, operand *o, dt_operand **indexes,
            q = insert_operand (p, c->what, indexes, pos, parent);
          else
            {
-             q = elm = p->append_true_op (parent, pos);
+             q = elm = p->append_true_op (o, parent, pos);
              goto at_assert_elm;
            }
          // get to the last capture
@@ -1839,18 +1966,19 @@ decision_tree::insert_operand (dt_node *p, operand *o, dt_operand **indexes,
              unsigned cc_index = c->where;
              dt_operand *match_op = indexes[cc_index];
 
-             dt_operand temp (dt_node::DT_TRUE, 0, 0);
+             dt_operand temp (dt_node::DT_TRUE, 0, 0, 0, 0);
              elm = decision_tree::find_node (p->kids, &temp);
 
              if (elm == 0)
                {
-                 dt_operand temp (dt_node::DT_MATCH, 0, match_op);
-                 elm = decision_tree::find_node (p->kids, &temp);
+                 dt_operand match (dt_node::DT_MATCH, 0, match_op, 0, 0);
+                 match.value_match = c->value_match;
+                 elm = decision_tree::find_node (p->kids, &match);
                }
            }
          else
            {
-             dt_operand temp (dt_node::DT_OPERAND, c->what, 0);
+             dt_operand temp (dt_node::DT_OPERAND, c->what, 0, 0, 0);
              elm = decision_tree::find_node (p->kids, &temp);
            }
 
@@ -1863,7 +1991,8 @@ at_assert_elm:
        }
       else
        {
-         p = p->append_match_op (indexes[capt_index], parent, pos);
+         p = p->append_match_op (o, indexes[capt_index], parent, pos);
+         as_a <dt_operand *>(p)->value_match = c->value_match;
          if (c->what)
            return insert_operand (p, c->what, indexes, 0, p);
          else
@@ -1885,8 +2014,9 @@ at_assert_elm:
 /* Insert S into the decision tree.  */
 
 void
-decision_tree::insert (struct simplify *s, unsigned pattern_no)
+decision_tree::insert (class simplify *s, unsigned pattern_no)
 {
+  current_id = s->id;
   dt_operand **indexes = XCNEWVEC (dt_operand *, s->capture_max + 1);
   dt_node *p = decision_tree::insert_operand (root, s->match, indexes);
   p->append_simplify (s, pattern_no, indexes);
@@ -1922,9 +2052,12 @@ decision_tree::print_node (dt_node *p, FILE *f, unsigned indent)
            fprintf (f, "%p, ", (void *) s->indexes[i]);
          fprintf (f, " } ");
        }
+      if (is_a <dt_operand *> (p))
+       fprintf (f, " [%u]", as_a <dt_operand *> (p)->for_id);
     }
 
-  fprintf (stderr, " (%p), %u, %u\n", (void *) p, p->level, p->kids.length ());
+  fprintf (stderr, " (%p, %p), %u, %u\n",
+          (void *) p, (void *) p->parent, p->level, p->kids.length ());
 
   for (unsigned i = 0; i < p->kids.length (); ++i)
     decision_tree::print_node (p->kids[i], f, indent + 2);
@@ -1944,8 +2077,9 @@ decision_tree::print (FILE *f)
    on the outermost match expression operands for cases we cannot
    handle.  */
 
-struct capture_info
+class capture_info
 {
+public:
   capture_info (simplify *s, operand *, bool);
   void walk_match (operand *o, unsigned toplevel_arg, bool, bool);
   bool walk_result (operand *o, bool, operand *);
@@ -2039,7 +2173,11 @@ capture_info::walk_match (operand *o, unsigned toplevel_arg,
       if (c->what
          && (e = dyn_cast <expr *> (c->what)))
        {
-         info[where].expr_p = true;
+         /* Zero-operand expression captures like ADDR_EXPR@0 are
+            similar as predicates -- if they are not mentioned in
+            the result we have to force them to have no side-effects.  */
+         if (e->ops.length () != 0)
+           info[where].expr_p = true;
          info[where].force_single_use |= e->force_single_use;
        }
     }
@@ -2048,7 +2186,7 @@ capture_info::walk_match (operand *o, unsigned toplevel_arg,
       for (unsigned i = 0; i < e->ops.length (); ++i)
        {
          bool cond_p = conditional_p;
-         bool cond_expr_cond_p = false;
+         bool expr_cond_p = false;
          if (i != 0 && *e->operation == COND_EXPR)
            cond_p = true;
          else if (*e->operation == TRUTH_ANDIF_EXPR
@@ -2057,8 +2195,8 @@ capture_info::walk_match (operand *o, unsigned toplevel_arg,
          if (i == 0
              && (*e->operation == COND_EXPR
                  || *e->operation == VEC_COND_EXPR))
-           cond_expr_cond_p = true;
-         walk_match (e->ops[i], toplevel_arg, cond_p, cond_expr_cond_p);
+           expr_cond_p = true;
+         walk_match (e->ops[i], toplevel_arg, cond_p, expr_cond_p);
        }
     }
   else if (is_a <predicate *> (o))
@@ -2116,42 +2254,42 @@ capture_info::walk_result (operand *o, bool conditional_p, operand *result)
          walk_result (e->ops[i], cond_p, result);
        }
     }
-  else if (if_expr *e = dyn_cast <if_expr *> (o))
+  else if (if_expr *ie = dyn_cast <if_expr *> (o))
     {
       /* 'if' conditions should be all fine.  */
-      if (e->trueexpr == result)
+      if (ie->trueexpr == result)
        {
-         walk_result (e->trueexpr, false, result);
+         walk_result (ie->trueexpr, false, result);
          return true;
        }
-      if (e->falseexpr == result)
+      if (ie->falseexpr == result)
        {
-         walk_result (e->falseexpr, false, result);
+         walk_result (ie->falseexpr, false, result);
          return true;
        }
       bool res = false;
-      if (is_a <if_expr *> (e->trueexpr)
-         || is_a <with_expr *> (e->trueexpr))
-       res |= walk_result (e->trueexpr, false, result);
-      if (e->falseexpr
-         && (is_a <if_expr *> (e->falseexpr)
-             || is_a <with_expr *> (e->falseexpr)))
-       res |= walk_result (e->falseexpr, false, result);
+      if (is_a <if_expr *> (ie->trueexpr)
+         || is_a <with_expr *> (ie->trueexpr))
+       res |= walk_result (ie->trueexpr, false, result);
+      if (ie->falseexpr
+         && (is_a <if_expr *> (ie->falseexpr)
+             || is_a <with_expr *> (ie->falseexpr)))
+       res |= walk_result (ie->falseexpr, false, result);
       return res;
     }
-  else if (with_expr *e = dyn_cast <with_expr *> (o))
+  else if (with_expr *we = dyn_cast <with_expr *> (o))
     {
-      bool res = (e->subexpr == result);
+      bool res = (we->subexpr == result);
       if (res
-         || is_a <if_expr *> (e->subexpr)
-         || is_a <with_expr *> (e->subexpr))
-       res |= walk_result (e->subexpr, false, result);
+         || is_a <if_expr *> (we->subexpr)
+         || is_a <with_expr *> (we->subexpr))
+       res |= walk_result (we->subexpr, false, result);
       if (res)
-       walk_c_expr (e->with);
+       walk_c_expr (we->with);
       return res;
     }
-  else if (c_expr *e = dyn_cast <c_expr *> (o))
-    walk_c_expr (e);
+  else if (c_expr *ce = dyn_cast <c_expr *> (o))
+    walk_c_expr (ce);
   else
     gcc_unreachable ();
 
@@ -2193,13 +2331,15 @@ capture_info::walk_c_expr (c_expr *e)
                   || n->type == CPP_NAME)
               && !(n->flags & PREV_WHITE))
        {
-         const char *id;
+         const char *id1;
          if (n->type == CPP_NUMBER)
-           id = (const char *)n->val.str.text;
+           id1 = (const char *)n->val.str.text;
          else
-           id = (const char *)CPP_HASHNODE (n->val.node.node)->ident.str;
-         unsigned where = *e->capture_ids->get(id);
-         info[info[where].same_as].force_no_side_effects_p = true;
+           id1 = (const char *)CPP_HASHNODE (n->val.node.node)->ident.str;
+         unsigned *where = e->capture_ids->get(id1);
+         if (! where)
+           fatal_at (n, "unknown capture id '%s'", id1);
+         info[info[*where].same_as].force_no_side_effects_p = true;
          if (verbose >= 1
              && !gimple)
            warning_at (t, "capture escapes");
@@ -2220,11 +2360,12 @@ is_conversion (id_base *op)
          || *op == VIEW_CONVERT_EXPR);
 }
 
-/* Get the type to be used for generating operands of OP from the
+/* Get the type to be used for generating operand POS of OP from the
    various sources.  */
 
 static const char *
-get_operand_type (id_base *op, const char *in_type,
+get_operand_type (id_base *op, unsigned pos,
+                 const char *in_type,
                  const char *expr_type,
                  const char *other_oprnd_type)
 {
@@ -2239,6 +2380,21 @@ get_operand_type (id_base *op, const char *in_type,
   else if (is_a <operator_id *> (op)
           && strcmp (as_a <operator_id *> (op)->tcc, "tcc_comparison") == 0)
     return other_oprnd_type;
+  else if (*op == COND_EXPR
+          && pos == 0)
+    return "boolean_type_node";
+  else if (strncmp (op->id, "CFN_COND_", 9) == 0)
+    {
+      /* IFN_COND_* operands 1 and later by default have the same type
+        as the result.  The type of operand 0 needs to be specified
+        explicitly.  */
+      if (pos > 0 && expr_type)
+       return expr_type;
+      else if (pos > 0 && in_type)
+       return in_type;
+      else
+       return NULL;
+    }
   else
     {
       /* Otherwise all types should match - choose one in order of
@@ -2280,7 +2436,8 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
           || *opr == IMAGPART_EXPR)
     {
       /* __real and __imag use the component type of its operand.  */
-      sprintf (optype, "TREE_TYPE (TREE_TYPE (ops%d[0]))", depth);
+      snprintf (optype, sizeof (optype), "TREE_TYPE (TREE_TYPE (_o%d[0]))",
+               depth);
       type = optype;
     }
   else if (is_a <operator_id *> (opr)
@@ -2292,22 +2449,23 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
        type = in_type;
       else
        {
-         sprintf (optype, "boolean_type_node");
+         snprintf (optype, sizeof (optype), "boolean_type_node");
          type = optype;
        }
       in_type = NULL;
     }
   else if (*opr == COND_EXPR
-          || *opr == VEC_COND_EXPR)
+          || *opr == VEC_COND_EXPR
+          || strncmp (opr->id, "CFN_COND_", 9) == 0)
     {
       /* Conditions are of the same type as their first alternative.  */
-      sprintf (optype, "TREE_TYPE (ops%d[1])", depth);
+      snprintf (optype, sizeof (optype), "TREE_TYPE (_o%d[1])", depth);
       type = optype;
     }
   else
     {
       /* Other operations are of the same type as their first operand.  */
-      sprintf (optype, "TREE_TYPE (ops%d[0])", depth);
+      snprintf (optype, sizeof (optype), "TREE_TYPE (_o%d[0])", depth);
       type = optype;
     }
   if (!type)
@@ -2315,17 +2473,18 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
 
   fprintf_indent (f, indent, "{\n");
   indent += 2;
-  fprintf_indent (f, indent, "tree ops%d[%u], res;\n", depth, ops.length ());
+  fprintf_indent (f, indent,
+                 "tree _o%d[%u], _r%d;\n", depth, ops.length (), depth);
   char op0type[64];
-  snprintf (op0type, 64, "TREE_TYPE (ops%d[0])", depth);
+  snprintf (op0type, sizeof (op0type), "TREE_TYPE (_o%d[0])", depth);
   for (unsigned i = 0; i < ops.length (); ++i)
     {
-      char dest[32];
-      snprintf (dest, 32, "ops%d[%u]", depth, i);
-      const char *optype
-       = get_operand_type (opr, in_type, expr_type,
+      char dest1[32];
+      snprintf (dest1, sizeof (dest1), "_o%d[%u]", depth, i);
+      const char *optype1
+       = get_operand_type (opr, i, in_type, expr_type,
                            i == 0 ? NULL : op0type);
-      ops[i]->gen_transform (f, indent, dest, gimple, depth + 1, optype,
+      ops[i]->gen_transform (f, indent, dest1, gimple, depth + 1, optype1,
                             cinfo, indexes,
                             (*opr == COND_EXPR
                              || *opr == VEC_COND_EXPR) && i == 0 ? 1 : 2);
@@ -2342,10 +2501,11 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
       if (*opr == CONVERT_EXPR)
        {
          fprintf_indent (f, indent,
-                         "if (%s != TREE_TYPE (ops%d[0])\n",
+                         "if (%s != TREE_TYPE (_o%d[0])\n",
                          type, depth);
          fprintf_indent (f, indent,
-                         "    && !useless_type_conversion_p (%s, TREE_TYPE (ops%d[0])))\n",
+                         "    && !useless_type_conversion_p (%s, TREE_TYPE "
+                         "(_o%d[0])))\n",
                          type, depth);
          fprintf_indent (f, indent + 2, "{\n");
          indent += 4;
@@ -2353,50 +2513,48 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
       /* ???  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 "
+                     "(res_op->cond.any_else (), %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_indent (f, indent,
-                     "gimple_resimplify%d (lseq, &tem_code, %s, tem_ops, valueize);\n",
-                     ops.length (), type);
+       fprintf (f, ", _o%d[%u]", depth, i);
+      fprintf (f, ");\n");
+      fprintf_indent (f, indent, "tem_op.resimplify (lseq, valueize);\n");
       fprintf_indent (f, indent,
-                     "res = maybe_push_res_to_seq (tem_code, %s, tem_ops, lseq);\n",
-                     type);
+                     "_r%d = maybe_push_res_to_seq (&tem_op, lseq);\n", depth);
       fprintf_indent (f, indent,
-                     "if (!res) return false;\n");
+                     "if (!_r%d) return false;\n",
+                     depth);
       if (*opr == CONVERT_EXPR)
        {
          indent -= 4;
          fprintf_indent (f, indent, "  }\n");
          fprintf_indent (f, indent, "else\n");
-         fprintf_indent (f, indent, "  res = ops%d[0];\n", depth);
+         fprintf_indent (f, indent, "  _r%d = _o%d[0];\n", depth, depth);
        }
     }
   else
     {
       if (*opr == CONVERT_EXPR)
        {
-         fprintf_indent (f, indent, "if (TREE_TYPE (ops%d[0]) != %s)\n",
+         fprintf_indent (f, indent, "if (TREE_TYPE (_o%d[0]) != %s)\n",
                          depth, type);
          indent += 2;
        }
       if (opr->kind == id_base::CODE)
-       fprintf_indent (f, indent, "res = fold_build%d_loc (loc, %s, %s",
-                       ops.length(), opr_name, type);
+       fprintf_indent (f, indent, "_r%d = fold_build%d_loc (loc, %s, %s",
+                       depth, ops.length(), opr_name, type);
       else
        {
          fprintf_indent (f, indent, "{\n");
-         fprintf_indent (f, indent, "  res = maybe_build_call_expr_loc (loc, "
-                         "%s, %s, %d", opr_name, type, ops.length());
+         fprintf_indent (f, indent, "  _r%d = maybe_build_call_expr_loc (loc, "
+                         "%s, %s, %d", depth, opr_name, type, ops.length());
        }
       for (unsigned i = 0; i < ops.length (); ++i)
-       fprintf (f, ", ops%d[%u]", depth, i);
+       fprintf (f, ", _o%d[%u]", depth, i);
       fprintf (f, ");\n");
       if (opr->kind != id_base::CODE)
        {
-         fprintf_indent (f, indent, "  if (!res)\n");
+         fprintf_indent (f, indent, "  if (!_r%d)\n", depth);
          fprintf_indent (f, indent, "    return NULL_TREE;\n");
          fprintf_indent (f, indent, "}\n");
        }
@@ -2404,10 +2562,10 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
        {
          indent -= 2;
          fprintf_indent (f, indent, "else\n");
-         fprintf_indent (f, indent, "  res = ops%d[0];\n", depth);
+         fprintf_indent (f, indent, "  _r%d = _o%d[0];\n", depth, depth);
        }
     }
-  fprintf_indent (f, indent, "%s = res;\n", dest);
+  fprintf_indent (f, indent, "%s = _r%d;\n", dest, depth);
   indent -= 2;
   fprintf_indent (f, indent, "}\n");
 }
@@ -2425,10 +2583,22 @@ c_expr::gen_transform (FILE *f, int indent, const char *dest,
     fprintf_indent (f, indent, "%s = ", dest);
 
   unsigned stmt_nr = 1;
+  int prev_line = -1;
   for (unsigned i = 0; i < code.length (); ++i)
     {
       const cpp_token *token = &code[i];
 
+      /* We can't recover from all lexing losses but we can roughly restore line
+         breaks from location info.  */
+      const line_map_ordinary *map;
+      linemap_resolve_location (line_table, token->src_loc,
+                               LRK_SPELLING_LOCATION, &map);
+      expanded_location loc = linemap_expand_location (line_table, map,
+                                                      token->src_loc);
+      if (prev_line != -1 && loc.line != prev_line)
+       fputc ('\n', f);
+      prev_line = loc.line;
+
       /* Replace captures for code-gen.  */
       if (token->type == CPP_ATSIGN)
        {
@@ -2479,11 +2649,11 @@ c_expr::gen_transform (FILE *f, int indent, const char *dest,
       if (token->type == CPP_SEMICOLON)
        {
          stmt_nr++;
-         fputc ('\n', f);
          if (dest && stmt_nr == nr_stmts)
            fprintf_indent (f, indent, "%s = ", dest);
        }
     }
+  fputc ('\n', f);
 }
 
 /* Generate transform code for a capture.  */
@@ -2498,13 +2668,24 @@ capture::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
       if (indexes[where] == 0)
        {
          char buf[20];
-         sprintf (buf, "captures[%u]", where);
+         snprintf (buf, sizeof (buf), "captures[%u]", where);
          what->gen_transform (f, indent, buf, gimple, depth, in_type,
                               cinfo, NULL);
        }
     }
 
-  fprintf_indent (f, indent, "%s = captures[%u];\n", dest, where);
+  /* If in GENERIC some capture is used multiple times, unshare it except
+     when emitting the last use.  */
+  if (!gimple
+      && cinfo->info.exists ()
+      && cinfo->info[cinfo->info[where].same_as].result_use_count > 1)
+    {
+      fprintf_indent (f, indent, "%s = unshare_expr (captures[%u]);\n",
+                     dest, where);
+      cinfo->info[cinfo->info[where].same_as].result_use_count--;
+    }
+  else
+    fprintf_indent (f, indent, "%s = captures[%u];\n", dest, where);
 
   /* ???  Stupid tcc_comparison GENERIC trees in COND_EXPRs.  Deal
      with substituting a capture of that.  */
@@ -2539,14 +2720,14 @@ capture::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
 char *
 dt_operand::get_name (char *name)
 {
-  if (!parent)
+  if (! parent)
     sprintf (name, "t");
   else if (parent->level == 1)
-    sprintf (name, "op%u", pos);
+    sprintf (name, "_p%u", pos);
   else if (parent->type == dt_node::DT_MATCH)
-    return parent->get_name (name);
+    return as_a <dt_operand *> (parent)->get_name (name);
   else
-    sprintf (name, "o%u%u", parent->level, pos);
+    sprintf (name, "_q%u%u", parent->level, pos);
   return name;
 }
 
@@ -2555,10 +2736,10 @@ dt_operand::get_name (char *name)
 void
 dt_operand::gen_opname (char *name, unsigned pos)
 {
-  if (!parent)
-    sprintf (name, "op%u", pos);
+  if (! parent)
+    sprintf (name, "_p%u", pos);
   else
-    sprintf (name, "o%u%u", level, pos);
+    sprintf (name, "_q%u%u", level, pos);
 }
 
 /* Generate matching code for the decision tree operand which is
@@ -2589,12 +2770,20 @@ dt_operand::gen_predicate (FILE *f, int indent, const char *opname, bool gimple)
    a capture-match.  */
 
 unsigned
-dt_operand::gen_match_op (FILE *f, int indent, const char *opname)
+dt_operand::gen_match_op (FILE *f, int indent, const char *opname, bool)
 {
   char match_opname[20];
   match_dop->get_name (match_opname);
-  fprintf_indent (f, indent, "if (%s == %s || operand_equal_p (%s, %s, 0))\n",
-                 opname, match_opname, opname, match_opname);
+  if (value_match)
+    fprintf_indent (f, indent, "if ((%s == %s && ! TREE_SIDE_EFFECTS (%s)) "
+                   "|| operand_equal_p (%s, %s, 0))\n",
+                   opname, match_opname, opname, opname, match_opname);
+  else
+    fprintf_indent (f, indent, "if ((%s == %s && ! TREE_SIDE_EFFECTS (%s)) "
+                   "|| (operand_equal_p (%s, %s, 0) "
+                   "&& types_match (%s, %s)))\n",
+                   opname, match_opname, opname, opname, match_opname,
+                   opname, match_opname);
   fprintf_indent (f, indent + 2, "{\n");
   return 1;
 }
@@ -2602,11 +2791,12 @@ dt_operand::gen_match_op (FILE *f, int indent, const char *opname)
 /* Generate GIMPLE matching code for the decision tree operand.  */
 
 unsigned
-dt_operand::gen_gimple_expr (FILE *f, int indent)
+dt_operand::gen_gimple_expr (FILE *f, int indent, int depth)
 {
   expr *e = static_cast<expr *> (op);
   id_base *id = e->operation;
   unsigned n_ops = e->ops.length ();
+  unsigned n_braces = 0;
 
   for (unsigned i = 0; i < n_ops; ++i)
     {
@@ -2622,62 +2812,65 @@ dt_operand::gen_gimple_expr (FILE *f, int indent)
              /* ???  If this is a memory operation we can't (and should not)
                 match this.  The only sensible operand types are
                 SSA names and invariants.  */
-             fprintf_indent (f, indent,
-                             "tree %s = TREE_OPERAND (gimple_assign_rhs1 (def), %i);\n",
-                             child_opname, i);
+             if (e->is_generic)
+               {
+                 char opname[20];
+                 get_name (opname);
+                 fprintf_indent (f, indent,
+                                 "tree %s = TREE_OPERAND (%s, %i);\n",
+                                 child_opname, opname, i);
+               }
+             else
+               fprintf_indent (f, indent,
+                               "tree %s = TREE_OPERAND "
+                               "(gimple_assign_rhs1 (_a%d), %i);\n",
+                               child_opname, depth, i);
              fprintf_indent (f, indent,
                              "if ((TREE_CODE (%s) == SSA_NAME\n",
                              child_opname);
              fprintf_indent (f, indent,
-                             "     || is_gimple_min_invariant (%s))\n",
+                             "     || is_gimple_min_invariant (%s)))\n",
                              child_opname);
-             fprintf_indent (f, indent,
-                             "    && (%s = do_valueize (valueize, %s)))\n",
-                             child_opname, child_opname);
              fprintf_indent (f, indent,
                              "  {\n");
              indent += 4;
+             n_braces++;
+             fprintf_indent (f, indent,
+                             "%s = do_valueize (valueize, %s);\n",
+                             child_opname, child_opname);
              continue;
            }
          else
            fprintf_indent (f, indent,
-                           "tree %s = gimple_assign_rhs%u (def);\n",
-                           child_opname, i + 1);
+                           "tree %s = gimple_assign_rhs%u (_a%d);\n",
+                           child_opname, i + 1, depth);
        }
       else
        fprintf_indent (f, indent,
-                       "tree %s = gimple_call_arg (def, %u);\n",
-                       child_opname, i);
+                       "tree %s = gimple_call_arg (_c%d, %u);\n",
+                       child_opname, depth, i);
       fprintf_indent (f, indent,
-                     "if ((%s = do_valueize (valueize, %s)))\n",
+                     "%s = do_valueize (valueize, %s);\n",
                      child_opname, child_opname);
-      fprintf_indent (f, indent, "  {\n");
-      indent += 4;
     }
   /* While the toplevel operands are canonicalized by the caller
      after valueizing operands of sub-expressions we have to
      re-canonicalize operand order.  */
-  if (operator_id *code = dyn_cast <operator_id *> (id))
+  int opno = commutative_op (id);
+  if (opno >= 0)
     {
-      /* ???  We can't canonicalize tcc_comparison operands here
-         because that requires changing the comparison code which
-        we already matched...  */
-      if (commutative_tree_code (code->code)
-         || commutative_ternary_tree_code (code->code))
-       {
-         char child_opname0[20], child_opname1[20];
-         gen_opname (child_opname0, 0);
-         gen_opname (child_opname1, 1);
-         fprintf_indent (f, indent,
-                         "if (tree_swap_operands_p (%s, %s, false))\n",
-                         child_opname0, child_opname1);
-         fprintf_indent (f, indent,
-                         "  std::swap (%s, %s);\n",
-                         child_opname0, child_opname1);
-       }
+      char child_opname0[20], child_opname1[20];
+      gen_opname (child_opname0, opno);
+      gen_opname (child_opname1, opno + 1);
+      fprintf_indent (f, indent,
+                     "if (tree_swap_operands_p (%s, %s))\n",
+                     child_opname0, child_opname1);
+      fprintf_indent (f, indent,
+                     "  std::swap (%s, %s);\n",
+                     child_opname0, child_opname1);
     }
 
-  return n_ops;
+  return n_braces;
 }
 
 /* Generate GENERIC matching code for the decision tree operand.  */
@@ -2707,7 +2900,7 @@ dt_operand::gen_generic_expr (FILE *f, int indent, const char *opname)
 /* Generate matching code for the children of the decision tree node.  */
 
 void
-dt_node::gen_kids (FILE *f, int indent, bool gimple)
+dt_node::gen_kids (FILE *f, int indent, bool gimple, int depth)
 {
   auto_vec<dt_operand *> gimple_exprs;
   auto_vec<dt_operand *> generic_exprs;
@@ -2758,10 +2951,10 @@ dt_node::gen_kids (FILE *f, int indent, bool gimple)
             Like DT_TRUE, DT_MATCH serves as a barrier as it can cause
             dependent matches to get out-of-order.  Generate code now
             for what we have collected sofar.  */
-         gen_kids_1 (f, indent, gimple, gimple_exprs, generic_exprs,
+         gen_kids_1 (f, indent, gimple, depth, gimple_exprs, generic_exprs,
                      fns, generic_fns, preds, others);
          /* And output the true operand itself.  */
-         kids[i]->gen (f, indent, gimple);
+         kids[i]->gen (f, indent, gimple, depth);
          gimple_exprs.truncate (0);
          generic_exprs.truncate (0);
          fns.truncate (0);
@@ -2774,14 +2967,14 @@ dt_node::gen_kids (FILE *f, int indent, bool gimple)
     }
 
   /* Generate code for the remains.  */
-  gen_kids_1 (f, indent, gimple, gimple_exprs, generic_exprs,
+  gen_kids_1 (f, indent, gimple, depth, gimple_exprs, generic_exprs,
              fns, generic_fns, preds, others);
 }
 
 /* Generate matching code for the children of the decision tree node.  */
 
 void
-dt_node::gen_kids_1 (FILE *f, int indent, bool gimple,
+dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, int depth,
                     vec<dt_operand *> gimple_exprs,
                     vec<dt_operand *> generic_exprs,
                     vec<dt_operand *> fns,
@@ -2815,24 +3008,23 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple,
 
   if (exprs_len || fns_len)
     {
+      depth++;
       fprintf_indent (f, indent,
                      "case SSA_NAME:\n");
       fprintf_indent (f, indent,
-                     "  if (do_valueize (valueize, %s) != NULL_TREE)\n",
-                     kid_opname);
+                     "  if (gimple *_d%d = get_def (valueize, %s))\n",
+                     depth, kid_opname);
       fprintf_indent (f, indent,
                      "    {\n");
-      fprintf_indent (f, indent,
-                     "      gimple *def_stmt = SSA_NAME_DEF_STMT (%s);\n",
-                     kid_opname);
-
       indent += 6;
       if (exprs_len)
        {
          fprintf_indent (f, indent,
-                         "if (gassign *def = dyn_cast <gassign *> (def_stmt))\n");
+                         "if (gassign *_a%d = dyn_cast <gassign *> (_d%d))\n",
+                         depth, depth);
          fprintf_indent (f, indent,
-                         "  switch (gimple_assign_rhs_code (def))\n");
+                         "  switch (gimple_assign_rhs_code (_a%d))\n",
+                         depth);
          indent += 4;
          fprintf_indent (f, indent, "{\n");
          for (unsigned i = 0; i < exprs_len; ++i)
@@ -2844,7 +3036,7 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple,
              else
                fprintf_indent (f, indent, "case %s:\n", op->id);
              fprintf_indent (f, indent, "  {\n");
-             gimple_exprs[i]->gen (f, indent + 4, true);
+             gimple_exprs[i]->gen (f, indent + 4, true, depth);
              fprintf_indent (f, indent, "    break;\n");
              fprintf_indent (f, indent, "  }\n");
            }
@@ -2856,11 +3048,11 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple,
       if (fns_len)
        {
          fprintf_indent (f, indent,
-                         "%sif (gcall *def = dyn_cast <gcall *>"
-                         " (def_stmt))\n",
-                         exprs_len ? "else " : "");
+                         "%sif (gcall *_c%d = dyn_cast <gcall *> (_d%d))\n",
+                         exprs_len ? "else " : "", depth, depth);
          fprintf_indent (f, indent,
-                         "  switch (gimple_call_combined_fn (def))\n");
+                         "  switch (gimple_call_combined_fn (_c%d))\n",
+                         depth);
 
          indent += 4;
          fprintf_indent (f, indent, "{\n");
@@ -2868,10 +3060,15 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple,
            {
              expr *e = as_a <expr *>(fns[i]->op);
              fprintf_indent (f, indent, "case %s:\n", e->operation->id);
-             fprintf_indent (f, indent, "  {\n");
-             fns[i]->gen (f, indent + 4, true);
-             fprintf_indent (f, indent, "    break;\n");
-             fprintf_indent (f, indent, "  }\n");
+             /* We need to be defensive against bogus prototypes allowing
+                calls with not enough arguments.  */
+             fprintf_indent (f, indent,
+                             "  if (gimple_call_num_args (_c%d) == %d)\n"
+                             "    {\n", depth, e->ops.length ());
+             fns[i]->gen (f, indent + 6, true, depth);
+             fprintf_indent (f, indent,
+                             "    }\n"
+                             "  break;\n");
            }
 
          fprintf_indent (f, indent, "default:;\n");
@@ -2880,7 +3077,22 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple,
        }
 
       indent -= 6;
+      depth--;
       fprintf_indent (f, indent, "    }\n");
+      /* See if there is SSA_NAME among generic_exprs and if yes, emit it
+        here rather than in the next loop.  */
+      for (unsigned i = 0; i < generic_exprs.length (); ++i)
+       {
+         expr *e = as_a <expr *>(generic_exprs[i]->op);
+         id_base *op = e->operation;
+         if (*op == SSA_NAME && (exprs_len || fns_len))
+           {
+             fprintf_indent (f, indent + 4, "{\n");
+             generic_exprs[i]->gen (f, indent + 6, gimple, depth);
+             fprintf_indent (f, indent + 4, "}\n");
+           }
+       }
+
       fprintf_indent (f, indent, "  break;\n");
     }
 
@@ -2890,10 +3102,13 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple,
       id_base *op = e->operation;
       if (*op == CONVERT_EXPR || *op == NOP_EXPR)
        fprintf_indent (f, indent, "CASE_CONVERT:\n");
+      else if (*op == SSA_NAME && (exprs_len || fns_len))
+       /* Already handled above.  */
+       continue;
       else
        fprintf_indent (f, indent, "case %s:\n", op->id);
       fprintf_indent (f, indent, "  {\n");
-      generic_exprs[i]->gen (f, indent + 4, gimple);
+      generic_exprs[i]->gen (f, indent + 4, gimple, depth);
       fprintf_indent (f, indent, "    break;\n");
       fprintf_indent (f, indent, "  }\n");
     }
@@ -2915,10 +3130,11 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple,
          gcc_assert (e->operation->kind == id_base::FN);
 
          fprintf_indent (f, indent, "case %s:\n", e->operation->id);
-         fprintf_indent (f, indent, "  {\n");
-         generic_fns[j]->gen (f, indent + 4, false);
-         fprintf_indent (f, indent, "    break;\n");
-         fprintf_indent (f, indent, "  }\n");
+         fprintf_indent (f, indent, "  if (call_expr_nargs (%s) == %d)\n"
+                                    "    {\n", kid_opname, e->ops.length ());
+         generic_fns[j]->gen (f, indent + 6, false, depth);
+         fprintf_indent (f, indent, "    }\n"
+                                    "  break;\n");
        }
       fprintf_indent (f, indent, "default:;\n");
 
@@ -2940,6 +3156,8 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple,
       expr *e = as_a <expr *> (preds[i]->op);
       predicate_id *p = as_a <predicate_id *> (e->operation);
       preds[i]->get_name (kid_opname);
+      fprintf_indent (f, indent, "{\n");
+      indent += 2;
       fprintf_indent (f, indent, "tree %s_pops[%d];\n", kid_opname, p->nargs);
       fprintf_indent (f, indent, "if (%s_%s (%s, %s_pops%s))\n",
               gimple ? "gimple" : "tree",
@@ -2953,18 +3171,20 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple,
          fprintf_indent (f, indent + 4, "tree %s = %s_pops[%d];\n",
                          child_opname, kid_opname, j);
        }
-      preds[i]->gen_kids (f, indent + 4, gimple);
+      preds[i]->gen_kids (f, indent + 4, gimple, depth);
       fprintf (f, "}\n");
+      indent -= 2;
+      fprintf_indent (f, indent, "}\n");
     }
 
   for (unsigned i = 0; i < others.length (); ++i)
-    others[i]->gen (f, indent, gimple);
+    others[i]->gen (f, indent, gimple, depth);
 }
 
 /* Generate matching code for the decision tree operand.  */
 
 void
-dt_operand::gen (FILE *f, int indent, bool gimple)
+dt_operand::gen (FILE *f, int indent, bool gimple, int depth)
 {
   char opname[20];
   get_name (opname);
@@ -2980,7 +3200,7 @@ dt_operand::gen (FILE *f, int indent, bool gimple)
 
        case operand::OP_EXPR:
          if (gimple)
-           n_braces = gen_gimple_expr (f, indent);
+           n_braces = gen_gimple_expr (f, indent, depth);
          else
            n_braces = gen_generic_expr (f, indent, opname);
          break;
@@ -2991,12 +3211,12 @@ dt_operand::gen (FILE *f, int indent, bool gimple)
   else if (type == DT_TRUE)
     ;
   else if (type == DT_MATCH)
-    n_braces = gen_match_op (f, indent, opname);
+    n_braces = gen_match_op (f, indent, opname, gimple);
   else
     gcc_unreachable ();
 
   indent += 4 * n_braces;
-  gen_kids (f, indent, gimple);
+  gen_kids (f, indent, gimple, depth);
 
   for (unsigned i = 0; i < n_braces; ++i)
     {
@@ -3064,7 +3284,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
            if (cinfo.force_no_side_effects & (1 << i))
              {
                fprintf_indent (f, indent,
-                               "if (TREE_SIDE_EFFECTS (op%d)) return NULL_TREE;\n",
+                               "if (TREE_SIDE_EFFECTS (_p%d)) return NULL_TREE;\n",
                                i);
                if (verbose >= 1)
                  warning_at (as_a <expr *> (s->match)->ops[i]->location,
@@ -3122,11 +3342,19 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
        }
     }
 
-  fprintf_indent (f, indent, "if (dump_file && (dump_flags & TDF_DETAILS)) "
-          "fprintf (dump_file, \"Applying pattern ");
+  if (s->kind == simplify::SIMPLIFY)
+    fprintf_indent (f, indent, "if (__builtin_expect (!dbg_cnt (match), 0)) return %s;\n",
+                   gimple ? "false" : "NULL_TREE");
+
+  fprintf_indent (f, indent, "if (__builtin_expect (dump_file && (dump_flags & TDF_FOLDING), 0)) "
+          "fprintf (dump_file, \"%s ",
+          s->kind == simplify::SIMPLIFY
+          ? "Applying pattern" : "Matching expression");
+  fprintf (f, "%%s:%%d, %%s:%%d\\n\", ");
   output_line_directive (f,
-                        result ? result->location : s->match->location, true);
-  fprintf (f, ", %%s:%%d\\n\", __FILE__, __LINE__);\n");
+                        result ? result->location : s->match->location, true,
+                        true);
+  fprintf (f, ", __FILE__, __LINE__);\n");
 
   if (!result)
     {
@@ -3153,17 +3381,22 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
          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, sizeof (dest), "res_ops[%d]", j);
+             else
+               snprintf (dest, sizeof (dest), "res_op->ops[%d]", j);
              const char *optype
-               = get_operand_type (opr,
+               = 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.  */
@@ -3179,30 +3412,28 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
             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 ());
+                           "res_op->resimplify (lseq, valueize);\n");
        }
       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");
            }
@@ -3244,14 +3475,14 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
            {
              char dest[32];
              if (is_predicate)
-               snprintf (dest, 32, "res_ops[%d]", j);
+               snprintf (dest, sizeof (dest), "res_ops[%d]", j);
              else
                {
                  fprintf_indent (f, indent, "tree res_op%d;\n", j);
-                 snprintf (dest, 32, "res_op%d", j);
+                 snprintf (dest, sizeof (dest), "res_op%d", j);
                }
              const char *optype
-               = get_operand_type (opr,
+               = get_operand_type (opr, j,
                                    "type", e->expr_type,
                                    j == 0
                                    ? NULL : "TREE_TYPE (res_op0)");
@@ -3262,24 +3493,24 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
            fprintf_indent (f, indent, "return true;\n");
          else
            {
-             fprintf_indent (f, indent, "tree res;\n");
+             fprintf_indent (f, indent, "tree _r;\n");
              /* Re-fold the toplevel result.  Use non_lvalue to
-                build NON_LVALUE_EXPRs so they get properly
+                build NON_LVALUE_EXPRs so they get properly
                 ignored when in GIMPLE form.  */
              if (*opr == NON_LVALUE_EXPR)
                fprintf_indent (f, indent,
-                               "res = non_lvalue_loc (loc, res_op0);\n");
+                               "_r = non_lvalue_loc (loc, res_op0);\n");
              else
                {
                  if (is_a <operator_id *> (opr))
                    fprintf_indent (f, indent,
-                                   "res = fold_build%d_loc (loc, %s, type",
+                                   "_r = fold_build%d_loc (loc, %s, type",
                                    e->ops.length (),
                                    *e->operation == CONVERT_EXPR
                                    ? "NOP_EXPR" : e->operation->id);
                  else
                    fprintf_indent (f, indent,
-                                   "res = maybe_build_call_expr_loc (loc, "
+                                   "_r = maybe_build_call_expr_loc (loc, "
                                    "%s, type, %d", e->operation->id,
                                    e->ops.length());
                  for (unsigned j = 0; j < e->ops.length (); ++j)
@@ -3287,7 +3518,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
                  fprintf (f, ");\n");
                  if (!is_a <operator_id *> (opr))
                    {
-                     fprintf_indent (f, indent, "if (!res)\n");
+                     fprintf_indent (f, indent, "if (!_r)\n");
                      fprintf_indent (f, indent, "  return NULL_TREE;\n");
                    }
                }
@@ -3297,8 +3528,8 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
               || result->type == operand::OP_C_EXPR)
 
        {
-         fprintf_indent (f, indent, "tree res;\n");
-         result->gen_transform (f, indent, "res", false, 1, "type",
+         fprintf_indent (f, indent, "tree _r;\n");
+         result->gen_transform (f, indent, "_r", false, 1, "type",
                                    &cinfo, indexes);
        }
       else
@@ -3319,12 +3550,12 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
                                  "if (TREE_SIDE_EFFECTS (captures[%d]))\n",
                                  i);
                  fprintf_indent (f, indent + 2,
-                                 "res = build2_loc (loc, COMPOUND_EXPR, type, "
-                                 "fold_ignored_result (captures[%d]), res);\n",
+                                 "_r = build2_loc (loc, COMPOUND_EXPR, type, "
+                                 "fold_ignored_result (captures[%d]), _r);\n",
                                  i);
                }
            }
-         fprintf_indent (f, indent, "return res;\n");
+         fprintf_indent (f, indent, "return _r;\n");
        }
     }
 }
@@ -3334,7 +3565,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
    that is not part of the decision tree (simplify->match).  */
 
 void
-dt_simplify::gen (FILE *f, int indent, bool gimple)
+dt_simplify::gen (FILE *f, int indent, bool gimple, int depth ATTRIBUTE_UNUSED)
 {
   fprintf_indent (f, indent, "{\n");
   indent += 2;
@@ -3360,7 +3591,7 @@ dt_simplify::gen (FILE *f, int indent, bool gimple)
     {
       if (gimple)
        {
-         fprintf_indent (f, indent, "if (%s (res_code, res_ops, seq, "
+         fprintf_indent (f, indent, "if (%s (res_op, seq, "
                          "valueize, type, captures", info->fname);
          for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
            if (s->for_subst_vec[i].first->used)
@@ -3373,7 +3604,7 @@ dt_simplify::gen (FILE *f, int indent, bool gimple)
          fprintf_indent (f, indent, "tree res = %s (loc, type",
                          info->fname);
          for (unsigned i = 0; i < as_a <expr *> (s->match)->ops.length (); ++i)
-           fprintf (f, ", op%d", i);
+           fprintf (f, ", _p%d", i);
          fprintf (f, ", captures");
          for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
            {
@@ -3391,11 +3622,11 @@ dt_simplify::gen (FILE *f, int indent, bool gimple)
          if (! s->for_subst_vec[i].first->used)
            continue;
          if (is_a <operator_id *> (s->for_subst_vec[i].second))
-           fprintf_indent (f, indent, "enum tree_code %s = %s;\n",
+           fprintf_indent (f, indent, "const enum tree_code %s = %s;\n",
                            s->for_subst_vec[i].first->id,
                            s->for_subst_vec[i].second->id);
          else if (is_a <fn_id *> (s->for_subst_vec[i].second))
-           fprintf_indent (f, indent, "combined_fn %s = %s;\n",
+           fprintf_indent (f, indent, "const combined_fn %s = %s;\n",
                            s->for_subst_vec[i].first->id,
                            s->for_subst_vec[i].second->id);
          else
@@ -3528,20 +3759,19 @@ 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"
-                "                 tree ARG_UNUSED (type), tree *ARG_UNUSED "
+                "%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);
       else
        {
          fprintf (f, "\nstatic tree\n"
-                  "%s (location_t ARG_UNUSED (loc), tree ARG_UNUSED (type),\n",
+                  "%s (location_t ARG_UNUSED (loc), const tree ARG_UNUSED (type),\n",
                   (*iter).second->fname);
          for (unsigned i = 0;
               i < as_a <expr *>(s->s->s->match)->ops.length (); ++i)
-           fprintf (f, " tree ARG_UNUSED (op%d),", i);
+           fprintf (f, " tree ARG_UNUSED (_p%d),", i);
          fprintf (f, " tree *captures\n");
        }
       for (unsigned i = 0; i < s->s->s->for_subst_vec.length (); ++i)
@@ -3549,10 +3779,10 @@ decision_tree::gen (FILE *f, bool gimple)
          if (! s->s->s->for_subst_vec[i].first->used)
            continue;
          if (is_a <operator_id *> (s->s->s->for_subst_vec[i].second))
-           fprintf (f, ", enum tree_code ARG_UNUSED (%s)",
+           fprintf (f, ", const enum tree_code ARG_UNUSED (%s)",
                     s->s->s->for_subst_vec[i].first->id);
          else if (is_a <fn_id *> (s->s->s->for_subst_vec[i].second))
-           fprintf (f, ", combined_fn ARG_UNUSED (%s)",
+           fprintf (f, ", const combined_fn ARG_UNUSED (%s)",
                     s->s->s->for_subst_vec[i].first->id);
        }
 
@@ -3566,12 +3796,12 @@ decision_tree::gen (FILE *f, bool gimple)
     }
   fprintf (stderr, "removed %u duplicate tails\n", rcnt);
 
-  for (unsigned n = 1; n <= 3; ++n)
+  for (unsigned n = 1; n <= 5; ++n)
     {
       /* First generate split-out functions.  */
-      for (unsigned i = 0; i < root->kids.length (); i++)
+      for (unsigned j = 0; j < root->kids.length (); j++)
        {
-         dt_operand *dop = static_cast<dt_operand *>(root->kids[i]);
+         dt_operand *dop = static_cast<dt_operand *>(root->kids[j]);
          expr *e = static_cast<expr *>(dop->op);
          if (e->ops.length () != n
              /* Builtin simplifications are somewhat premature on
@@ -3584,8 +3814,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",
@@ -3593,13 +3824,13 @@ decision_tree::gen (FILE *f, bool gimple)
          else
            fprintf (f, "\nstatic tree\n"
                     "generic_simplify_%s (location_t ARG_UNUSED (loc), enum "
-                    "tree_code ARG_UNUSED (code), tree ARG_UNUSED (type)",
+                    "tree_code ARG_UNUSED (code), const tree ARG_UNUSED (type)",
                     e->operation->id);
          for (unsigned i = 0; i < n; ++i)
-           fprintf (f, ", tree op%d", i);
+           fprintf (f, ", tree _p%d", i);
          fprintf (f, ")\n");
          fprintf (f, "{\n");
-         dop->gen_kids (f, 2, gimple);
+         dop->gen_kids (f, 2, gimple, 0);
          if (gimple)
            fprintf (f, "  return false;\n");
          else
@@ -3611,15 +3842,15 @@ 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"
-                "                 code_helper code, tree type");
+                "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"
                 "generic_simplify (location_t loc, enum tree_code code, "
-                "tree type ATTRIBUTE_UNUSED");
+                "const tree type ATTRIBUTE_UNUSED");
       for (unsigned i = 0; i < n; ++i)
-       fprintf (f, ", tree op%d", i);
+       fprintf (f, ", tree _p%d", i);
       fprintf (f, ")\n");
       fprintf (f, "{\n");
 
@@ -3650,13 +3881,13 @@ 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",
                     e->operation->id);
-         for (unsigned i = 0; i < n; ++i)
-           fprintf (f, ", op%d", i);
+         for (unsigned j = 0; j < n; ++j)
+           fprintf (f, ", _p%d", j);
          fprintf (f, ");\n");
        }
       fprintf (f,       "    default:;\n"
@@ -3681,11 +3912,11 @@ write_predicate (FILE *f, predicate_id *p, decision_tree &dt, bool gimple)
           p->nargs > 0 ? ", tree *res_ops" : "",
           gimple ? ", tree (*valueize)(tree) ATTRIBUTE_UNUSED" : "");
   /* Conveniently make 'type' available.  */
-  fprintf_indent (f, 2, "tree type = TREE_TYPE (t);\n");
+  fprintf_indent (f, 2, "const tree type = TREE_TYPE (t);\n");
 
   if (!gimple)
     fprintf_indent (f, 2, "if (TREE_SIDE_EFFECTS (t)) return false;\n");
-  dt.root->gen_kids (f, 2, gimple);
+  dt.root->gen_kids (f, 2, gimple, 0);
 
   fprintf_indent (f, 2, "return false;\n"
           "}\n");
@@ -3723,13 +3954,15 @@ private:
   const cpp_token *eat_ident (const char *);
   const char *get_number ();
 
-  id_base *parse_operation ();
+  unsigned get_internal_capture_id ();
+
+  id_base *parse_operation (unsigned char &);
   operand *parse_capture (operand *, bool);
   operand *parse_expr ();
   c_expr *parse_c_expr (cpp_ttype);
   operand *parse_op ();
 
-  void record_operlist (source_location, user_id *);
+  void record_operlist (location_t, user_id *);
 
   void parse_pattern ();
   operand *parse_result (operand *, predicate_id *);
@@ -3737,10 +3970,12 @@ private:
                      vec<simplify *>&, operand *, operand *);
   void parse_simplify (simplify::simplify_kind,
                       vec<simplify *>&, predicate_id *, operand *);
-  void parse_for (source_location);
-  void parse_if (source_location);
-  void parse_predicates (source_location);
-  void parse_operator_list (source_location);
+  void parse_for (location_t);
+  void parse_if (location_t);
+  void parse_predicates (location_t);
+  void parse_operator_list (location_t);
+
+  void finish_match_operand (operand *);
 
   cpp_reader *r;
   vec<c_expr *> active_ifs;
@@ -3749,6 +3984,7 @@ private:
   vec<user_id *> oper_lists;
 
   cid_map_t *capture_ids;
+  unsigned last_id;
 
 public:
   vec<simplify *> simplifiers;
@@ -3768,8 +4004,7 @@ parser::next ()
     {
       token = cpp_get_token (r);
     }
-  while (token->type == CPP_PADDING
-        && token->type != CPP_EOF);
+  while (token->type == CPP_PADDING);
   return token;
 }
 
@@ -3784,8 +4019,7 @@ parser::peek (unsigned num)
     {
       token = cpp_peek_token (r, i++);
     }
-  while ((token->type == CPP_PADDING
-         && token->type != CPP_EOF)
+  while (token->type == CPP_PADDING
         || (--num > 0));
   /* If we peek at EOF this is a fatal error as it leaves the
      cpp_reader in unusable state.  Assume we really wanted a
@@ -3878,11 +4112,26 @@ parser::get_number ()
   return (const char *)token->val.str.text;
 }
 
+/* Return a capture ID that can be used internally.  */
+
+unsigned
+parser::get_internal_capture_id ()
+{
+  unsigned newid = capture_ids->elements ();
+  /* Big enough for a 32-bit UINT_MAX plus prefix.  */
+  char id[13];
+  bool existed;
+  snprintf (id, sizeof (id), "__%u", newid);
+  capture_ids->get_or_insert (xstrdup (id), &existed);
+  if (existed)
+    fatal ("reserved capture id '%s' already used", id);
+  return newid;
+}
 
 /* Record an operator-list use for transparent for handling.  */
 
 void
-parser::record_operlist (source_location loc, user_id *p)
+parser::record_operlist (location_t loc, user_id *p)
 {
   if (!oper_lists_set->add (p))
     {
@@ -3898,54 +4147,43 @@ parser::record_operlist (source_location loc, user_id *p)
    convert2?  */
 
 id_base *
-parser::parse_operation ()
+parser::parse_operation (unsigned char &opt_grp)
 {
   const cpp_token *id_tok = peek ();
+  char *alt_id = NULL;
   const char *id = get_ident ();
   const cpp_token *token = peek ();
-  if (strcmp (id, "convert0") == 0)
-    fatal_at (id_tok, "use 'convert?' here");
-  else if (strcmp (id, "view_convert0") == 0)
-    fatal_at (id_tok, "use 'view_convert?' here");
+  opt_grp = 0;
   if (token->type == CPP_QUERY
       && !(token->flags & PREV_WHITE))
     {
-      if (strcmp (id, "convert") == 0)
-       id = "convert0";
-      else if (strcmp (id, "convert1") == 0)
-       ;
-      else if (strcmp (id, "convert2") == 0)
-       ;
-      else if (strcmp (id, "view_convert") == 0)
-       id = "view_convert0";
-      else if (strcmp (id, "view_convert1") == 0)
-       ;
-      else if (strcmp (id, "view_convert2") == 0)
-       ;
-      else
-       fatal_at (id_tok, "non-convert operator conditionalized");
-
       if (!parsing_match_operand)
        fatal_at (id_tok, "conditional convert can only be used in "
                  "match expression");
+      if (ISDIGIT (id[strlen (id) - 1]))
+       {
+         opt_grp = id[strlen (id) - 1] - '0' + 1;
+         alt_id = xstrdup (id);
+         alt_id[strlen (id) - 1] = '\0';
+         if (opt_grp == 1)
+           fatal_at (id_tok, "use '%s?' here", alt_id);
+       }
+      else
+       opt_grp = 1;
       eat_token (CPP_QUERY);
     }
-  else if (strcmp (id, "convert1") == 0
-          || strcmp (id, "convert2") == 0
-          || strcmp (id, "view_convert1") == 0
-          || strcmp (id, "view_convert2") == 0)
-    fatal_at (id_tok, "expected '?' after conditional operator");
-  id_base *op = get_operator (id);
+  id_base *op = get_operator (alt_id ? alt_id : id);
   if (!op)
-    fatal_at (id_tok, "unknown operator %s", id);
-
+    fatal_at (id_tok, "unknown operator %s", alt_id ? alt_id : id);
+  if (alt_id)
+    free (alt_id);
   user_id *p = dyn_cast<user_id *> (op);
   if (p && p->is_oper_list)
     {
       if (active_fors.length() == 0)
        record_operlist (id_tok->src_loc, p);
       else
-       fatal_at (id_tok, "operator-list %s cannot be exapnded inside 'for'", id);
+       fatal_at (id_tok, "operator-list %s cannot be expanded inside 'for'", id);
     }
   return op;
 }
@@ -3953,12 +4191,22 @@ parser::parse_operation ()
 /* Parse a capture.
      capture = '@'<number>  */
 
-struct operand *
+class operand *
 parser::parse_capture (operand *op, bool require_existing)
 {
-  source_location src_loc = eat_token (CPP_ATSIGN)->src_loc;
+  location_t src_loc = eat_token (CPP_ATSIGN)->src_loc;
   const cpp_token *token = peek ();
   const char *id = NULL;
+  bool value_match = false;
+  /* For matches parse @@ as a value-match denoting the prevailing operand.  */
+  if (token->type == CPP_ATSIGN
+      && ! (token->flags & PREV_WHITE)
+      && parsing_match_operand)
+    {
+      eat_token (CPP_ATSIGN);
+      token = peek ();
+      value_match = true;
+    }
   if (token->type == CPP_NUMBER)
     id = get_number ();
   else if (token->type == CPP_NAME)
@@ -3974,17 +4222,18 @@ parser::parse_capture (operand *op, bool require_existing)
        fatal_at (src_loc, "unknown capture id");
       num = next_id;
     }
-  return new capture (src_loc, num, op);
+  return new capture (src_loc, num, op, value_match);
 }
 
 /* Parse an expression
      expr = '(' <operation>[capture][flag][type] <operand>... ')'  */
 
-struct operand *
+class operand *
 parser::parse_expr ()
 {
   const cpp_token *token = peek ();
-  expr *e = new expr (parse_operation (), token->src_loc);
+  unsigned char opt_grp;
+  expr *e = new expr (parse_operation (opt_grp), token->src_loc);
   token = peek ();
   operand *op;
   bool is_commutative = false;
@@ -4009,11 +4258,11 @@ parser::parse_expr ()
                {
                  if (*sp == 'c')
                    {
-                     if (operator_id *p
+                     if (operator_id *o
                            = dyn_cast<operator_id *> (e->operation))
                        {
-                         if (!commutative_tree_code (p->code)
-                             && !comparison_code_p (p->code))
+                         if (!commutative_tree_code (o->code)
+                             && !comparison_code_p (o->code))
                            fatal_at (token, "operation is not commutative");
                        }
                      else if (user_id *p = dyn_cast<user_id *> (e->operation))
@@ -4054,20 +4303,14 @@ parser::parse_expr ()
     op = parse_capture (e, false);
   else if (force_capture)
     {
-      unsigned num = capture_ids->elements ();
-      char id[8];
-      bool existed;
-      sprintf (id, "__%u", num);
-      capture_ids->get_or_insert (xstrdup (id), &existed);
-      if (existed)
-       fatal_at (token, "reserved capture id '%s' already used", id);
-      op = new capture (token->src_loc, num, e);
+      unsigned num = get_internal_capture_id ();
+      op = new capture (token->src_loc, num, e, false);
     }
   else
     op = e;
   do
     {
-      const cpp_token *token = peek ();
+      token = peek ();
       if (token->type == CPP_CLOSE_PAREN)
        {
          if (e->operation->nargs != -1
@@ -4076,13 +4319,22 @@ parser::parse_expr ()
                      e->operation->id, e->operation->nargs, e->ops.length ());
          if (is_commutative)
            {
-             if (e->ops.length () == 2)
+             if (e->ops.length () == 2
+                 || commutative_op (e->operation) >= 0)
                e->is_commutative = true;
              else
-               fatal_at (token, "only binary operators or function with "
-                         "two arguments can be marked commutative");
+               fatal_at (token, "only binary operators or functions with "
+                         "two arguments can be marked commutative, "
+                         "unless the operation is known to be inherently "
+                         "commutative");
            }
          e->expr_type = expr_type;
+         if (opt_grp != 0)
+           {
+             if (e->ops.length () != 1)
+               fatal_at (token, "only unary operations can be conditional");
+             e->opt_grp = opt_grp;
+           }
          return op;
        }
       else if (!(token->flags & PREV_WHITE))
@@ -4105,7 +4357,7 @@ parser::parse_c_expr (cpp_ttype start)
   unsigned opencnt;
   vec<cpp_token> code = vNULL;
   unsigned nr_stmts = 0;
-  source_location loc = eat_token (start)->src_loc;
+  location_t loc = eat_token (start)->src_loc;
   if (start == CPP_OPEN_PAREN)
     end = CPP_CLOSE_PAREN;
   else if (start == CPP_OPEN_BRACE)
@@ -4123,6 +4375,8 @@ parser::parse_c_expr (cpp_ttype start)
       else if (token->type == end
               && --opencnt == 0)
        break;
+      else if (token->type == CPP_EOF)
+       fatal_at (token, "unexpected end of file");
 
       /* This is a lame way of counting the number of statements.  */
       if (token->type == CPP_SEMICOLON)
@@ -4149,11 +4403,11 @@ parser::parse_c_expr (cpp_ttype start)
    a standalone capture.
      op = predicate | expr | c_expr | capture  */
 
-struct operand *
+class operand *
 parser::parse_op ()
 {
   const cpp_token *token = peek ();
-  struct operand *op = NULL;
+  class operand *op = NULL;
   if (token->type == CPP_OPEN_PAREN)
     {
       eat_token (CPP_OPEN_PAREN);
@@ -4173,17 +4427,17 @@ parser::parse_op ()
          id_base *opr = get_operator (id);
          if (!opr)
            fatal_at (token, "expected predicate name");
-         if (operator_id *code = dyn_cast <operator_id *> (opr))
+         if (operator_id *code1 = dyn_cast <operator_id *> (opr))
            {
-             if (code->nargs != 0)
+             if (code1->nargs != 0)
                fatal_at (token, "using an operator with operands as predicate");
              /* Parse the zero-operand operator "predicates" as
                 expression.  */
              op = new expr (opr, token->src_loc);
            }
-         else if (user_id *code = dyn_cast <user_id *> (opr))
+         else if (user_id *code2 = dyn_cast <user_id *> (opr))
            {
-             if (code->nargs != 0)
+             if (code2->nargs != 0)
                fatal_at (token, "using an operator with operands as predicate");
              /* Parse the zero-operand operator "predicates" as
                 expression.  */
@@ -4225,7 +4479,7 @@ parser::push_simplify (simplify::simplify_kind kind,
     active_fors.safe_push (oper_lists);
 
   simplifiers.safe_push
-    (new simplify (kind, match, result,
+    (new simplify (kind, last_id++, match, result,
                   active_fors.copy (), capture_ids));
 
   if (!oper_lists.is_empty ())
@@ -4292,7 +4546,7 @@ parser::parse_result (operand *result, predicate_id *matcher)
   else if (peek_ident ("switch"))
     {
       token = eat_ident ("switch");
-      source_location ifloc = eat_token (CPP_OPEN_PAREN)->src_loc;
+      location_t ifloc = eat_token (CPP_OPEN_PAREN)->src_loc;
       eat_ident ("if");
       if_expr *ife = new if_expr (ifloc);
       operand *res = ife;
@@ -4372,7 +4626,8 @@ parser::parse_simplify (simplify::simplify_kind kind,
 
   const cpp_token *loc = peek ();
   parsing_match_operand = true;
-  struct operand *match = parse_op ();
+  class operand *match = parse_op ();
+  finish_match_operand (match);
   parsing_match_operand = false;
   if (match->type == operand::OP_CAPTURE && !matcher)
     fatal_at (loc, "outermost expression cannot be captured");
@@ -4430,7 +4685,7 @@ parser::parse_simplify (simplify::simplify_kind kind,
      subst = <ident> '(' <ident>... ')'  */
 
 void
-parser::parse_for (source_location)
+parser::parse_for (location_t)
 {
   auto_vec<const cpp_token *> user_id_tokens;
   vec<user_id *> user_ids = vNULL;
@@ -4462,10 +4717,6 @@ parser::parse_for (source_location)
          id_base *idb = get_operator (oper, true);
          if (idb == NULL)
            fatal_at (token, "no such operator '%s'", oper);
-         if (*idb == CONVERT0 || *idb == CONVERT1 || *idb == CONVERT2
-             || *idb == VIEW_CONVERT0 || *idb == VIEW_CONVERT1
-             || *idb == VIEW_CONVERT2)
-           fatal_at (token, "conditional operators cannot be used inside for");
 
          if (arity == -1)
            arity = idb->nargs;
@@ -4544,7 +4795,7 @@ parser::parse_for (source_location)
      oprs = '(' 'define_operator_list' <ident> <ident>... ')'  */
 
 void
-parser::parse_operator_list (source_location)
+parser::parse_operator_list (location_t)
 {
   const cpp_token *token = peek (); 
   const char *id = get_ident ();
@@ -4596,7 +4847,7 @@ parser::parse_operator_list (source_location)
      if = '(' 'if' '(' <c-expr> ')' <pattern> ')'  */
 
 void
-parser::parse_if (source_location)
+parser::parse_if (location_t)
 {
   c_expr *ifexpr = parse_c_expr (CPP_OPEN_PAREN);
 
@@ -4607,7 +4858,7 @@ parser::parse_if (source_location)
   active_ifs.safe_push (ifexpr);
   while (1)
     {
-      const cpp_token *token = peek ();
+      token = peek ();
       if (token->type == CPP_CLOSE_PAREN)
        break;
 
@@ -4620,7 +4871,7 @@ parser::parse_if (source_location)
      preds = '(' 'define_predicates' <ident>... ')'  */
 
 void
-parser::parse_predicates (source_location)
+parser::parse_predicates (location_t)
 {
   do
     {
@@ -4651,21 +4902,21 @@ parser::parse_pattern ()
   else if (strcmp (id, "match") == 0)
     {
       bool with_args = false;
-      source_location e_loc = peek ()->src_loc;
+      location_t e_loc = peek ()->src_loc;
       if (peek ()->type == CPP_OPEN_PAREN)
        {
          eat_token (CPP_OPEN_PAREN);
          with_args = true;
        }
       const char *name = get_ident ();
-      id_base *id = get_operator (name);
+      id_base *id1 = get_operator (name);
       predicate_id *p;
-      if (!id)
+      if (!id1)
        {
          p = add_predicate (name);
          user_predicates.safe_push (p);
        }
-      else if ((p = dyn_cast <predicate_id *> (id)))
+      else if ((p = dyn_cast <predicate_id *> (id1)))
        ;
       else
        fatal_at (token, "cannot add a match to a non-predicate ID");
@@ -4713,6 +4964,69 @@ parser::parse_pattern ()
   eat_token (CPP_CLOSE_PAREN);
 }
 
+/* Helper for finish_match_operand, collecting captures of OP in CPTS
+   recursively.  */
+
+static void
+walk_captures (operand *op, vec<vec<capture *> > cpts)
+{
+  if (! op)
+    return;
+
+  if (capture *c = dyn_cast <capture *> (op))
+    {
+      cpts[c->where].safe_push (c);
+      walk_captures (c->what, cpts);
+    }
+  else if (expr *e = dyn_cast <expr *> (op))
+    for (unsigned i = 0; i < e->ops.length (); ++i)
+      walk_captures (e->ops[i], cpts);
+}
+
+/* Finish up OP which is a match operand.  */
+
+void
+parser::finish_match_operand (operand *op)
+{
+  /* Look for matching captures, diagnose mis-uses of @@ and apply
+     early lowering and distribution of value_match.  */
+  auto_vec<vec<capture *> > cpts;
+  cpts.safe_grow_cleared (capture_ids->elements ());
+  walk_captures (op, cpts);
+  for (unsigned i = 0; i < cpts.length (); ++i)
+    {
+      capture *value_match = NULL;
+      for (unsigned j = 0; j < cpts[i].length (); ++j)
+       {
+         if (cpts[i][j]->value_match)
+           {
+             if (value_match)
+               fatal_at (cpts[i][j]->location, "duplicate @@");
+             value_match = cpts[i][j];
+           }
+       }
+      if (cpts[i].length () == 1 && value_match)
+       fatal_at (value_match->location, "@@ without a matching capture");
+      if (value_match)
+       {
+         /* Duplicate prevailing capture with the existing ID, create
+            a fake ID and rewrite all captures to use it.  This turns
+            @@1 into @__<newid>@1 and @1 into @__<newid>.  */
+         value_match->what = new capture (value_match->location,
+                                          value_match->where,
+                                          value_match->what, false);
+         /* Create a fake ID and rewrite all captures to use it.  */
+         unsigned newid = get_internal_capture_id ();
+         for (unsigned j = 0; j < cpts[i].length (); ++j)
+           {
+             cpts[i][j]->where = newid;
+             cpts[i][j]->value_match = true;
+           }
+       }
+      cpts[i].release ();
+    }
+}
+
 /* Main entry of the parser.  Repeatedly parse outer control structures.  */
 
 parser::parser (cpp_reader *r_)
@@ -4726,6 +5040,7 @@ parser::parser (cpp_reader *r_)
   capture_ids = NULL;
   user_predicates = vNULL;
   parsing_match_operand = false;
+  last_id = 0;
 
   const cpp_token *token = next ();
   while (token->type != CPP_EOF)
@@ -4779,14 +5094,14 @@ main (int argc, char **argv)
        }
     }
 
-  line_table = XCNEW (struct line_maps);
+  line_table = XCNEW (class line_maps);
   linemap_init (line_table, 0);
   line_table->reallocator = xrealloc;
   line_table->round_alloc_size = round_alloc_size;
 
   r = cpp_create_reader (CLK_GNUC99, NULL, line_table);
   cpp_callbacks *cb = cpp_get_callbacks (r);
-  cb->error = error_cb;
+  cb->diagnostic = diagnostic_cb;
 
   /* Add the build directory to the #include "" search path.  */
   cpp_dir *dir = XCNEW (cpp_dir);
@@ -4808,12 +5123,6 @@ main (int argc, char **argv)
   add_operator (SYM, # SYM, # TYPE, NARGS);
 #define END_OF_BASE_TREE_CODES
 #include "tree.def"
-add_operator (CONVERT0, "convert0", "tcc_unary", 1);
-add_operator (CONVERT1, "convert1", "tcc_unary", 1);
-add_operator (CONVERT2, "convert2", "tcc_unary", 1);
-add_operator (VIEW_CONVERT0, "view_convert0", "tcc_unary", 1);
-add_operator (VIEW_CONVERT1, "view_convert1", "tcc_unary", 1);
-add_operator (VIEW_CONVERT2, "view_convert2", "tcc_unary", 1);
 #undef END_OF_BASE_TREE_CODES
 #undef DEFTREECODE
 
@@ -4844,12 +5153,12 @@ add_operator (VIEW_CONVERT2, "view_convert2", "tcc_unary", 1);
       lower (pred->matchers, gimple);
 
       if (verbose == 2)
-       for (unsigned i = 0; i < pred->matchers.length (); ++i)
-         print_matches (pred->matchers[i]);
+       for (unsigned j = 0; j < pred->matchers.length (); ++j)
+         print_matches (pred->matchers[j]);
 
       decision_tree dt;
-      for (unsigned i = 0; i < pred->matchers.length (); ++i)
-       dt.insert (pred->matchers[i], i);
+      for (unsigned j = 0; j < pred->matchers.length (); ++j)
+       dt.insert (pred->matchers[j], j);
 
       if (verbose == 2)
        dt.print (stderr);