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


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

Re: [PATCH][match-and-simplify] Hande side-effects in GENERIC


On Wed, 22 Oct 2014, Richard Biener wrote:

> 
> The following auto-handles preserving of side-effects properly
> for GENERIC simplification instead of simply rejecting operands
> with side-effects.  Cases we cannot handle correctly are still
> handled that way.
> 
> For example for
> 
> /* (x | CST1) & CST2 -> (x & CST2) | (CST1 & CST2) */
> (simplify
>   (bit_and (bit_ior @0 CONSTANT_CLASS_P@1) CONSTANT_CLASS_P@2)
>   (bit_ior (bit_and @0 @2) (bit_and @1 @2)))
> 
> we generate
> 
> captures[0] = o20;
> captures[1] = o21;
> captures[2] = op1;
> if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Applying 
> pattern match-bitwise.pd:59, %s:%d\n", __FILE__, __LINE__);
>   if (TREE_SIDE_EFFECTS (captures[2]))
>     captures[2] = save_expr (captures[2]);
> ...
>   res = fold_build2_loc (loc, BIT_IOR_EXPR, type, res_op0, res_op1);
>   return res;
> 
> of course somewhat pointless for CONSTANT_CLASS_P @2 (but well...).
> 
> For example for
> 
> (simplify
>   (minus @0 @0)
>   (if (!FLOAT_TYPE_P (type) || !HONOR_NANS (TYPE_MODE (type)))
>    { build_zero_cst (type); }))
> 
> we generate
> 
> captures[0] = op0;
> /* #line 48 "/space/rguenther/src/svn/match-and-simplify/gcc/match.pd" */
> if (!FLOAT_TYPE_P (type) || !HONOR_NANS (TYPE_MODE (type)))
>   {
>     if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, 
> "Applying pattern match.pd:49, %s:%d\n", __FILE__, __LINE__);
>     tree res;
>     res =  build_zero_cst (type);
>     if (TREE_SIDE_EFFECTS (captures[0]))
>       res = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (captures[0]), 
> fold_ignored_result (captures[0]), res);

Just noticed wrong type used here, fixed to do

 res = build2_loc (loc, COMPOUND_EXPR, type, fold_ignored_result (captures[0]), res);

Richard.

>     return res;
>   }
> 
> I chose to open-code omit_N_operands.
> 
> For example for
> 
> (simplify
>   (cond (bit_not @0) @1 @2)
>   (cond @0 @2 @1))
> 
> we generate
> 
> captures[0] = o20;
> captures[1] = op1;
> captures[2] = op2;
> if (TREE_SIDE_EFFECTS (op0) || TREE_SIDE_EFFECTS (op1) || 
> TREE_SIDE_EFFECTS (op2)) return NULL_TREE;
> if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Applying 
> pattern match.pd:207, %s:%d\n", __FILE__, __LINE__);
> tree res_op0;
> res_op0 = captures[0];
> tree res_op1;
> res_op1 = captures[2];
> tree res_op2;
> res_op2 = captures[1];
> tree res;
> res = fold_build3_loc (loc, COND_EXPR, type, res_op0, res_op1, res_op2);
>   return res;
> 
> thus give up if any operand of the outer expression has side effects.
> 
> We currently give up for conditionally executed side-effects and
> for C expressions in transforms that mention any captures (we
> don't understand if they constitute a substitution into the
> result).  I also give up if captured expressions are substituted
> (they would make captures inside that expression used) and if
> the replacement contains CSEs.  We could fix the latter two cases
> if required.
> 
> Bootstrap and regtest running on x86_64-unknown-linux-gnu.
> 
> Richard.
> 
> 2014-10-22  Richard Biener  <rguenther@suse.de>
> 
> 	* genmatch.c (count_captures): New function.
> 	(dt_simplify::gen): Handle preserving side-effects for
> 	GENERIC code generation.
> 	(decision_tree::gen_generic): Do not reject operands
> 	with TREE_SIDE_EFFECTS.
> 
> Index: gcc/genmatch.c
> ===================================================================
> --- gcc/genmatch.c	(revision 216549)
> +++ gcc/genmatch.c	(working copy)
> @@ -1861,6 +1861,46 @@ dt_operand::gen (FILE *f, bool gimple)
>      fprintf (f, "}\n");
>  }
>  
> +/* Count how many times captures are substituted in O and put the
> +   result in the array of counters CPT.  Return false if the
> +   counting isn't precise.  */
> +
> +static bool
> +count_captures (operand *o, int *cpt)
> +{
> +  if (capture *c = dyn_cast <capture *> (o))
> +    {
> +      /* Give up for non-leafs (CSEs).  */
> +      if (c->what)
> +	return false;
> +      cpt[c->where]++;
> +    }
> +  else if (expr *e = dyn_cast <expr *> (o))
> +    {
> +      /* Give up for conditionally executed operands.  */
> +      if (*e->operation == COND_EXPR
> +	  || *e->operation == TRUTH_ANDIF_EXPR
> +	  || *e->operation == TRUTH_ORIF_EXPR)
> +	return false;
> +      for (unsigned i = 0; i < e->ops.length (); ++i)
> +	if (!count_captures (e->ops[i], cpt))
> +	  return false;
> +    }
> +  else if (c_expr *e = dyn_cast <c_expr *> (o))
> +    {
> +      /* Give up for C exprs mentioning captures.  */
> +      for (unsigned i = 0; i < e->code.length (); ++i)
> +	if (e->code[i].type == CPP_ATSIGN
> +	    && (e->code[i+1].type == CPP_NUMBER
> +		|| e->code[i+1].type == CPP_NAME)
> +	    && !(e->code[i+1].flags & PREV_WHITE))
> +	  return false;
> +    }
> +  else
> +    gcc_unreachable ();
> +  return true;
> +}
> +
>  /* Generate code for the '(if ...)', '(with ..)' and actual transform
>     step of a '(simplify ...)' or '(match ...)'.  This handles everything
>     that is not part of the decision tree (simplify->match).  */
> @@ -1929,6 +1969,25 @@ dt_simplify::gen (FILE *f, bool gimple)
>        n_braces++;
>      }
>  
> +  /* 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.  Try to compute the number
> +     of times an expression is substituted.  */
> +  int *cpt = XALLOCAVEC (int, s->capture_max + 1);
> +  memset (cpt, 0, sizeof (int) * (s->capture_max + 1));
> +  if (!gimple
> +      && s->result
> +      && !count_captures (s->result, cpt))
> +    {
> +      /* Oops.  We could not get an exact count - give up and simply
> +         reject the pattern if any input operand had side-effects.  */
> +      fprintf (f, "if (TREE_SIDE_EFFECTS (op0)");
> +      for (unsigned i = 1; i < as_a <expr *> (s->match)->ops.length (); ++i)
> +	fprintf (f, " || TREE_SIDE_EFFECTS (op%u)", i);
> +      fprintf (f, ") return NULL_TREE;\n");
> +      cpt[0] = -1;
> +    }
> +
>    fprintf (f, "if (dump_file && (dump_flags & TDF_DETAILS)) "
>  	   "fprintf (dump_file, \"Applying pattern ");
>    output_line_directive (f, s->result_location, true);
> @@ -1983,10 +2042,21 @@ dt_simplify::gen (FILE *f, bool gimple)
>      }
>    else /* GENERIC */
>      {
> +      bool is_predicate = false;
>        if (result->type == operand::OP_EXPR)
>  	{
>  	  expr *e = as_a <expr *> (result);
> -	  bool is_predicate = is_a <predicate_id *> (e->operation);
> +	  is_predicate = is_a <predicate_id *> (e->operation);
> +	  /* Search for captures used multiple times in the result expression
> +	     and dependent on TREE_SIDE_EFFECTS emit a SAVE_EXPR.  */
> +	  if (!is_predicate && cpt[0] != -1)
> +	    for (int i = 0; i < s->capture_max + 1; ++i)
> +	      {
> +		if (cpt[i] > 1)
> +		  fprintf (f, "  if (TREE_SIDE_EFFECTS (captures[%d]))\n"
> +			   "    captures[%d] = save_expr (captures[%d]);\n",
> +			   i, i, i);
> +	      }
>  	  for (unsigned j = 0; j < e->ops.length (); ++j)
>  	    {
>  	      char dest[32];
> @@ -2004,22 +2074,23 @@ dt_simplify::gen (FILE *f, bool gimple)
>  				    ? NULL : "TREE_TYPE (res_op0)");
>  	      e->ops[j]->gen_transform (f, dest, false, 1, optype, indexes);
>  	    }
> -	  if (is_a <predicate_id *> (e->operation))
> +	  if (is_predicate)
>  	    fprintf (f, "return true;\n");
>  	  else
>  	    {
> +	      fprintf (f, "  tree res;\n");
>  	      /* 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)
> -		fprintf (f, "  return non_lvalue_loc (loc, res_op0);\n");
> +		fprintf (f, "  res = non_lvalue_loc (loc, res_op0);\n");
>  	      else
>  		{
>  		  if (e->operation->kind == id_base::CODE)
> -		    fprintf (f, "  return fold_build%d_loc (loc, %s, type",
> +		    fprintf (f, "  res = fold_build%d_loc (loc, %s, type",
>  			     e->ops.length (), e->operation->id);
>  		  else
> -		    fprintf (f, "  return build_call_expr_loc "
> +		    fprintf (f, "  res = build_call_expr_loc "
>  			     "(loc, builtin_decl_implicit (%s), %d",
>  			     e->operation->id, e->ops.length());
>  		  for (unsigned j = 0; j < e->ops.length (); ++j)
> @@ -2030,13 +2101,29 @@ dt_simplify::gen (FILE *f, bool gimple)
>  	}
>        else if (result->type == operand::OP_CAPTURE
>  	       || result->type == operand::OP_C_EXPR)
> +
>  	{
>  	  fprintf (f, "  tree res;\n");
>  	  s->result->gen_transform (f, " res", false, 1, "type", indexes);
> -	  fprintf (f, "  return res;\n");
>  	}
>        else
>  	gcc_unreachable ();
> +      if (!is_predicate)
> +	{
> +	  /* Search for captures not used in the result expression and dependent
> +	     on TREE_SIDE_EFFECTS emit omit_one_operand.  */
> +	  if (cpt[0] != -1)
> +	    for (int i = 0; i < s->capture_max + 1; ++i)
> +	      {
> +		if (cpt[i] == 0)
> +		  fprintf (f, "  if (TREE_SIDE_EFFECTS (captures[%d]))\n"
> +			   "    res = build2_loc (loc, COMPOUND_EXPR, "
> +			   "TREE_TYPE (captures[%d]), "
> +			   "fold_ignored_result (captures[%d]), res);\n",
> +			   i, i, i);
> +	      }
> +	  fprintf (f, "  return res;\n");
> +	}
>      }
>  
>    for (unsigned i = 0; i < n_braces; ++i)
> @@ -2107,18 +2194,6 @@ decision_tree::gen_generic (FILE *f)
>        fprintf (f, ")\n");
>        fprintf (f, "{\n");
>  
> -      /* ???  For now reject all simplifications on operands with
> -         side-effects as we are not prepared to properly wrap
> -	 omitted parts with omit_one_operand and friends.  In
> -	 principle we can do that automagically for a subset of
> -	 transforms (and only reject the remaining cases).
> -	 This fixes for example gcc.c-torture/execute/20050131-1.c.  */
> -      fprintf (f, "if ((op0 && TREE_SIDE_EFFECTS (op0))");
> -      for (unsigned i = 1; i < n; ++i)
> -	fprintf (f, "|| (op%d && TREE_SIDE_EFFECTS (op%d))", i, i);
> -      fprintf (f, ")\n"
> -	       "  return NULL_TREE;\n");
> -
>        fprintf (f, "switch (code)\n"
>  	       "{\n");
>        for (unsigned i = 0; i < root->kids.length (); i++)
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend"orffer


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