[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