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


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

[PATCH] Merge even more tails (from for expansion) in genmatch.c


This changes for lowering for most cases that can end up being tail-merged
to not substitute the operator into the result expression but refer to it
using a local variable of the name of the for iterator.

Boostrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

This drops the number of tail implementations from 744 to 224 (in my
dev tree).

Richard.

2015-08-03  Richard Biener  <rguenther@suse.de>

	* genmatch.c (simplify::for_subst_vec): New member.
	(binary_ok): New helper for for lowering.
	(lower_for): Delay substituting operators into result expressions
	if we can merge the results eventually again.
	(capture_info::walk_result): Adjust for user_id appearing as
	result expression operator.
	(expr::gen_transform): Likewise.
	(dt_simplify::gen_1): Likewise.
	(dt_simplify::gen): Pass not substituted operators to tail
	functions or initialize local variable with it.
	(decision_tree::gen): Adjust function signature.
	* match.pd: Fix tests against global code and add default
	cases to switch stmts.

Index: gcc/genmatch.c
===================================================================
--- gcc/genmatch.c	(revision 226490)
+++ gcc/genmatch.c	(working copy)
@@ -683,7 +683,7 @@ struct simplify
   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_),
-      for_vec (for_vec_),
+      for_vec (for_vec_), for_subst_vec (vNULL),
       capture_ids (capture_ids_), capture_max (capture_ids_->elements () - 1) {}
 
   simplify_kind kind;
@@ -697,6 +697,7 @@ struct simplify
   /* Collected 'for' expression operators that have to be replaced
      in the lowering phase.  */
   vec<vec<user_id *> > for_vec;
+  vec<std::pair<user_id *, id_base *> > for_subst_vec;
   /* A map of capture identifiers to indexes.  */
   cid_map_t *capture_ids;
   int capture_max;
@@ -1135,6 +1136,38 @@ replace_id (operand *o, user_id *id, id_
   return o;
 }
 
+/* Return true if the binary operator OP is ok for delayed substitution
+   during for lowering.  */
+
+static bool
+binary_ok (operator_id *op)
+{
+  switch (op->code)
+    {
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case MIN_EXPR:
+    case MAX_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case BIT_AND_EXPR:
+      return true;
+    default:
+      return false;
+    }
+}
+
 /* Lower recorded fors for SIN and output to SIMPLIFIERS.  */
 
 static void
@@ -1154,9 +1187,46 @@ lower_for (simplify *sin, vec<simplify *
       vec<user_id *>& ids = for_vec[fi];
       unsigned n_ids = ids.length ();
       unsigned max_n_opers = 0;
+      bool can_delay_subst = (sin->kind == simplify::SIMPLIFY);
       for (unsigned i = 0; i < n_ids; ++i)
-	if (ids[i]->substitutes.length () > max_n_opers)
-	  max_n_opers = ids[i]->substitutes.length ();
+	{
+	  if (ids[i]->substitutes.length () > max_n_opers)
+	    max_n_opers = ids[i]->substitutes.length ();
+	  /* Require that all substitutes are of the same kind so that
+	     if we delay substitution to the result op code generation
+	     can look at the first substitute for deciding things like
+	     types of operands.  */
+	  enum id_base::id_kind kind = ids[i]->substitutes[0]->kind;
+	  for (unsigned j = 0; j < ids[i]->substitutes.length (); ++j)
+	    if (ids[i]->substitutes[j]->kind != kind)
+	      can_delay_subst = false;
+	    else if (operator_id *op
+		       = dyn_cast <operator_id *> (ids[i]->substitutes[j]))
+	      {
+		operator_id *op0
+		  = as_a <operator_id *> (ids[i]->substitutes[0]);
+		if (strcmp (op->tcc, "tcc_comparison") == 0
+		    && strcmp (op0->tcc, "tcc_comparison") == 0)
+		  ;
+		/* Unfortunately we can't just allow all tcc_binary.  */
+		else if (strcmp (op->tcc, "tcc_binary") == 0
+			 && strcmp (op0->tcc, "tcc_binary") == 0
+			 && binary_ok (op)
+			 && binary_ok (op0))
+		  ;
+		else if ((strcmp (op->id + 1, "SHIFT_EXPR") == 0
+			  || strcmp (op->id + 1, "ROTATE_EXPR") == 0)
+			 && (strcmp (op0->id + 1, "SHIFT_EXPR") == 0
+			     || strcmp (op0->id + 1, "ROTATE_EXPR") == 0))
+		  ;
+		else
+		  can_delay_subst = false;
+	      }
+	    else if (is_a <fn_id *> (ids[i]->substitutes[j]))
+	      ;
+	    else
+	      can_delay_subst = false;
+	}
 
       unsigned worklist_end = worklist.length ();
       for (unsigned si = worklist_start; si < worklist_end; ++si)
@@ -1166,16 +1236,26 @@ lower_for (simplify *sin, vec<simplify *
 	    {
 	      operand *match_op = s->match;
 	      operand *result_op = s->result;
+	      vec<std::pair<user_id *, id_base *> > subst;
+	      subst.create (n_ids);
 	      for (unsigned i = 0; i < n_ids; ++i)
 		{
 		  user_id *id = ids[i];
 		  id_base *oper = id->substitutes[j % id->substitutes.length ()];
+		  subst.quick_push (std::make_pair (id, oper));
 		  match_op = replace_id (match_op, id, oper);
-		  if (result_op)
+		  if (result_op
+		      && !can_delay_subst)
 		    result_op = replace_id (result_op, id, oper);
 		}
 	      simplify *ns = new simplify (s->kind, 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);
 	    }
 	}
@@ -1818,6 +1937,9 @@ capture_info::walk_result (operand *o, b
     }
   else if (expr *e = dyn_cast <expr *> (o))
     {
+      id_base *opr = e->operation;
+      if (user_id *uid = dyn_cast <user_id *> (opr))
+	opr = uid->substitutes[0];
       for (unsigned i = 0; i < e->ops.length (); ++i)
 	{
 	  bool cond_p = conditional_p;
@@ -1972,7 +2094,14 @@ expr::gen_transform (FILE *f, int indent
 		     int depth, const char *in_type, capture_info *cinfo,
 		     dt_operand **indexes, bool)
 {
-  bool conversion_p = is_conversion (operation);
+  id_base *opr = operation;
+  /* When we delay operator substituting during lowering of fors we
+     make sure that for code-gen purposes the effects of each substitute
+     are the same.  Thus just look at that.  */
+  if (user_id *uid = dyn_cast <user_id *> (opr))
+    opr = uid->substitutes[0];
+
+  bool conversion_p = is_conversion (opr);
   const char *type = expr_type;
   char optype[64];
   if (type)
@@ -1982,23 +2111,23 @@ expr::gen_transform (FILE *f, int indent
     /* For conversions we need to build the expression using the
        outer type passed in.  */
     type = in_type;
-  else if (*operation == REALPART_EXPR
-	   || *operation == IMAGPART_EXPR)
+  else if (*opr == REALPART_EXPR
+	   || *opr == IMAGPART_EXPR)
     {
       /* __real and __imag use the component type of its operand.  */
       sprintf (optype, "TREE_TYPE (TREE_TYPE (ops%d[0]))", depth);
       type = optype;
     }
-  else if (is_a <operator_id *> (operation)
-	   && !strcmp (as_a <operator_id *> (operation)->tcc, "tcc_comparison"))
+  else if (is_a <operator_id *> (opr)
+	   && !strcmp (as_a <operator_id *> (opr)->tcc, "tcc_comparison"))
     {
       /* comparisons use boolean_type_node (or what gets in), but
          their operands need to figure out the types themselves.  */
       sprintf (optype, "boolean_type_node");
       type = optype;
     }
-  else if (*operation == COND_EXPR
-	   || *operation == VEC_COND_EXPR)
+  else if (*opr == COND_EXPR
+	   || *opr == VEC_COND_EXPR)
     {
       /* Conditions are of the same type as their first alternative.  */
       sprintf (optype, "TREE_TYPE (ops%d[1])", depth);
@@ -2023,24 +2152,24 @@ expr::gen_transform (FILE *f, int indent
       char dest[32];
       snprintf (dest, 32, "ops%d[%u]", depth, i);
       const char *optype
-	= get_operand_type (operation, in_type, expr_type,
+	= get_operand_type (opr, in_type, expr_type,
 			    i == 0 ? NULL : op0type);
       ops[i]->gen_transform (f, indent, dest, gimple, depth + 1, optype,
 			     cinfo, indexes,
-			     ((!(*operation == COND_EXPR)
-			       && !(*operation == VEC_COND_EXPR))
+			     ((!(*opr == COND_EXPR)
+			       && !(*opr == VEC_COND_EXPR))
 			      || i != 0));
     }
 
-  const char *opr;
+  const char *opr_name;
   if (*operation == CONVERT_EXPR)
-    opr = "NOP_EXPR";
+    opr_name = "NOP_EXPR";
   else
-    opr = operation->id;
+    opr_name = operation->id;
 
   if (gimple)
     {
-      if (*operation == CONVERT_EXPR)
+      if (*opr == CONVERT_EXPR)
 	{
 	  fprintf_indent (f, indent,
 			  "if (%s != TREE_TYPE (ops%d[0])\n",
@@ -2054,7 +2183,7 @@ expr::gen_transform (FILE *f, int indent
       /* ???  Building a stmt can fail for various reasons here, seq being
          NULL or the stmt referencing SSA names occuring in abnormal PHIs.
 	 So if we fail here we should continue matching other patterns.  */
-      fprintf_indent (f, indent, "code_helper tem_code = %s;\n", opr);
+      fprintf_indent (f, indent, "code_helper tem_code = %s;\n", opr_name);
       fprintf_indent (f, indent, "tree tem_ops[3] = { ");
       for (unsigned i = 0; i < ops.length (); ++i)
 	fprintf (f, "ops%d[%u]%s", depth, i,
@@ -2067,7 +2196,7 @@ expr::gen_transform (FILE *f, int indent
 		      type);
       fprintf_indent (f, indent,
 		      "if (!res) return false;\n");
-      if (*operation == CONVERT_EXPR)
+      if (*opr == CONVERT_EXPR)
 	{
 	  indent -= 4;
 	  fprintf_indent (f, indent, "  }\n");
@@ -2077,22 +2206,22 @@ expr::gen_transform (FILE *f, int indent
     }
   else
     {
-      if (*operation == CONVERT_EXPR)
+      if (*opr == CONVERT_EXPR)
 	{
 	  fprintf_indent (f, indent, "if (TREE_TYPE (ops%d[0]) != %s)\n",
 			  depth, type);
 	  indent += 2;
 	}
-      if (operation->kind == id_base::CODE)
+      if (opr->kind == id_base::CODE)
 	fprintf_indent (f, indent, "res = fold_build%d_loc (loc, %s, %s",
-			ops.length(), opr, type);
+			ops.length(), opr_name, type);
       else
 	fprintf_indent (f, indent, "res = build_call_expr_loc (loc, "
-			"builtin_decl_implicit (%s), %d", opr, ops.length());
+			"builtin_decl_implicit (%s), %d", opr_name, ops.length());
       for (unsigned i = 0; i < ops.length (); ++i)
 	fprintf (f, ", ops%d[%u]", depth, i);
       fprintf (f, ");\n");
-      if (*operation == CONVERT_EXPR)
+      if (*opr == CONVERT_EXPR)
 	{
 	  indent -= 2;
 	  fprintf_indent (f, indent, "else\n");
@@ -2838,7 +2995,15 @@ dt_simplify::gen_1 (FILE *f, int indent,
       if (result->type == operand::OP_EXPR)
 	{
 	  expr *e = as_a <expr *> (result);
-	  bool is_predicate = is_a <predicate_id *> (e->operation);
+	  id_base *opr = e->operation;
+	  bool is_predicate = false;
+	  /* When we delay operator substituting during lowering of fors we
+	     make sure that for code-gen purposes the effects of each substitute
+	     are the same.  Thus just look at that.  */
+	  if (user_id *uid = dyn_cast <user_id *> (opr))
+	    opr = uid->substitutes[0];
+	  else if (is_a <predicate_id *> (opr))
+	    is_predicate = true;
 	  if (!is_predicate)
 	    fprintf_indent (f, indent, "*res_code = %s;\n",
 			    *e->operation == CONVERT_EXPR
@@ -2848,7 +3013,7 @@ dt_simplify::gen_1 (FILE *f, int indent,
 	      char dest[32];
 	      snprintf (dest, 32, "res_ops[%d]", j);
 	      const char *optype
-		= get_operand_type (e->operation,
+		= get_operand_type (opr,
 				    "type", e->expr_type,
 				    j == 0 ? NULL : "TREE_TYPE (res_ops[0])");
 	      /* We need to expand GENERIC conditions we captured from
@@ -2858,8 +3023,8 @@ dt_simplify::gen_1 (FILE *f, int indent,
 		   /* 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))
+		   && ((!(*opr == COND_EXPR)
+			&& !(*opr == VEC_COND_EXPR))
 		       || j != 0));
 	      e->ops[j]->gen_transform (f, indent, dest, true, 1, optype,
 					&cinfo,
@@ -2908,7 +3073,14 @@ dt_simplify::gen_1 (FILE *f, int indent,
       if (result->type == operand::OP_EXPR)
 	{
 	  expr *e = as_a <expr *> (result);
-	  is_predicate = is_a <predicate_id *> (e->operation);
+	  id_base *opr = e->operation;
+	  /* When we delay operator substituting during lowering of fors we
+	     make sure that for code-gen purposes the effects of each substitute
+	     are the same.  Thus just look at that.  */
+	  if (user_id *uid = dyn_cast <user_id *> (opr))
+	    opr = uid->substitutes[0];
+	  else if (is_a <predicate_id *> (opr))
+	    is_predicate = true;
 	  /* Search for captures used multiple times in the result expression
 	     and dependent on TREE_SIDE_EFFECTS emit a SAVE_EXPR.  */
 	  if (!is_predicate)
@@ -2938,7 +3110,7 @@ dt_simplify::gen_1 (FILE *f, int indent,
 		  snprintf (dest, 32, "res_op%d", j);
 		}
 	      const char *optype
-	        = get_operand_type (e->operation,
+	        = get_operand_type (opr,
 				    "type", e->expr_type,
 				    j == 0
 				    ? NULL : "TREE_TYPE (res_op0)");
@@ -2953,12 +3125,12 @@ dt_simplify::gen_1 (FILE *f, int indent,
 	      /* Re-fold the toplevel result.  Use non_lvalue to
 	         build NON_LVALUE_EXPRs so they get properly
 		 ignored when in GIMPLE form.  */
-	      if (*e->operation == NON_LVALUE_EXPR)
+	      if (*opr == NON_LVALUE_EXPR)
 		fprintf_indent (f, indent,
 				"res = non_lvalue_loc (loc, res_op0);\n");
 	      else
 		{
-		  if (e->operation->kind == id_base::CODE)
+		  if (is_a <operator_id *> (opr))
 		    fprintf_indent (f, indent,
 				    "res = fold_build%d_loc (loc, %s, type",
 				    e->ops.length (),
@@ -3040,7 +3212,10 @@ dt_simplify::gen (FILE *f, int indent, b
       if (gimple)
 	{
 	  fprintf_indent (f, indent, "if (%s (res_code, res_ops, seq, "
-			  "valueize, type, captures))\n", info->fname);
+			  "valueize, type, captures", info->fname);
+	  for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
+	    fprintf (f, ", %s", s->for_subst_vec[i].second->id);
+	  fprintf (f, "))\n");
 	  fprintf_indent (f, indent, "  return true;\n");
 	}
       else
@@ -3049,12 +3224,30 @@ dt_simplify::gen (FILE *f, int indent, b
 			  info->fname);
 	  for (unsigned i = 0; i < as_a <expr *> (s->match)->ops.length (); ++i)
 	    fprintf (f, ", op%d", i);
-	  fprintf (f, ", captures);\n");
+	  fprintf (f, ", captures");
+	  for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
+	    fprintf (f, ", %s", s->for_subst_vec[i].second->id);
+	  fprintf (f, ");\n");
 	  fprintf_indent (f, indent, "if (res) return res;\n");
 	}
     }
   else
-    gen_1 (f, indent, gimple, s->result);
+    {
+      for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
+	{
+	  if (is_a <operator_id *> (s->for_subst_vec[i].second))
+	    fprintf_indent (f, indent, "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, "enum built_in_function %s = %s;\n",
+			    s->for_subst_vec[i].first->id,
+			    s->for_subst_vec[i].second->id);
+	  else
+	    gcc_unreachable ();
+	}
+      gen_1 (f, indent, gimple, s->result);
+    }
 
   indent -= 2;
   fprintf_indent (f, indent, "}\n");
@@ -3184,7 +3377,7 @@ decision_tree::gen (FILE *f, bool gimple
 		 "                 gimple_seq *seq, tree (*valueize)(tree) "
 		 "ATTRIBUTE_UNUSED,\n"
 		 "                 tree ARG_UNUSED (type), tree *ARG_UNUSED "
-		 "(captures))\n",
+		 "(captures)\n",
 		 s->fname);
       else
 	{
@@ -3194,10 +3387,19 @@ decision_tree::gen (FILE *f, bool gimple
 	  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 *captures)\n");
+	  fprintf (f, " tree *captures\n");
+	}
+      for (unsigned i = 0; i < s->s->s->for_subst_vec.length (); ++i)
+	{
+	  if (is_a <operator_id *> (s->s->s->for_subst_vec[i].second))
+	    fprintf (f, ", 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, ", enum built_in_function ARG_UNUSED (%s)",
+		     s->s->s->for_subst_vec[i].first->id);
 	}
 
-      fprintf (f, "{\n");
+      fprintf (f, ")\n{\n");
       s->s->gen_1 (f, 2, gimple, s->s->s->result);
       if (gimple)
 	fprintf (f, "  return false;\n");
Index: gcc/match.pd
===================================================================
--- gcc/match.pd	(revision 226490)
+++ gcc/match.pd	(working copy)
@@ -945,7 +985,7 @@ (define_operator_list CBRT BUILT_IN_CBRT
      (if (low >= prec)
       (if (op == LROTATE_EXPR || op == RROTATE_EXPR)
        (op @0 { build_int_cst (TREE_TYPE (@1), low % prec); })
-       (if (TYPE_UNSIGNED (type) || code == LSHIFT_EXPR)
+       (if (TYPE_UNSIGNED (type) || op == LSHIFT_EXPR)
         { build_zero_cst (type); }
         (op @0 { build_int_cst (TREE_TYPE (@1), prec - 1); })))
       (op @0 { build_int_cst (TREE_TYPE (@1), low); })))))))
@@ -1955,7 +2027,7 @@ (define_operator_list CBRT BUILT_IN_CBRT
   (cmp @0 REAL_CST@1)
   (if (REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
        && (cmp != LTGT_EXPR || ! flag_trapping_math))
-   { constant_boolean_node (cmp == ORDERED_EXPR || code == LTGT_EXPR
+   { constant_boolean_node (cmp == ORDERED_EXPR || cmp == LTGT_EXPR
 			    ? false : true, type); })))
 
 /* bool_var != 0 becomes bool_var.  */
@@ -2020,6 +2092,8 @@ (define_operator_list CBRT BUILT_IN_CBRT
 	   x = build_real (type, dconst10);
 	 }
          break;
+       default:
+	 gcc_unreachable ();
        }
      }
     (mult (logs { x; }) @0))))
@@ -2042,6 +2116,8 @@ (define_operator_list CBRT BUILT_IN_CBRT
          x = build_real (type, real_value_truncate (TYPE_MODE (type),
 						    dconst_third ()));
          break;
+       default:
+	 gcc_unreachable ();
        }
      }
     (mult { x; } (logs @0)))))


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