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

Reply via email to