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?

Thanks,
Richard.

2014-08-15  Richard Biener  <rguent...@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        (revision 214018)
+++ gcc/match.pd        (working copy)
@@ -113,6 +113,21 @@ along with GCC; see the file COPYING3.
 #include "match-builtin.pd"
 #include "match-constant-folding.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 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.  */)
+
+
 /* ????s
 
    We cannot reasonably match vector CONSTRUCTORs or vector constants
Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c   (revision 214018)
+++ gcc/gimple-fold.c   (working copy)
@@ -1335,6 +1335,80 @@ gimple_fold_builtin_memset (gimple_stmt_
   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 (*valueize)(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   (revision 214018)
+++ gcc/gimple-fold.h   (working copy)
@@ -121,4 +121,10 @@ tree gimple_simplify (enum built_in_func
 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     (revision 214018)
+++ gcc/gimple-match-head.c     (working copy)
@@ -268,6 +268,31 @@ gimple_resimplify3 (gimple_seq *seq,
   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
@@ -742,3 +767,4 @@ do_valueize (tree (*valueize)(tree), tre
     return valueize (op);
   return op;
 }
+
Index: gcc/genmatch.c
===================================================================
--- gcc/genmatch.c      (revision 214018)
+++ gcc/genmatch.c      (working copy)
@@ -822,7 +822,8 @@ void
 check_no_user_id (simplify *s)
 {
   check_no_user_id (s->match);
-  check_no_user_id (s->result);
+  if (s->result)
+    check_no_user_id (s->result);
 }
 
 /* Code gen off the AST.  */
@@ -1674,6 +1675,8 @@ dt_simplify::gen_gimple (FILE *f)
     }
       output_line_directive (f, s->result_location);
 
+      if (s->result)
+       {
       if (s->result->type == operand::OP_EXPR)
        {
          expr *e = static_cast <expr *> (s->result);
@@ -1697,6 +1700,15 @@ dt_simplify::gen_gimple (FILE *f)
        }
       else
        gcc_unreachable ();
+       }
+      else
+       {
+         /* ???  We 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");
+       }
 
       fprintf (f, "return true;\n");
       if (s->ifexpr_vec != vNULL)
@@ -1954,7 +1966,8 @@ write_header (FILE *f, vec<simplify *>&
 
   /* Outline complex C expressions to helper functions.  */
   for (unsigned i = 0; i < simplifiers.length (); ++i)
-    outline_c_exprs (stdout, simplifiers[i]->result);
+    if (simplifiers[i]->result)
+      outline_c_exprs (stdout, simplifiers[i]->result);
 }
 
 
@@ -2283,8 +2296,12 @@ parse_simplify (cpp_reader *r, source_lo
   operand *ifexpr = parse_c_expr (r, CPP_OPEN_PAREN);
   eat_token (r, CPP_CLOSE_PAREN);
 
-  result_loc = peek (r)->src_loc;
-  simplify *s = new simplify (id, match, match_location, parse_op (r), 
result_loc);
+  token = peek (r);
+  result_loc = token->src_loc;
+  operand *result = NULL;
+  if (token->type != CPP_CLOSE_PAREN)
+    result = parse_op (r);
+  simplify *s = new simplify (id, match, match_location, result, result_loc);
   s->ifexpr_vec.safe_push (ifexpr);
   return s;
 }

Reply via email to