On Mon, 18 Aug 2014, Prathamesh Kulkarni wrote: > On Fri, Aug 15, 2014 at 6:18 PM, Richard Biener <rguent...@suse.de> 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. */) > > > Essentially we are forwarding transform code-gen to gimple_simplify_memset ? > I was wondering for such functions, > would it be a good idea to mark them with some symbol (say %) ? > > for eg, the above pattern would be written as: > > (define_forward_fn gimple_simplify_memset 3) > // forward transform code-gen to gimple_simplify_memset which expects 3 > operands > > (simplify > (BUILT_IN_MEMSET (addr@1 @4) INTEGER_CST_P@2 tree_fits_uhwi_p@3) > (%gimple_simplify_memset @1 @2 @3)) > > gimple_simplify would auto-forward the remaining arguments (res, > res_code, res_ops, etc.) > to gimple_simplify_memset.
The issue with the above is that it would parse as the "result" and thus the "result" expression now can magically fail... I thought about doing (if (gimple_simplify_memset (@1, @2, @3, @@)) thus having a "special" @@ that will append the boilerplate arguments. But both are only to make the syntax prettier. I also thought about allowing implicit compound expressions (aka C comma operator) with using sth like (simplify (BUILT_IN_MEMSET @1 @2 @3) ((= (mem_ref @1 0) @2) @1)) well, simplified of course. That is, the result may be a list of expressions and we introduce some magic new operator that allows generating an assigment. Similarly for a hypothetical call "simplifier" that does (simplify (BUILT_IN_FOO @1) ((BUILT_IN_FOO_SIDE_EFFECTS @1) (BUILT_IN_BAR @1))) at the moment emitting a sequence of statements is the #1 reason for using "manual simplifiers". Eventually the assignment could be done as c_expr (simplify (BUILT_IN_MEMSET @1 @2 @3) ({ 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); } @1)) but that accesses the magic 'seq' and the c_expr wouldn't have a "result". If we restrict all this to GIMPLE then we could require all but the last "stmts" in the list of expressions to evaluate to a statement and code-gen the add to the sequence. But then you'd want to have common variables in the if-expr and result c_exprs ... Which is why I proposed it in the awkward (but most powerful and generic) way. Richard. > > Thanks, > Prathamesh > > > 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; > > } > > -- Richard Biener <rguent...@suse.de> SUSE / SUSE Labs SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 GF: Jeff Hawn, Jennifer Guild, Felix Imend"orffer