[PATCH][RFC][match-and-simplify] "Manually" written patterns

Richard Biener rguenther@suse.de
Thu Aug 21 12:27:00 GMT 2014


On Fri, 15 Aug 2014, Richard Biener wrote:

> 
> The following introduces "manually" written patterns.  That is,
> part of the matching and the transform are fully manual.  An
> example where this is necessary is when the result isn't really
> an "expression" but a series of statements.
> 
> For example take simplifications of the memset builtin.  With
> the proposal we coud write
> 
> (simplify
>   (BUILT_IN_MEMSET @1 @2 integer_zerop)
>   @1)
> (simplify
>   (BUILT_IN_MEMSET (addr@1 @4) INTEGER_CST_P@2 tree_fits_uhwi_p@3)
>   (if (gimple_simplify_memset (@1, @2, @3, res_code, res_ops, seq, 
> valueize)))
>   /* Note "result" intentionally omitted.  The predicate if applying is
>      supposed to have populated *res_code and *res_ops and seq.  */)
> 
> covering the zero-length case with a regular pattern and the rest
> with a if-expr predicate that also does the transform.  Note
> that parts of the argument constraining is done via regular
> matching predicates and the pattern is inserted into the decision
> tree as usual.
> 
> How gimple_simplify_memset looks like is visible in the patch.
> 
> Note that this exposes the implementation details of the _GIMPLE_
> code-path (so the above doesn't even apply to GENERIC - luckily
> I've not implemented builtin function simplification for GENERIC
> so the above doesn't fall over ;)).
> 
> The syntax for the trailing args could be made nicer, but we use
> 'type' freely as well.
> 
> It clearly "abuses" (if ...) but it fits kind-of well.  Makes
> simply omitting the result pattern in a regular simplify
> fail in interesting ways though...
> 
> Caveat: runs into the issue that it's not possible to
> query the number of arguments to a function (thus no
> re-simplification yet).  I can lookup the decl for the
> builtin and parse its DECL_ARGUMENTS, but well...
> Similar issue exists when parsing built-in calls,
> we can't error on not enough arguments.
> 
> Status: it builds.
> 
> Comments?

No changes but updated patch.  As the important part is being
able to re-simplify calls so we can continue to stage
sprintf_chk -> sprintf -> memcpy I still need to figure out
the best way doing that and implement example patterns exercising
this.

I also need to merge from trunk so I can re-order the
match-and-simplify transform to happen before the rest in
fold_stmt.

Richard.

2014-08-15  Richard Biener  <rguenther@suse.de>

	* match.pd: Add example memset simplification with manual
	implemented part.
	* gimple-fold.c (gimple_simplify_memset): New function.
	* gimple-fold.h (gimple_simplify_memset): Declare.
	* gimple-match-head.c (gimple_resimplify): New function.
	* genmatch.c (check_no_user_id): Guard against NULL result.
	(write_header): Likewise.
	(dt_simplify::gen_gimple): Deal with NULL result.
	(parse_simplify): Allow missing result.

Index: gcc/match.pd
===================================================================
*** gcc/match.pd.orig	2014-08-21 13:54:41.787051398 +0200
--- gcc/match.pd	2014-08-21 14:11:56.196980181 +0200
*************** along with GCC; see the file COPYING3.
*** 127,132 ****
--- 127,150 ----
  #include "match-constant-folding.pd"
  #include "match-comparison.pd"
  
+ 
+ /* "Manual" simplifications but still in the decision tree.
+    Allows us to strip off "easy" parts and (parts of) the
+    pattern/predicate matching.  */
+ 
+ (simplify
+   (BUILT_IN_MEMSET @1 @2 @3)
+   /* Size zero memset simplifies to the destination pointer.  */
+   (if (integer_zerop (@3))
+    @1)
+   (if (TREE_CODE (@1) == ADDR_EXPR
+        && TREE_CODE (@2) == INTEGER_CST
+        && tree_fits_uhwi_p (@3)
+        && gimple_simplify_memset (@1, @2, @3, res_code, res_ops, seq, valueize))
+    /* Note "result" intentionally omitted.  The predicate if applying is
+       supposed to have populated *res_code and *res_ops and seq.  */))
+ 
+ 
  /* ????s
  
     We cannot reasonably match vector CONSTRUCTORs or vector constants
Index: gcc/gimple-fold.c
===================================================================
*** gcc/gimple-fold.c.orig	2014-08-21 13:54:41.801051398 +0200
--- gcc/gimple-fold.c	2014-08-21 14:16:46.148960218 +0200
*************** gimple_fold_builtin_memset (gimple_stmt_
*** 1335,1340 ****
--- 1335,1414 ----
    return true;
  }
  
+ /* Manual simplification example.
+    Fold function call to builtin memset or bzero setting the
+    memory of size LEN to VAL.  Return whether a simplification was made.  */
+ 
+ bool
+ gimple_simplify_memset (tree dest, tree c, tree len,
+ 			code_helper *res_code, tree *res_ops,
+ 			gimple_seq *seq, tree (*)(tree))
+ {
+   tree etype;
+   unsigned HOST_WIDE_INT length, cval;
+ 
+   if (!seq)
+     return false;
+ 
+   /* If the LEN parameter is zero, this is handled by another pattern.
+      But as they are only differing in predicates we can still arrive
+      here (there isn't a integer_nonzerop).  */
+   if (integer_zerop (len))
+     return false;
+ 
+   gcc_assert (tree_fits_uhwi_p (len));
+ 
+   gcc_assert (TREE_CODE (c) == INTEGER_CST);
+ 
+   tree var = dest;
+   gcc_assert (TREE_CODE (var) == ADDR_EXPR);
+ 
+   var = TREE_OPERAND (var, 0);
+   if (TREE_THIS_VOLATILE (var))
+     return false;
+ 
+   etype = TREE_TYPE (var);
+   if (TREE_CODE (etype) == ARRAY_TYPE)
+     etype = TREE_TYPE (etype);
+ 
+   if (!INTEGRAL_TYPE_P (etype)
+       && !POINTER_TYPE_P (etype))
+     return false;
+ 
+   if (! var_decl_component_p (var))
+     return false;
+ 
+   length = tree_to_uhwi (len);
+   if (GET_MODE_SIZE (TYPE_MODE (etype)) != length
+       || get_pointer_alignment (dest) / BITS_PER_UNIT < length)
+     return false;
+ 
+   if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT)
+     return false;
+ 
+   if (integer_zerop (c))
+     cval = 0;
+   else
+     {
+       if (CHAR_BIT != 8 || BITS_PER_UNIT != 8 || HOST_BITS_PER_WIDE_INT > 64)
+ 	return NULL_TREE;
+ 
+       cval = TREE_INT_CST_LOW (c);
+       cval &= 0xff;
+       cval |= cval << 8;
+       cval |= cval << 16;
+       cval |= (cval << 31) << 1;
+     }
+ 
+   var = fold_build2 (MEM_REF, etype, dest, build_int_cst (ptr_type_node, 0));
+   gimple store = gimple_build_assign (var, build_int_cst_type (etype, cval));
+   gimple_seq_add_stmt_without_update (seq, store);
+   *res_code = TREE_CODE (dest);
+   res_ops[0] = dest;
+ 
+   return true;
+ }
+ 
  
  /* Return the string length, maximum string length or maximum value of
     ARG in LENGTH.
Index: gcc/gimple-fold.h
===================================================================
*** gcc/gimple-fold.h.orig	2014-08-21 13:54:41.813051397 +0200
--- gcc/gimple-fold.h	2014-08-21 13:54:43.813051259 +0200
*************** tree gimple_simplify (enum built_in_func
*** 139,142 ****
--- 139,148 ----
  tree gimple_simplify (enum built_in_function, tree, tree, tree, tree,
  		      gimple_seq *, tree (*)(tree));
  
+ /* Manual simplifiers.  */
+ class code_helper;
+ bool gimple_simplify_memset (tree dest, tree c, tree len,
+ 			     code_helper *res_code, tree *res_ops,
+ 			     gimple_seq *seq, tree (*valueize)(tree));
+ 
  #endif  /* GCC_GIMPLE_FOLD_H */
Index: gcc/gimple-match-head.c
===================================================================
*** gcc/gimple-match-head.c.orig	2014-08-21 13:54:41.813051397 +0200
--- gcc/gimple-match-head.c	2014-08-21 13:54:43.813051259 +0200
*************** gimple_resimplify3 (gimple_seq *seq,
*** 266,271 ****
--- 266,296 ----
    return canonicalized;
  }
  
+ static bool
+ gimple_resimplify (gimple_seq *seq,
+ 		   code_helper *res_code, tree type, tree *res_ops,
+ 		   tree (*valueize)(tree))
+ {
+   if (res_code->is_tree_code ())
+     {
+       switch (TREE_CODE_LENGTH ((tree_code) *res_code))
+ 	{
+ 	case 1:
+ 	  return gimple_resimplify1 (seq, res_code, type, res_ops, valueize);
+ 	case 2:
+ 	  return gimple_resimplify2 (seq, res_code, type, res_ops, valueize);
+ 	case 3:
+ 	  return gimple_resimplify3 (seq, res_code, type, res_ops, valueize);
+ 	default:
+ 	  return false;
+ 	}
+     }
+   else
+     {
+       /* ??? */
+       return false;
+     }
+ }
  
  /* Push the exploded expression described by RCODE, TYPE and OPS
     as a statement to SEQ if necessary and return a gimple value
Index: gcc/genmatch.c
===================================================================
*** gcc/genmatch.c.orig	2014-08-21 13:54:41.815051397 +0200
--- gcc/genmatch.c	2014-08-21 14:02:49.648017810 +0200
*************** void
*** 855,861 ****
  check_no_user_id (simplify *s)
  {
    check_no_user_id (s->match);
!   check_no_user_id (s->result);
  }
  
  /* Code gen off the AST.  */
--- 855,862 ----
  check_no_user_id (simplify *s)
  {
    check_no_user_id (s->match);
!   if (s->result)
!     check_no_user_id (s->result);
  }
  
  /* Code gen off the AST.  */
*************** dt_simplify::gen (FILE *f, bool gimple)
*** 1726,1732 ****
  
    if (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);
--- 1727,1743 ----
  
    if (gimple)
      {
!       if (!s->result)
! 	{
! 	  /* If there is no result then a previous if-expression
! 	     has populated res_ops and res_code.
! 	     ???  e can't statically determine which of the
! 	     n-ary gimple_resimplify routines to call so call
! 	     a dispatcher.  */
! 	  fprintf (f, "gimple_resimplify (seq, res_code, type, "
! 		   "res_ops, valueize);\n");
! 	}
!       else if (s->result->type == operand::OP_EXPR)
  	{
  	  expr *e = static_cast <expr *> (s->result);
  	  fprintf (f, "*res_code = %s;\n", e->operation->op->id);
*************** dt_simplify::gen (FILE *f, bool gimple)
*** 1753,1758 ****
--- 1764,1771 ----
      }
    else /* GENERIC */
      {
+       /* Manual matchers are not supported in GENERIC.  */
+       gcc_assert (s->result);
        if (s->result->type == operand::OP_EXPR)
  	{
  	  expr *e = static_cast <expr *> (s->result);
*************** write_header (FILE *f, vec<simplify *>&
*** 1938,1944 ****
  
    /* Outline complex C expressions to helper functions.  */
    for (unsigned i = 0; i < simplifiers.length (); ++i)
!     outline_c_exprs (stdout, simplifiers[i]->result);
  }
  
  
--- 1951,1958 ----
  
    /* Outline complex C expressions to helper functions.  */
    for (unsigned i = 0; i < simplifiers.length (); ++i)
!     if (simplifiers[i]->result)
!       outline_c_exprs (stdout, simplifiers[i]->result);
  }
  
  
*************** parse_simplify (cpp_reader *r, source_lo
*** 2283,2293 ****
--- 2297,2314 ----
      {
        if (token->type == CPP_OPEN_PAREN)
  	{
+ 	  source_location paren_loc = token->src_loc;
  	  eat_token (r, CPP_OPEN_PAREN);
  	  if (peek_ident (r, "if"))
  	    {
  	      eat_ident (r, "if");
  	      ifexprs.safe_push (parse_c_expr (r, CPP_OPEN_PAREN));
+ 	      /* If this if is immediately closed then it contains a
+ 	         manual matcher.  Push it.  */
+ 	      if (peek (r)->type == CPP_CLOSE_PAREN)
+ 	        simplifiers.safe_push
+ 		    (new simplify (id, match, match_location, NULL,
+ 				   paren_loc, copy_reverse (ifexprs)));
  	    }
  	  else
  	    {
*************** parse_for (cpp_reader *r, source_locatio
*** 2382,2388 ****
  	    {
  	      simplify *s = for_simplifiers[j];
  	      operand *match_op = replace_id (s->match, user_id, opers[i]);
! 	      operand *result_op = replace_id (s->result, user_id, opers[i]);
  	      vec<operand *> ifexpr_vec = vNULL;
  	      for (unsigned j = 0; j < s->ifexpr_vec.length (); ++j)
  		ifexpr_vec.safe_push (replace_id (s->ifexpr_vec[j], user_id, opers[i]));
--- 2403,2409 ----
  	    {
  	      simplify *s = for_simplifiers[j];
  	      operand *match_op = replace_id (s->match, user_id, opers[i]);
! 	      operand *result_op = s->result ? replace_id (s->result, user_id, opers[i]) : NULL;
  	      vec<operand *> ifexpr_vec = vNULL;
  	      for (unsigned j = 0; j < s->ifexpr_vec.length (); ++j)
  		ifexpr_vec.safe_push (replace_id (s->ifexpr_vec[j], user_id, opers[i]));



More information about the Gcc-patches mailing list