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


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

Re: Match-and-simplify and COND_EXPR


On Tue, 11 Nov 2014, Richard Biener wrote:

> On Tue, 11 Nov 2014, Richard Biener wrote:
> 
> > On Mon, 10 Nov 2014, Andrew Pinski wrote:
> > 
> > > On Fri, Nov 7, 2014 at 2:23 AM, Richard Biener <rguenther@suse.de> wrote:
> > > > On Thu, 6 Nov 2014, Andrew Pinski wrote:
> > > >
> > > >> On Thu, Nov 6, 2014 at 2:40 AM, Richard Biener <rguenther@suse.de> wrote:
> > > >> > On Thu, 6 Nov 2014, Richard Biener wrote:
> > > >> >
> > > >> >> On Wed, 5 Nov 2014, Andrew Pinski wrote:
> > > >> >>
> > > >> >> > Hi,
> > > >> >> >   I was trying to hook up tree-ssa-phiopt to match-and-simplify using
> > > >> >> > either gimple_build (or rather using gimple_simplify depending on if
> > > >> >> > we want to produce cond_expr for conditional move).  I ran into a
> > > >> >> > problem.
> > > >> >> > With the pattern below:
> > > >> >> > /* a ? 0 : 1 -> a if 0 and 1 are integral types. */
> > > >> >> > (simplify
> > > >> >> >   (cond_expr @0 integer_zerop integer_onep)
> > > >> >> >   (if (INTEGRAL_TYPE_P (type))
> > > >> >> >     (convert @0)))
> > > >> >>
> > > >> >> Ok, so you are capturing a GENERIC expr here but nothing knows that.
> > > >> >> It would work if you'd do (ugh)
> > > >> >>
> > > >> >> (for op (lt le eq ne ge gt)
> > > >> >>  (simplify
> > > >> >>   (cond_expr (op @0 @1) integer_zerop integer_onep)
> > > >> >>   (if (INTEGRAL_TYPE_P (type))
> > > >> >>    (convert (op @0 @1)))))
> > > >> >> (simplify
> > > >> >>  (cond_expr SSA_NAME@0 integer_zerop integer_onep)
> > > >> >>   (if (INTEGRAL_TYPE_P (type))
> > > >> >>    (convert @0))))
> > > >> >>
> > > >> >> as a workaround.  To make your version work will require (quite)
> > > >> >> some special-casing in the code generator or maybe the resimplify
> > > >> >> helper.  Let me see if I can cook up a "simple" fix.
> > > >> >
> > > >> > Sth like below (for the real fix this has to be replicated in
> > > >> > all gimple_resimplifyN functions).  I'm missing a testcase
> > > >> > where the pattern would apply (and not be already folded by fold),
> > > >> > so I didn't check if it actually works.
> > > >>
> > > >> You do need to check if seq is NULL though as gimple_build depends on
> > > >> seq not being NULL.  But otherwise yes this works for me.
> > > >
> > > > Ok, here is a better and more complete fix.  The optimization
> > > > whether a captured expression may be a GENERIC condition isn't
> > > > implemented so a lot of checks are emitted right now.  Also
> > > > if gimple_build would fail this terminates the whole matching
> > > > process, not just matching of the current pattern (failing "late"
> > > > isn't supported with the style of code we emit - well, without
> > > > adding ugly gotos and labels).
> > > >
> > > > At least it avoids splitting up conditions if substituted into
> > > > a COND_EXPR, so simplifications of COND_EXPRs in-place (w/o seq)
> > > > should still work.
> > > >
> > > > Can you check whether this works for you?
> > > 
> > > This works for most cases but does not work for things like:
> > > /* a != b ? a : b -> a */
> > > (simplify
> > >   (cond_expr (ne @0 @1) @0 @1)
> > >   @0)
> > >
> > > In gimple_simplify after it matches COND_EXPR. It does not look into
> > > the operand 0 to see if it matches NE_EXPR, it just sees if it was a
> > > SSA_NAME.  In this case I was trying to do a simple replacement of
> > > value_replacement in tree-ssa-phiopt.c.
> > 
> > Yeah - I hoped you wouldn't notice.  It's not too difficult to fix.
> > Still this ugly ambiguity in the GIMPLE IL is bad and I wonder if
> > it is better to finally fix it with
> > 
> > Index: gcc/gimple-expr.c
> > ===================================================================
> > --- gcc/gimple-expr.c   (revision 216973)
> > +++ gcc/gimple-expr.c   (working copy)
> > @@ -641,10 +641,7 @@ is_gimple_lvalue (tree t)
> >  bool
> >  is_gimple_condexpr (tree t)
> >  {
> > -  return (is_gimple_val (t) || (COMPARISON_CLASS_P (t)
> > -                               && !tree_could_throw_p (t)
> > -                               && is_gimple_val (TREE_OPERAND (t, 0))
> > -                               && is_gimple_val (TREE_OPERAND (t, 1))));
> > +  return is_gimple_val (t);
> >  }
> >  
> >  /* Return true if T is a gimple address.  */
> > 
> > I expect mostly fallout from passes building [VEC_]COND_EXPRs and
> > not gimplifying it and of course missed optimizations from the
> > vectorizer which will likely now try to vectorize the separate
> > comparisons in some maybe odd way (not sure).
> > 
> > I did this experiment once but didn't finish it.  Too bad :/
> > 
> > > But for my purpose right now this is sufficient and will be posting a
> > > patch which does not remove things from tree-ssa-phiopt.c just yet.
> > 
> > Fair enough.  I suppose for GCC 5 I will need to deal with the odd
> > GIMPLE IL.  At least I can consider it a "bug" and thus fix this
> > during stage3 ;)
> 
> Well.  Like the following which creates the expected code for
> 
> (simplify
>  (cond_expr (eq @0 @1) @0 @1)
>  @1)
> 
> I'll install this on the branch and work on the other patch to
> clean it up a bit.

Here is a combined patch to test.

Richard.

Index: gcc/genmatch.c
===================================================================
--- gcc/genmatch.c	(revision 217279)
+++ gcc/genmatch.c	(working copy)
@@ -411,6 +411,7 @@ typedef hash_map<const char *, unsigned,
 /* The AST produced by parsing of the pattern definitions.  */
 
 struct dt_operand;
+struct capture_info;
 
 /* The base class for operands.  */
 
@@ -419,7 +420,9 @@ struct operand {
   operand (enum op_type type_) : type (type_) {}
   enum op_type type;
   virtual void gen_transform (FILE *, const char *, bool, int,
-			      const char *, dt_operand ** = 0)
+			      const char *, capture_info *,
+			      dt_operand ** = 0,
+			      bool = true)
     { gcc_unreachable  (); }
 };
 
@@ -438,7 +441,8 @@ struct expr : public operand
 {
   expr (id_base *operation_, bool is_commutative_ = false)
     : operand (OP_EXPR), operation (operation_),
-      ops (vNULL), expr_type (NULL), is_commutative (is_commutative_) {}
+      ops (vNULL), expr_type (NULL), is_commutative (is_commutative_),
+      is_generic (false) {}
   void append_op (operand *op) { ops.safe_push (op); }
   /* The operator and its operands.  */
   id_base *operation;
@@ -448,8 +452,11 @@ struct expr : public operand
   /* Whether the operation is to be applied commutatively.  This is
      later lowered to two separate patterns.  */
   bool is_commutative;
+  /* Whether the expression is expected to be in GENERIC form.  */
+  bool is_generic;
   virtual void gen_transform (FILE *f, const char *, bool, int,
-			      const char *, dt_operand ** = 0);
+			      const char *, capture_info *,
+			      dt_operand ** = 0, bool = true);
 };
 
 /* An operator that is represented by native C code.  This is always
@@ -479,7 +486,8 @@ struct c_expr : public operand
   /* The identifier replacement vector.  */
   vec<id_tab> ids;
   virtual void gen_transform (FILE *f, const char *, bool, int,
-			      const char *, dt_operand **);
+			      const char *, capture_info *,
+			      dt_operand ** = 0, bool = true);
 };
 
 /* A wrapper around another operand that captures its value.  */
@@ -493,7 +501,8 @@ struct capture : public operand
   /* The captured value.  */
   operand *what;
   virtual void gen_transform (FILE *f, const char *, bool, int,
-			      const char *, dt_operand ** = 0);
+			      const char *, capture_info *,
+			      dt_operand ** = 0, bool = true);
 };
 
 template<>
@@ -842,6 +851,106 @@ lower_opt_convert (simplify *s, vec<simp
     }
 }
 
+/* Lower the compare operand of COND_EXPRs and VEC_COND_EXPRs to a
+   GENERIC and a GIMPLE variant.  */
+
+static vec<operand *>
+lower_cond (operand *o)
+{
+  vec<operand *> ro = vNULL;
+
+  if (capture *c = dyn_cast<capture *> (o))
+    {
+      if (c->what)
+	{
+	  vec<operand *> lop = vNULL;
+	  lop = lower_cond (c->what);
+
+	  for (unsigned i = 0; i < lop.length (); ++i)
+	    ro.safe_push (new capture (c->where, lop[i]));
+	  return ro;
+	}
+    }
+
+  expr *e = dyn_cast<expr *> (o);
+  if (!e || e->ops.length () == 0)
+    {
+      ro.safe_push (o);
+      return ro;
+    }
+
+  vec< vec<operand *> > ops_vector = vNULL;
+  for (unsigned i = 0; i < e->ops.length (); ++i)
+    ops_vector.safe_push (lower_cond (e->ops[i]));
+
+  auto_vec< vec<operand *> > result;
+  auto_vec<operand *> v (e->ops.length ());
+  v.quick_grow_cleared (e->ops.length ());
+  cartesian_product (ops_vector, result, v, 0);
+
+  for (unsigned i = 0; i < result.length (); ++i)
+    {
+      expr *ne = new expr (e->operation);
+      for (unsigned j = 0; j < result[i].length (); ++j)
+	ne->append_op (result[i][j]);
+      ro.safe_push (ne);
+      /* If this is a COND with a captured expression or an
+         expression with two operands then also match a GENERIC
+	 form on the compare.  */
+      if ((*e->operation == COND_EXPR
+	   || *e->operation == VEC_COND_EXPR)
+	  && ((is_a <capture *> (e->ops[0])
+	       && as_a <capture *> (e->ops[0])->what
+	       && is_a <expr *> (as_a <capture *> (e->ops[0])->what)
+	       && as_a <expr *>
+	            (as_a <capture *> (e->ops[0])->what)->ops.length () == 2)
+	      || (is_a <expr *> (e->ops[0])
+		  && as_a <expr *> (e->ops[0])->ops.length () == 2)))
+	{
+	  expr *ne = new expr (e->operation);
+	  for (unsigned j = 0; j < result[i].length (); ++j)
+	    ne->append_op (result[i][j]);
+	  if (capture *c = dyn_cast <capture *> (ne->ops[0]))
+	    {
+	      expr *ocmp = as_a <expr *> (c->what);
+	      expr *cmp = new expr (ocmp->operation);
+	      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->where, cmp);
+	    }
+	  else
+	    {
+	      expr *ocmp = as_a <expr *> (ne->ops[0]);
+	      expr *cmp = new expr (ocmp->operation);
+	      for (unsigned j = 0; j < ocmp->ops.length (); ++j)
+		cmp->append_op (ocmp->ops[j]);
+	      cmp->is_generic = true;
+	      ne->ops[0] = cmp;
+	    }
+	  ro.safe_push (ne);
+	}
+    }
+
+  return ro;
+}
+
+/* Lower the compare operand of COND_EXPRs and VEC_COND_EXPRs to a
+   GENERIC and a GIMPLE variant.  */
+
+static void
+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 (matchers[i], s->match_location,
+				   s->result, s->result_location, s->ifexpr_vec,
+				   s->for_vec, s->capture_ids);
+      simplifiers.safe_push (ns);
+    }
+}
+
 /* In AST operand O replace operator ID with operator WITH.  */
 
 operand *
@@ -937,19 +1046,27 @@ lower_for (simplify *sin, vec<simplify *
 /* Lower the AST for everything in SIMPLIFIERS.  */
 
 static void
-lower (vec<simplify *>& simplifiers)
+lower (vec<simplify *>& simplifiers, bool gimple)
 {
-  auto_vec<simplify *> out_simplifiers0;
+  auto_vec<simplify *> out_simplifiers;
   for (unsigned i = 0; i < simplifiers.length (); ++i)
-    lower_opt_convert (simplifiers[i], out_simplifiers0);
+    lower_opt_convert (simplifiers[i], out_simplifiers);
+
+  simplifiers.truncate (0);
+  for (unsigned i = 0; i < out_simplifiers.length (); ++i)
+    lower_commutative (out_simplifiers[i], simplifiers);
+
+  out_simplifiers.truncate (0);
+  if (gimple)
+    for (unsigned i = 0; i < simplifiers.length (); ++i)
+      lower_cond (simplifiers[i], out_simplifiers);
+  else
+    out_simplifiers.safe_splice (simplifiers);
 
-  auto_vec<simplify *> out_simplifiers1;
-  for (unsigned i = 0; i < out_simplifiers0.length (); ++i)
-    lower_commutative (out_simplifiers0[i], out_simplifiers1);
 
   simplifiers.truncate (0);
-  for (unsigned i = 0; i < out_simplifiers1.length (); ++i)
-    lower_for (out_simplifiers1[i], simplifiers);
+  for (unsigned i = 0; i < out_simplifiers.length (); ++i)
+    lower_for (out_simplifiers[i], simplifiers);
 }
 
 
@@ -1069,7 +1186,8 @@ cmp_operand (operand *o1, operand *o2)
     {
       expr *e1 = static_cast<expr *>(o1);
       expr *e2 = static_cast<expr *>(o2);
-      return e1->operation == e2->operation;
+      return (e1->operation == e2->operation
+	      && e1->is_generic == e2->is_generic);
     }
   else
     return false;
@@ -1306,6 +1424,196 @@ decision_tree::print (FILE *f)
 }
 
 
+/* For GENERIC we have to take care of wrapping multiple-used
+   expressions with side-effects in save_expr and preserve side-effects
+   of expressions with omit_one_operand.  Analyze captures in
+   match, result and with expressions and perform early-outs
+   on the outermost match expression operands for cases we cannot
+   handle.  */
+
+struct capture_info
+{
+  capture_info (simplify *s);
+  void walk_match (operand *o, unsigned toplevel_arg, bool, bool);
+  void walk_result (operand *o, bool);
+  void walk_c_expr (c_expr *);
+
+  struct cinfo
+    {
+      bool expr_p;
+      bool cse_p;
+      bool force_no_side_effects_p;
+      bool cond_expr_cond_p;
+      unsigned long toplevel_msk;
+      int result_use_count;
+    };
+
+  auto_vec<cinfo> info;
+  unsigned long force_no_side_effects;
+};
+
+/* Analyze captures in S.  */
+
+capture_info::capture_info (simplify *s)
+{
+  expr *e;
+  if (!s->result
+      || ((e = dyn_cast <expr *> (s->result))
+	  && is_a <predicate_id *> (e->operation)))
+    {
+      force_no_side_effects = -1;
+      return;
+    }
+
+  force_no_side_effects = 0;
+  info.safe_grow_cleared (s->capture_max + 1);
+  e = as_a <expr *> (s->match);
+  for (unsigned i = 0; i < e->ops.length (); ++i)
+    walk_match (e->ops[i], i,
+		(i != 0
+		 && (*e->operation == COND_EXPR
+		     || *e->operation == VEC_COND_EXPR))
+		|| *e->operation == TRUTH_ANDIF_EXPR
+		|| *e->operation == TRUTH_ORIF_EXPR,
+		i == 0
+		&& (*e->operation == COND_EXPR
+		    || *e->operation == VEC_COND_EXPR));
+
+  walk_result (s->result, false);
+
+  for (unsigned i = 0; i < s->ifexpr_vec.length (); ++i)
+    if (s->ifexpr_vec[i].is_with)
+      walk_c_expr (as_a <c_expr *>(s->ifexpr_vec[i].cexpr));
+}
+
+/* Analyze captures in the match expression piece O.  */
+
+void
+capture_info::walk_match (operand *o, unsigned toplevel_arg,
+			  bool conditional_p, bool cond_expr_cond_p)
+{
+  if (capture *c = dyn_cast <capture *> (o))
+    {
+      info[c->where].toplevel_msk |= 1 << toplevel_arg;
+      info[c->where].force_no_side_effects_p |= conditional_p;
+      info[c->where].cond_expr_cond_p |= cond_expr_cond_p;
+      /* Mark expr (non-leaf) captures and recurse.  */
+      if (c->what
+	  && is_a <expr *> (c->what))
+	{
+	  info[c->where].expr_p = true;
+	  walk_match (c->what, toplevel_arg, conditional_p, false);
+	}
+    }
+  else if (expr *e = dyn_cast <expr *> (o))
+    {
+      for (unsigned i = 0; i < e->ops.length (); ++i)
+	{
+	  bool cond_p = conditional_p;
+	  bool cond_expr_cond_p = false;
+	  if (*e->operation == COND_EXPR
+	      || *e->operation == VEC_COND_EXPR)
+	    {
+	      if (i != 0)
+		cond_p = true;
+	      else
+		cond_expr_cond_p = true;
+	    }
+	  else if (*e->operation == TRUTH_ANDIF_EXPR
+		   || *e->operation == TRUTH_ORIF_EXPR)
+	    cond_p = true;
+	  walk_match (e->ops[i], toplevel_arg, cond_p, cond_expr_cond_p);
+	}
+    }
+  else if (is_a <predicate *> (o))
+    {
+      /* Mark non-captured leafs toplevel arg for checking.  */
+      force_no_side_effects |= 1 << toplevel_arg;
+    }
+  else
+    gcc_unreachable ();
+}
+
+/* Analyze captures in the result expression piece O.  */
+
+void
+capture_info::walk_result (operand *o, bool conditional_p)
+{
+  if (capture *c = dyn_cast <capture *> (o))
+    {
+      info[c->where].result_use_count++;
+      /* If we substitute an expression capture we don't know
+         which captures this will end up using (well, we don't
+	 compute that).  Force the uses to be side-effect free
+	 which means forcing the toplevels that reach the
+	 expression side-effect free.  */
+      if (info[c->where].expr_p)
+	force_no_side_effects |= info[c->where].toplevel_msk;
+      /* Mark CSE capture capture uses as forced to have
+         no side-effects. */
+      if (c->what
+	  && is_a <expr *> (c->what))
+	{
+	  info[c->where].cse_p = true;
+	  walk_result (c->what, true);
+	}
+    }
+  else if (expr *e = dyn_cast <expr *> (o))
+    {
+      for (unsigned i = 0; i < e->ops.length (); ++i)
+	{
+	  bool cond_p = conditional_p;
+	  if (i == 0
+	      && (*e->operation == COND_EXPR
+		  || *e->operation == VEC_COND_EXPR))
+	    cond_p = true;
+	  else if (*e->operation == TRUTH_ANDIF_EXPR
+		   || *e->operation == TRUTH_ORIF_EXPR)
+	    cond_p = true;
+	  walk_result (e->ops[i], cond_p);
+	}
+    }
+  else if (c_expr *e = dyn_cast <c_expr *> (o))
+    walk_c_expr (e);
+  else
+    gcc_unreachable ();
+}
+
+/* Look for captures in the C expr E.  */
+
+void
+capture_info::walk_c_expr (c_expr *e)
+{
+  /* Give up for C exprs mentioning captures not inside TREE_TYPE ().  */
+  unsigned p_depth = 0;
+  for (unsigned i = 0; i < e->code.length (); ++i)
+    {
+      const cpp_token *t = &e->code[i];
+      const cpp_token *n = i < e->code.length () - 1 ? &e->code[i+1] : NULL;
+      if (t->type == CPP_NAME
+	  && strcmp ((const char *)CPP_HASHNODE
+		       (t->val.node.node)->ident.str, "TREE_TYPE") == 0
+	  && n->type == CPP_OPEN_PAREN)
+	p_depth++;
+      else if (t->type == CPP_CLOSE_PAREN
+	       && p_depth > 0)
+	p_depth--;
+      else if (p_depth == 0
+	       && t->type == CPP_ATSIGN
+	       && (n->type == CPP_NUMBER
+		   || n->type == CPP_NAME)
+	       && !(n->flags & PREV_WHITE))
+	{
+	  const char *id;
+	  if (n->type == CPP_NUMBER)
+	    id = (const char *)n->val.str.text;
+	  else
+	    id = (const char *)CPP_HASHNODE (n->val.node.node)->ident.str;
+	  info[*e->capture_ids->get(id)].force_no_side_effects_p = true;
+	}
+    }
+}
+
 
 /* Code generation off the decision tree and the refered AST nodes.  */
 
@@ -1355,7 +1663,8 @@ get_operand_type (id_base *op, const cha
 
 void
 expr::gen_transform (FILE *f, const char *dest, bool gimple, int depth,
-		     const char *in_type, dt_operand **indexes)
+		     const char *in_type, capture_info *cinfo,
+		     dt_operand **indexes, bool)
 {
   bool conversion_p = is_conversion (operation);
   const char *type = expr_type;
@@ -1402,7 +1711,10 @@ expr::gen_transform (FILE *f, const char
       const char *optype
 	= get_operand_type (operation, in_type, expr_type,
 			    i == 0 ? NULL : op0type);
-      ops[i]->gen_transform (f, dest, gimple, depth + 1, optype, indexes);
+      ops[i]->gen_transform (f, dest, gimple, depth + 1, optype, cinfo, indexes,
+			     ((!(*operation == COND_EXPR)
+			       && !(*operation == VEC_COND_EXPR))
+			      || i != 0));
     }
 
   const char *opr;
@@ -1452,7 +1764,8 @@ expr::gen_transform (FILE *f, const char
 
 void
 c_expr::gen_transform (FILE *f, const char *dest,
-		       bool, int, const char *, dt_operand **)
+		       bool, int, const char *, capture_info *,
+		       dt_operand **, bool)
 {
   if (dest && nr_stmts == 1)
     fprintf (f, "%s = ", dest);
@@ -1521,7 +1834,8 @@ c_expr::gen_transform (FILE *f, const ch
 
 void
 capture::gen_transform (FILE *f, const char *dest, bool gimple, int depth,
-			const char *in_type, dt_operand **indexes)
+			const char *in_type, capture_info *cinfo,
+			dt_operand **indexes, bool expand_compares)
 {
   if (what && is_a<expr *> (what))
     {
@@ -1529,11 +1843,25 @@ capture::gen_transform (FILE *f, const c
 	{
 	  char buf[20];
 	  sprintf (buf, "captures[%u]", where);
-	  what->gen_transform (f, buf, gimple, depth, in_type, NULL);
+	  what->gen_transform (f, buf, gimple, depth, in_type, cinfo, NULL);
 	}
     }
 
   fprintf (f, "%s = captures[%u];\n", dest, where);
+
+  /* ???  Stupid tcc_comparison GENERIC trees in COND_EXPRs.  Deal
+     with substituting a capture of that.
+     ???  Returning false here will also not allow any other patterns
+     to match.  */
+  if (gimple && expand_compares
+      && cinfo->info[where].cond_expr_cond_p)
+    fprintf (f, "if (COMPARISON_CLASS_P (%s))\n"
+	     "  {\n"
+	     "    if (!seq) return false;\n"
+	     "    %s = gimple_build (seq, TREE_CODE (%s),"
+	     " TREE_TYPE (%s), TREE_OPERAND (%s, 0),"
+	     " TREE_OPERAND (%s, 1));\n"
+	     "  }\n", dest, dest, dest, dest, dest, dest);
 }
 
 /* Return the name of the operand representing the decision tree node.
@@ -1617,7 +1945,8 @@ dt_operand::gen_gimple_expr (FILE *f)
 
       if (id->kind == id_base::CODE)
 	{
-	  if (*id == REALPART_EXPR || *id == IMAGPART_EXPR
+	  if (e->is_generic
+	      || *id == REALPART_EXPR || *id == IMAGPART_EXPR
 	      || *id == BIT_FIELD_REF || *id == VIEW_CONVERT_EXPR)
 	    {
 	      /* ???  If this is a memory operation we can't (and should not)
@@ -1921,178 +2250,6 @@ dt_operand::gen (FILE *f, bool gimple)
 }
 
 
-/* For GENERIC we have to take care of wrapping multiple-used
-   expressions with side-effects in save_expr and preserve side-effects
-   of expressions with omit_one_operand.  Analyze captures in
-   match, result and with expressions and perform early-outs
-   on the outermost match expression operands for cases we cannot
-   handle.  */
-
-struct capture_info
-{
-  capture_info (simplify *s);
-  void walk_match (operand *o, unsigned toplevel_arg, bool);
-  void walk_result (operand *o, bool);
-  void walk_c_expr (c_expr *);
-
-  struct cinfo
-    {
-      bool expr_p;
-      bool cse_p;
-      bool force_no_side_effects_p;
-      unsigned long toplevel_msk;
-      int result_use_count;
-    };
-
-  auto_vec<cinfo> info;
-  unsigned long force_no_side_effects;
-};
-
-/* Analyze captures in S.  */
-
-capture_info::capture_info (simplify *s)
-{
-  expr *e;
-  if (!s->result
-      || ((e = dyn_cast <expr *> (s->result))
-	  && is_a <predicate_id *> (e->operation)))
-    {
-      force_no_side_effects = -1;
-      return;
-    }
-
-  force_no_side_effects = 0;
-  info.safe_grow_cleared (s->capture_max + 1);
-  e = as_a <expr *> (s->match);
-  for (unsigned i = 0; i < e->ops.length (); ++i)
-    walk_match (e->ops[i], i, false);
-
-  walk_result (s->result, false);
-
-  for (unsigned i = 0; i < s->ifexpr_vec.length (); ++i)
-    if (s->ifexpr_vec[i].is_with)
-      walk_c_expr (as_a <c_expr *>(s->ifexpr_vec[i].cexpr));
-}
-
-/* Analyze captures in the match expression piece O.  */
-
-void
-capture_info::walk_match (operand *o, unsigned toplevel_arg, bool conditional_p)
-{
-  if (capture *c = dyn_cast <capture *> (o))
-    {
-      info[c->where].toplevel_msk |= 1 << toplevel_arg;
-      info[c->where].force_no_side_effects_p |= conditional_p;
-      /* Mark expr (non-leaf) captures and recurse.  */
-      if (c->what
-	  && is_a <expr *> (c->what))
-	{
-	  info[c->where].expr_p = true;
-	  walk_match (c->what, toplevel_arg, conditional_p);
-	}
-    }
-  else if (expr *e = dyn_cast <expr *> (o))
-    {
-      for (unsigned i = 0; i < e->ops.length (); ++i)
-	{
-	  bool cond_p = conditional_p;
-	  if (i == 0
-	      && *e->operation == COND_EXPR)
-	    cond_p = true;
-	  else if (*e->operation == TRUTH_ANDIF_EXPR
-		   || *e->operation == TRUTH_ORIF_EXPR)
-	    cond_p = true;
-	  walk_match (e->ops[i], toplevel_arg, cond_p);
-	}
-    }
-  else if (is_a <predicate *> (o))
-    {
-      /* Mark non-captured leafs toplevel arg for checking.  */
-      force_no_side_effects |= 1 << toplevel_arg;
-    }
-  else
-    gcc_unreachable ();
-}
-
-/* Analyze captures in the result expression piece O.  */
-
-void
-capture_info::walk_result (operand *o, bool conditional_p)
-{
-  if (capture *c = dyn_cast <capture *> (o))
-    {
-      info[c->where].result_use_count++;
-      /* If we substitute an expression capture we don't know
-         which captures this will end up using (well, we don't
-	 compute that).  Force the uses to be side-effect free
-	 which means forcing the toplevels that reach the
-	 expression side-effect free.  */
-      if (info[c->where].expr_p)
-	force_no_side_effects |= info[c->where].toplevel_msk;
-      /* Mark CSE capture capture uses as forced to have
-         no side-effects. */
-      if (c->what
-	  && is_a <expr *> (c->what))
-	{
-	  info[c->where].cse_p = true;
-	  walk_result (c->what, true);
-	}
-    }
-  else if (expr *e = dyn_cast <expr *> (o))
-    {
-      for (unsigned i = 0; i < e->ops.length (); ++i)
-	{
-	  bool cond_p = conditional_p;
-	  if (i == 0
-	      && *e->operation == COND_EXPR)
-	    cond_p = true;
-	  else if (*e->operation == TRUTH_ANDIF_EXPR
-		   || *e->operation == TRUTH_ORIF_EXPR)
-	    cond_p = true;
-	  walk_result (e->ops[i], cond_p);
-	}
-    }
-  else if (c_expr *e = dyn_cast <c_expr *> (o))
-    walk_c_expr (e);
-  else
-    gcc_unreachable ();
-}
-
-/* Look for captures in the C expr E.  */
-
-void
-capture_info::walk_c_expr (c_expr *e)
-{
-  /* Give up for C exprs mentioning captures not inside TREE_TYPE ().  */
-  unsigned p_depth = 0;
-  for (unsigned i = 0; i < e->code.length (); ++i)
-    {
-      const cpp_token *t = &e->code[i];
-      const cpp_token *n = i < e->code.length () - 1 ? &e->code[i+1] : NULL;
-      if (t->type == CPP_NAME
-	  && strcmp ((const char *)CPP_HASHNODE
-		       (t->val.node.node)->ident.str, "TREE_TYPE") == 0
-	  && n->type == CPP_OPEN_PAREN)
-	p_depth++;
-      else if (t->type == CPP_CLOSE_PAREN
-	       && p_depth > 0)
-	p_depth--;
-      else if (p_depth == 0
-	       && t->type == CPP_ATSIGN
-	       && (n->type == CPP_NUMBER
-		   || n->type == CPP_NAME)
-	       && !(n->flags & PREV_WHITE))
-	{
-	  const char *id;
-	  if (n->type == CPP_NUMBER)
-	    id = (const char *)n->val.str.text;
-	  else
-	    id = (const char *)CPP_HASHNODE (n->val.node.node)->ident.str;
-	  info[*e->capture_ids->get(id)].force_no_side_effects_p = true;
-	}
-    }
-}
-
 
 /* Generate code for the '(if ...)', '(with ..)' and actual transform
    step of a '(simplify ...)' or '(match ...)'.  This handles everything
@@ -2124,7 +2281,7 @@ dt_simplify::gen (FILE *f, bool gimple)
 	    {
 	      fprintf (f, "{\n");
 	      output_line_directive (f, w.location);
-	      w.cexpr->gen_transform (f, NULL, true, 1, "type");
+	      w.cexpr->gen_transform (f, NULL, true, 1, "type", NULL);
 	      n_braces++;
 	    }
 	  else
@@ -2133,7 +2290,7 @@ dt_simplify::gen (FILE *f, bool gimple)
 	      fprintf (f, "if (");
 	      if (i == s->ifexpr_vec.length () - 1
 		  || s->ifexpr_vec[i+1].is_with)
-		w.cexpr->gen_transform (f, NULL, true, 1, "type");
+		w.cexpr->gen_transform (f, NULL, true, 1, "type", NULL);
 	      else
 		{
 		  unsigned j = i;
@@ -2147,7 +2304,8 @@ dt_simplify::gen (FILE *f, bool gimple)
 			}
 		      fprintf (f, "(");
 		      s->ifexpr_vec[j].cexpr->gen_transform (f, NULL,
-							     true, 1, "type");
+							     true, 1, "type",
+							     NULL);
 		      fprintf (f, ")");
 		      ++j;
 		    }
@@ -2224,7 +2382,18 @@ dt_simplify::gen (FILE *f, bool gimple)
 				    "type", e->expr_type,
 				    j == 0
 				    ? NULL : "TREE_TYPE (res_ops[0])");
-	      e->ops[j]->gen_transform (f, dest, true, 1, optype, indexes);
+	      /* We need to expand GENERIC conditions we captured from
+	         COND_EXPRs.  */
+	      bool expand_generic_cond_exprs_p
+	        = (!is_predicate
+		   /* But avoid doing that if the GENERIC condition is
+		      valid - which it is in the first operand of COND_EXPRs
+		      and VEC_COND_EXRPs.  */
+		   && ((!(*e->operation == COND_EXPR)
+			&& !(*e->operation == VEC_COND_EXPR))
+		       || j != 0));
+	      e->ops[j]->gen_transform (f, dest, true, 1, optype, &cinfo,
+					indexes, expand_generic_cond_exprs_p);
 	    }
 
 	  /* Re-fold the toplevel result.  It's basically an embedded
@@ -2236,8 +2405,23 @@ dt_simplify::gen (FILE *f, bool gimple)
       else if (result->type == operand::OP_CAPTURE
 	       || result->type == operand::OP_C_EXPR)
 	{
-	  result->gen_transform (f, "res_ops[0]", true, 1, "type", indexes);
-	  fprintf (f, "*res_code = TREE_CODE (res_ops[0]);\n");
+	  result->gen_transform (f, "res_ops[0]", true, 1, "type",
+				 &cinfo, indexes, false);
+	  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 (f, "if (COMPARISON_CLASS_P (res_ops[0]))\n"
+		       "  {\n"
+		       "    tree tem = res_ops[0];\n"
+		       "    res_ops[0] = TREE_OPERAND (tem, 0);\n"
+		       "    res_ops[1] = TREE_OPERAND (tem, 1);\n"
+		       "    *res_code = TREE_CODE (tem);\n"
+		       "  }\n"
+		       "else\n"
+		       "  *res_code = TREE_CODE (res_ops[0]);\n");
+	    }
 	}
       else
 	gcc_unreachable ();
@@ -2276,7 +2460,8 @@ dt_simplify::gen (FILE *f, bool gimple)
 				    "type", e->expr_type,
 				    j == 0
 				    ? NULL : "TREE_TYPE (res_op0)");
-	      e->ops[j]->gen_transform (f, dest, false, 1, optype, indexes);
+	      e->ops[j]->gen_transform (f, dest, false, 1, optype,
+					&cinfo, indexes);
 	    }
 	  if (is_predicate)
 	    fprintf (f, "return true;\n");
@@ -2310,7 +2495,8 @@ dt_simplify::gen (FILE *f, bool gimple)
 
 	{
 	  fprintf (f, "  tree res;\n");
-	  s->result->gen_transform (f, " res", false, 1, "type", indexes);
+	  s->result->gen_transform (f, " res", false, 1, "type",
+				    &cinfo, indexes);
 	}
       else
 	gcc_unreachable ();
@@ -3387,7 +3573,7 @@ add_operator (CONVERT2, "CONVERT2", "tcc
   for (unsigned i = 0; i < p.user_predicates.length (); ++i)
     {
       predicate_id *pred = p.user_predicates[i];
-      lower (pred->matchers);
+      lower (pred->matchers, gimple);
 
       if (verbose)
 	for (unsigned i = 0; i < pred->matchers.length (); ++i)
@@ -3404,7 +3590,7 @@ add_operator (CONVERT2, "CONVERT2", "tcc
     }
 
   /* Lower the main simplifiers and generate code for them.  */
-  lower (p.simplifiers);
+  lower (p.simplifiers, gimple);
 
   if (verbose)
     for (unsigned i = 0; i < p.simplifiers.length (); ++i)


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