Index: gcc/genmatch.c
===================================================================
--- gcc/genmatch.c	(revision 215499)
+++ gcc/genmatch.c	(working copy)
@@ -193,8 +193,9 @@ struct simplify;
 struct predicate_id : public id_base
 {
   predicate_id (const char *id_)
-    : id_base (id_base::PREDICATE, id_), matchers (vNULL) {}
+    : id_base (id_base::PREDICATE, id_), matchers (vNULL), nargs(-1) {}
   vec<simplify *> matchers;
+  int nargs;
 };
 
 template<>
@@ -433,14 +434,12 @@ struct if_or_with {
 };
 
 struct simplify {
-  simplify (const char *name_,
-	    operand *match_, source_location match_location_,
+  simplify (operand *match_, source_location match_location_,
 	    struct operand *result_, source_location result_location_, vec<if_or_with> ifexpr_vec_ = vNULL)
-      : name (name_), match (match_), match_location (match_location_),
+      : match (match_), match_location (match_location_),
       result (result_), result_location (result_location_),
       ifexpr_vec (ifexpr_vec_) {}
 
-  const char *name;
   operand *match; 
   source_location match_location;
   struct operand *result;
@@ -682,7 +681,7 @@ lower_commutative (simplify *s, vec<simp
   vec<operand *> matchers = commutate (s->match);
   for (unsigned i = 0; i < matchers.length (); ++i)
     {
-      simplify *ns = new simplify (s->name, matchers[i], s->match_location,
+      simplify *ns = new simplify (matchers[i], s->match_location,
 				   s->result, s->result_location, s->ifexpr_vec);
       simplifiers.safe_push (ns);
     }
@@ -810,7 +809,7 @@ lower_opt_convert (simplify *s, vec<simp
   vec<operand *> matchers = lower_opt_convert (s->match);
   for (unsigned i = 0; i < matchers.length (); ++i)
     {
-      simplify *ns = new simplify (s->name, matchers[i], s->match_location,
+      simplify *ns = new simplify (matchers[i], s->match_location,
 				   s->result, s->result_location, s->ifexpr_vec);
       simplifiers.safe_push (ns);
     }
@@ -1512,10 +1511,11 @@ dt_operand::gen_generic_expr (FILE *f, c
 void
 dt_node::gen_gimple_kids (FILE *f)
 {
-  vec<dt_operand *> gimple_exprs = vNULL;
-  vec<dt_operand *> generic_exprs = vNULL;
-  vec<dt_operand *> fns = vNULL;
-  vec<dt_node *> others = vNULL;
+  auto_vec<dt_operand *> gimple_exprs;
+  auto_vec<dt_operand *> generic_exprs;
+  auto_vec<dt_operand *> fns;
+  auto_vec<dt_operand *> preds;
+  auto_vec<dt_node *> others;
   dt_node *true_operand = NULL;
   for (unsigned i = 0; i < kids.length (); ++i)
     {
@@ -1527,6 +1527,8 @@ dt_node::gen_gimple_kids (FILE *f)
 		generic_exprs.safe_push (op);
 	      else if (e->operation->op->kind == id_base::FN)
 		fns.safe_push (op);
+	      else if (e->operation->op->kind == id_base::PREDICATE)
+		preds.safe_push (op);
 	      else
 		gimple_exprs.safe_push (op);
 	    }
@@ -1638,6 +1640,25 @@ dt_node::gen_gimple_kids (FILE *f)
     fprintf (f, "default:;\n"
 	     "}\n");
 
+  for (unsigned i = 0; i < preds.length (); ++i)
+    {
+      expr *e = as_a <expr *> (preds[i]->op);
+      predicate_id *p = as_a <predicate_id *> (e->operation->op);
+      preds[i]->get_name (kid_opname);
+      fprintf (f, "tree %s_pops[%d];\n", kid_opname, p->nargs);
+      fprintf (f, "if (gimple_%s (%s, %s_pops, valueize))\n", p->id,
+	       kid_opname, kid_opname);
+      fprintf (f, "{\n");
+      for (int j = 0; j < p->nargs; ++j)
+	{
+	  char child_opname[20];
+	  preds[i]->gen_opname (child_opname, j);
+	  fprintf (f, "tree %s = %s_pops[%d];\n", child_opname, kid_opname, j);
+	}
+      preds[i]->gen_gimple_kids (f);
+      fprintf (f, "}\n");
+    }
+
   for (unsigned i = 0; i < others.length (); ++i)
     others[i]->gen_gimple (f);
 
@@ -1721,6 +1742,10 @@ dt_operand::gen_generic (FILE *f)
 void
 dt_node::gen_generic_kids (FILE *f)
 {
+  auto_vec<dt_operand *> generic_exprs;
+  auto_vec<dt_operand *> fns;
+  auto_vec<dt_operand *> preds;
+
   bool any = false;
   for (unsigned j = 0; j < kids.length (); ++j)
     {
@@ -1729,7 +1754,23 @@ dt_node::gen_generic_kids (FILE *f)
 	{
 	  dt_operand *kid = static_cast<dt_operand *>(node);
 	  if (kid->op->type == operand::OP_EXPR)
-	    any = true;
+	    {
+	      expr *e = as_a <expr *> (kid->op);
+	      if (e->operation->op->kind == id_base::CODE)
+		{
+		  generic_exprs.safe_push (kid);
+		  any = true;
+		}
+	      else if (e->operation->op->kind == id_base::FN)
+		{
+		  fns.safe_push (kid);
+		  any = true;
+		}
+	      else if (e->operation->op->kind == id_base::PREDICATE)
+		preds.safe_push (kid);
+	      else
+		gcc_unreachable ();
+	    }
 	}
     }
 
@@ -1739,17 +1780,11 @@ dt_node::gen_generic_kids (FILE *f)
       static_cast <dt_operand *>(kids[0])->get_name (opname); 
       fprintf (f, "switch (TREE_CODE (%s))\n"
 	       "{\n", opname);
-      for (unsigned j = 0; j < kids.length (); ++j)
+      for (unsigned j = 0; j < generic_exprs.length (); ++j)
 	{
-	  dt_node *node = kids[j];
-	  if (node->type != DT_OPERAND)
-	    continue;
-	  dt_operand *kid = static_cast<dt_operand *>(node);
-	  if (kid->op->type != operand::OP_EXPR)
-	    continue;
-	  expr *e = static_cast <expr *>(kid->op);
-	  if (e->operation->op->kind != id_base::CODE)
-	    continue;
+	  dt_operand *kid = generic_exprs[j];
+	  expr *e = as_a <expr *>(kid->op);
+	  gcc_assert (e->operation->op->kind == id_base::CODE);
 
 	  /* ??? CONVERT */
 	  fprintf (f, "case %s:\n"
@@ -1760,17 +1795,11 @@ dt_node::gen_generic_kids (FILE *f)
 	}
 
       bool first = true;
-      for (unsigned j = 0; j < kids.length (); ++j)
+      for (unsigned j = 0; j < fns.length (); ++j)
 	{
-	  dt_node *node = kids[j];
-	  if (node->type != DT_OPERAND)
-	    continue;
-	  dt_operand *kid = static_cast<dt_operand *>(node);
-	  if (kid->op->type != operand::OP_EXPR)
-	    continue;
-	  expr *e = static_cast <expr *>(kid->op);
-	  if (e->operation->op->kind != id_base::FN)
-	    continue;
+	  dt_operand *kid = fns[j];
+	  expr *e = as_a <expr *>(kid->op);
+	  gcc_assert (e->operation->op->kind == id_base::FN);
 
 	  if (first)
 	    fprintf (f, "case CALL_EXPR:\n"
@@ -1797,6 +1826,26 @@ dt_node::gen_generic_kids (FILE *f)
 	       "}\n");
     }
 
+  for (unsigned i = 0; i < preds.length (); ++i)
+    {
+      expr *e = as_a <expr *> (preds[i]->op);
+      predicate_id *p = as_a <predicate_id *> (e->operation->op);
+      char kid_opname[128];
+      preds[i]->get_name (kid_opname);
+      fprintf (f, "tree %s_pops[%d];\n", kid_opname, p->nargs);
+      fprintf (f, "if (tree_%s (%s, %s_pops))\n", p->id,
+	       kid_opname, kid_opname);
+      fprintf (f, "{\n");
+      for (int j = 0; j < p->nargs; ++j)
+	{
+	  char child_opname[20];
+	  preds[i]->gen_opname (child_opname, j);
+	  fprintf (f, "tree %s = %s_pops[%d];\n", child_opname, kid_opname, j);
+	}
+      preds[i]->gen_generic_kids (f);
+      fprintf (f, "}\n");
+    }
+
   for (unsigned j = 0; j < kids.length (); ++j)
     {
       dt_node *node = kids[j];
@@ -1887,23 +1936,27 @@ dt_simplify::gen (FILE *f, bool gimple)
     {
       if (s->result->type == operand::OP_EXPR)
 	{
-	  expr *e = static_cast <expr *> (s->result);
-	  fprintf (f, "*res_code = %s;\n", e->operation->op->id);
+	  expr *e = as_a <expr *> (s->result);
+	  bool is_predicate = is_a <predicate_id *> (e->operation->op);
+	  if (!is_predicate)
+	    fprintf (f, "*res_code = %s;\n", e->operation->op->id);
 	  for (unsigned j = 0; j < e->ops.length (); ++j)
 	    {
 	      char dest[32];
 	      snprintf (dest, 32, "  res_ops[%d]", j);
 	      const char *optype
-	        = get_operand_type (e->operation->op,
-				    "type", e->expr_type,
-				    j == 0
-				    ? NULL : "TREE_TYPE (res_ops[0])");
+		  = get_operand_type (e->operation->op,
+				      "type", e->expr_type,
+				      j == 0
+				      ? NULL : "TREE_TYPE (res_ops[0])");
 	      e->ops[j]->gen_transform (f, dest, true, 1, optype, indexes);
 	    }
+
 	  /* Re-fold the toplevel result.  It's basically an embedded
 	     gimple_build w/o actually building the stmt.  */
-	  fprintf (f, "gimple_resimplify%d (seq, res_code, type, "
-		   "res_ops, valueize);\n", e->ops.length ());
+	  if (!is_predicate)
+	    fprintf (f, "gimple_resimplify%d (seq, res_code, type, "
+		     "res_ops, valueize);\n", e->ops.length ());
 	}
       else if (s->result->type == operand::OP_CAPTURE
 	       || s->result->type == operand::OP_C_EXPR)
@@ -1919,12 +1972,18 @@ dt_simplify::gen (FILE *f, bool gimple)
     {
       if (s->result->type == operand::OP_EXPR)
 	{
-	  expr *e = static_cast <expr *> (s->result);
+	  expr *e = as_a <expr *> (s->result);
+	  bool is_predicate = is_a <predicate_id *> (e->operation->op);
 	  for (unsigned j = 0; j < e->ops.length (); ++j)
 	    {
-	      fprintf (f, "   tree res_op%d;\n", j);
 	      char dest[32];
-	      snprintf (dest, 32, "  res_op%d", j);
+	      if (is_predicate)
+		snprintf (dest, 32, "res_ops[%d]", j);
+	      else
+		{
+		  fprintf (f, "   tree res_op%d;\n", j);
+		  snprintf (dest, 32, "  res_op%d", j);
+		}
 	      const char *optype
 	        = get_operand_type (e->operation->op,
 				    "type", e->expr_type,
@@ -1932,16 +1991,21 @@ dt_simplify::gen (FILE *f, bool gimple)
 				    ? NULL : "TREE_TYPE (res_op0)");
 	      e->ops[j]->gen_transform (f, dest, false, 1, optype, indexes);
 	    }
-	  /* Re-fold the toplevel result.  */
-	  if (e->operation->op->kind == id_base::CODE)
-	    fprintf (f, "  return fold_build%d (%s, type",
-		     e->ops.length (), e->operation->op->id);
+	  if (is_a <predicate_id *> (e->operation->op))
+	    fprintf (f, "return true;\n");
 	  else
-	    fprintf (f, "  return build_call_expr (builtin_decl_implicit (%s), %d",
-		     e->operation->op->id, e->ops.length());
-	  for (unsigned j = 0; j < e->ops.length (); ++j)
-	    fprintf (f, ", res_op%d", j);
-	  fprintf (f, ");\n");
+	    {
+	      /* Re-fold the toplevel result.  */
+	      if (e->operation->op->kind == id_base::CODE)
+		fprintf (f, "  return fold_build%d (%s, type",
+			 e->ops.length (), e->operation->op->id);
+	      else
+		fprintf (f, "  return build_call_expr (builtin_decl_implicit (%s), %d",
+			 e->operation->op->id, e->ops.length());
+	      for (unsigned j = 0; j < e->ops.length (); ++j)
+		fprintf (f, ", res_op%d", j);
+	      fprintf (f, ");\n");
+	    }
 	}
       else if (s->result->type == operand::OP_CAPTURE
 	       || s->result->type == operand::OP_C_EXPR)
@@ -2062,12 +2126,22 @@ decision_tree::gen_generic (FILE *f)
 }
 
 void
+write_predicate_prototype (FILE *f, predicate_id *p, bool gimple)
+{
+  fprintf (f, "bool %s%s (tree t%s%s);\n",
+	   gimple ? "gimple_" : "tree_", p->id,
+	   p->nargs > 0 ? ", tree *res_ops" : "",
+	   gimple ? ", tree (*valueize)(tree) = NULL" : "");
+}
+
+void
 write_predicate (FILE *f, predicate_id *p, decision_tree &dt, bool gimple)
 {
   fprintf (f, "\nbool\n"
-	   "%s%s (tree t%s)\n"
+	   "%s%s (tree t%s%s)\n"
 	   "{\n", gimple ? "gimple_" : "tree_", p->id,
-	   gimple ? ", tree (*valueize)(tree) = NULL" : "");
+	   p->nargs > 0 ? ", tree *res_ops" : "",
+	   gimple ? ", tree (*valueize)(tree)" : "");
   /* Conveniently make 'type' available.  */
   fprintf (f, "tree type = TREE_TYPE (t);\n");
 
@@ -2458,13 +2532,16 @@ copy_reverse (vec<T> v)
    and fill SIMPLIFIERS with the results.  */
 
 static void
-parse_simplify (cpp_reader *r, const char *id, source_location match_location,
-		vec<simplify *>& simplifiers)
+parse_simplify (cpp_reader *r, source_location match_location,
+		vec<simplify *>& simplifiers, predicate_id *matcher)
 {
   const cpp_token *loc = peek (r);
   struct operand *match = parse_op (r);
-  if (match->type != operand::OP_EXPR)
-    fatal_at (loc, "expected uncaptured expression");
+  if (match->type == operand::OP_CAPTURE && !matcher)
+    fatal_at (loc, "outermost expression cannot be captured");
+  if (match->type == operand::OP_EXPR
+      && is_a <predicate_id *> (as_a <expr *> (match)->operation->op))
+    fatal_at (loc, "outermost expression cannot be a predicate");
 
   const cpp_token *token = peek (r);
 
@@ -2472,8 +2549,14 @@ parse_simplify (cpp_reader *r, const cha
      definition.  Push it.  */
   if (token->type == CPP_CLOSE_PAREN)
     {
+      if (!matcher)
+	fatal_at (token, "expected transform expression");
+      else if (matcher->nargs > 0)
+	fatal_at (token, "expected match operand expression");
+      if (matcher->nargs == -1)
+	matcher->nargs = 0;
       simplifiers.safe_push
-	(new simplify (id, match, match_location, NULL, token->src_loc));
+	(new simplify (match, match_location, NULL, token->src_loc));
       return;
     }
 
@@ -2493,9 +2576,17 @@ parse_simplify (cpp_reader *r, const cha
 	         manual matcher or is part of a predicate definition.
 		 Push it.  */
 	      if (peek (r)->type == CPP_CLOSE_PAREN)
-		simplifiers.safe_push
-		   (new simplify (id, match, match_location, NULL,
-				  paren_loc, copy_reverse (ifexprs)));
+		{
+		  if (!matcher)
+		    fatal_at (token, "manual transform not implemented");
+		  else if (matcher->nargs > 0)
+		    fatal_at (token, "expected match operand expression");
+		  if (matcher->nargs == -1)
+		    matcher->nargs = 0;
+		  simplifiers.safe_push
+		      (new simplify (match, match_location, NULL,
+				     paren_loc, copy_reverse (ifexprs)));
+		}
 	    }
 	  else if (peek_ident (r, "with"))
 	    {
@@ -2507,8 +2598,20 @@ parse_simplify (cpp_reader *r, const cha
 	    }
 	  else
 	    {
+	      operand *op = parse_expr (r);
+	      if (matcher)
+		{
+		  expr *e = dyn_cast <expr *> (op);
+		  if (!e)
+		    fatal_at (token, "match operand expression cannot be captured");
+		  if (matcher->nargs == -1)
+		    matcher->nargs = e->ops.length ();
+		  if (matcher->nargs == 0
+		      || (unsigned) matcher->nargs != e->ops.length ())
+		    fatal_at (token, "match arity doesn't match");
+		}
 	      simplifiers.safe_push
-		  (new simplify (id, match, match_location, parse_expr (r),
+		  (new simplify (match, match_location, op,
 				 token->src_loc, copy_reverse (ifexprs)));
 	      eat_token (r, CPP_CLOSE_PAREN);
 	      /* A "default" result closes the enclosing scope.  */
@@ -2535,8 +2638,10 @@ parse_simplify (cpp_reader *r, const cha
 	}
       else
 	{
+	  if (matcher)
+	    fatal_at (token, "expected match operand expression");
 	  simplifiers.safe_push
-	      (new simplify (id, match, match_location, parse_op (r),
+	      (new simplify (match, match_location, parse_op (r),
 			     token->src_loc, copy_reverse (ifexprs)));
 	  /* A "default" result closes the enclosing scope.  */
 	  if (ifexprs.length () > 0)
@@ -2654,7 +2759,7 @@ parse_for (cpp_reader *r, source_locatio
 		ifexpr_vec[k].cexpr = replace_id (ifexpr_vec[k].cexpr, user_ids[i], oper);
 
 	    }
-	  simplify *ns = new simplify (s->name, match_op, s->match_location,
+	  simplify *ns = new simplify (match_op, s->match_location,
 				       result_op, s->result_location, ifexpr_vec);
 	  simplifiers.safe_push (ns);
 	}
@@ -2713,7 +2818,7 @@ parse_pattern (cpp_reader *r, vec<simpli
   const cpp_token *token = peek (r);
   const char *id = get_ident (r);
   if (strcmp (id, "simplify") == 0)
-    parse_simplify (r, NULL, token->src_loc, simplifiers);
+    parse_simplify (r, token->src_loc, simplifiers, NULL);
   else if (strcmp (id, "match") == 0)
     {
       const char *name = get_ident (r);
@@ -2725,8 +2830,7 @@ parse_pattern (cpp_reader *r, vec<simpli
 	;
       else
 	fatal_at (token, "cannot add a match to a non-predicate ID");
-      parse_simplify (r, name, token->src_loc, p->matchers);
-      /* ???  Sanity check the added "simplifiers".  */
+      parse_simplify (r, token->src_loc, p->matchers, p);
     }
   else if (strcmp (id, "for") == 0)
     parse_for (r, token->src_loc, simplifiers); 
@@ -2839,6 +2943,15 @@ add_operator (CONVERT2, "CONVERT2", "tcc
   for (hash_table<id_base>::iterator iter = operators->begin ();
        iter != operators->end (); ++iter)
     {
+      id_base *id = *iter;
+      if (predicate_id *p = dyn_cast <predicate_id *> (id))
+	if (p->matchers.exists ())
+	  /* ???  Write prototypes to some header?  */
+	  write_predicate_prototype (stdout, p, gimple);
+    }
+  for (hash_table<id_base>::iterator iter = operators->begin ();
+       iter != operators->end (); ++iter)
+    {
       id_base *id = *iter;
       if (predicate_id *p = dyn_cast <predicate_id *> (id))
 	if (p->matchers.exists ())
Index: gcc/match-bitwise.pd
===================================================================
--- gcc/match-bitwise.pd	(revision 215499)
+++ gcc/match-bitwise.pd	(working copy)
@@ -65,6 +65,42 @@ along with GCC; see the file COPYING3.
 
 /* Try simple folding for X op !X, and X op X.
    From tree-ssa-forwprop.c:simplify_bitwise_binary_1.  */
+/* tree-ssa-forwprop.c:truth_valued_ssa_name.  */
+(match truth_valued_p
+ @0
+ (if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1)))
+#if 0
+/* ???  for doesn't yet work for matchers.  */
+(for op (lt le eq ne ge gt truth_and truth_andif truth_or truth_orif truth_xor)
+ (match truth_valued_p
+  (op @0 @1)))
+#endif
+(match truth_valued_p
+  (truth_not @0))
+(match logical_inverted_value
+ (bit_not truth_valued_p@0)
+ (logical_inverted_value @0))
+(match logical_inverted_value
+ (eq @0 integer_zerop)
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
+  (logical_inverted_value @0)))
+(match logical_inverted_value
+ (ne truth_valued_p@0 integer_onep)
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
+  (logical_inverted_value @0)))
+(match logical_inverted_value
+ (bit_xor truth_valued_p@0 integer_onep)
+ (logical_inverted_value @0))
+/* X & !X -> 0.  */
+(simplify
+ (bit_and @0 (logical_inverted_value @0))
+ { build_zero_cst (type); })
+/* X | !X and X ^ !X -> 1, , if X is truth-valued.  */
+(for op (bit_ior bit_xor)
+ (simplify
+  (op truth_valued_p@0 (logical_inverted_value @0))
+  { build_one_cst (type); }))
+#if 0
 /* x & x -> x,  x | x -> x  */
 (for bitop (bit_and bit_ior)
  (simplify
@@ -98,6 +134,7 @@ along with GCC; see the file COPYING3.
    (if (truth_valued_ssa_name (@0))
     { bitop == BIT_AND ? build_zero_cst (type) : build_one_cst (type); }))))
 #endif
+#endif
 
 (for bitop (bit_and bit_ior)
      rbitop (bit_ior bit_and)
