This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [GSoC] symbol to denote multiple operators


On Fri, Jul 11, 2014 at 8:29 PM, Prathamesh Kulkarni
<bilbotheelffriend@gmail.com> wrote:
> On 7/11/14, Richard Biener <richard.guenther@gmail.com> wrote:
>> On Thu, Jul 10, 2014 at 8:05 PM, Prathamesh Kulkarni
>> <bilbotheelffriend@gmail.com> wrote:
>>> Hi,
>>>    I have attempted to add syntax for symbol to denote multiple
>>> operators.
>>>
>>> I tried it with few bogus patterns and it appears to work.... hopefully
>>> -:)
>>> eg: (bogus pattern):
>>> (for op in plus minus
>>>   (match_and_simplify
>>>     (op @0 @1)
>>>     (op @0 @0)))
>>>
>>> generates following patterns:
>>> (plus @0 @1) -> (plus @0 @0)  // simplify_0
>>> (plus @0 @1) -> (mult @0 @0)  // simplify_1
>>> (mult @0 @1) -> (plus @0 @0)  // simplify_2
>>> (mult @0 @1) -> (mult @0 @0)  // simplify_3
>>
>> s/mult/minus/?  I think it should only generate
>>
>>  (plus @0 @1) -> (plus @0 @0)
>>  (minus @0 @1) -> (minus @0 @0)
>>
>> to get the what you write we should need to write
>>
>>  (for op1 in plus minus
>>    (for op2 in plus minus
>>      (match_and_simplify
>>         (op1 @0 @1)
>>         (op2 @0 @0))))
>>
>>> root (0xab6b10), 0, 2
>>> |--(PLUS_EXPR) (0xab6b30), 1, 1
>>> |----true (0xab6ba0), 2, 1
>>> |------true (0xab6c10), 3, 2
>>> |--------simplify_0 { 0xab6ba0, 0xab6c10, (nil), (nil),  }  (0xab6c80), 4,
>>> 0
>>> |--------simplify_1 { 0xab6ba0, 0xab6c10, (nil), (nil),  }  (0xab6d40), 4,
>>> 0
>>> |--(MULT_EXPR) (0xab6d00), 1, 1
>>> |----true (0xab6d90), 2, 1
>>> |------true (0xab6e00), 3, 2
>>> |--------simplify_2 { 0xab6d90, 0xab6e00, (nil), (nil),  }  (0xab6e70), 4,
>>> 0
>>> |--------simplify_3 { 0xab6d90, 0xab6e00, (nil), (nil),  }  (0xab6f30), 4,
>>> 0
>>>
>>> * Changes to rest of the code:
>>> a) commutating patterns was interfering with this, because
>>> parse_match_and_simplify, immediately commutated match operand. Symbol
>>> should be replaced by operators before commutating. This required
>>> adjusting simplify (back to operand *match), and commutating is done
>>> in new function lower_commutative. Ideally this should be done during
>>> insertion in decision tree ?
>>
>> Yes, commutating should be done by inserting a pattern multiple
>> times with adjusted AST walk order.
>>
>>> b) adjustments required to e_operation constructor, so it doesn't
>>> call fatal, when it does not find id to be in the hash table.
>>
>> Eventually just temporarily insert a new operator in the hash table
>> when parsing comes along a (for OP ...?  That is, add a new kind,
>> USER and just re-use base->id?
>>
>>> * Caveats
>>> a) new e_operation constructor taking id_base * argument. Not sure
>>> if that's required.
>>> b) e_operation::user_id denotes user-defined identifier (<opname>),
>>> a rather apologetic name ...
>>> c) Similar to commutate(), replace_user_id() does not clone AST's.
>>> So we have multiple AST's sharing same nodes.
>>
>> I wonder if we want to parse the 'for' into an AST node instead,
>> thus not expand it on-the-fly.  Applying could then happen during
>> DT insertion.  Or as a separate lowering like you introduce
>> lower_commutative - that looks  cleaner.
>>
>> Or if we can simply parse the match-and-simplify multiple times, with
>> the for op replaces, using _cpp_backup_tokens.  Ok, no - that
>> sounds like too much of a hack.
>>
>>> * add multiple symbols ?
>>> should we have
>>> (for <opname> in operator-list1, <opname2> in operator-list2
>>>   (match_and_simplify
>>>      ...))
>>> or have nested for ?
>>> (for <opname> in operator-list1
>>>    (for <opname2> in operator-list2
>>>        (match_and_simplify
>>>           ....)))
>>
>> It depends on the desired semantics.  It's a lot clearer with
>> single opname for only (but then we eventually need nested for).
>>
>>> * we don't detect functions with wrong arguments
>>> for example, we dont give error on:
>>> (built_in_sqrt @0 @1)
>>> I guess that's because we don't have an easy way to figure out
>>> number of arguments a function expects ?
>>> (is there a built-in equivalent of tree_code_length[] ?)
>>
>> Yeah, the function stuff is still very simplistic and no, there isn't
>> any easy way of extracting the number of expected arguments
>> from builtins.def (it's encoded in the type).  The easiest way
>> would be to change builtins.def to add a number-of-args argument ...
>>
>> Let's just defer that issue.
>>
>>
>> As for the patch, we shouldn't do the cartesian_product - that's
>> hardly ever what the user intends and it means there isn't any
>> way of repeating the same pattern for multiple operators.
>>
>> A common use for 'for' would be (for OP in ne eq (...)) as most
>> equality foldings are valid for ne and eq.  Another is
>> for the various division kinds we have - trunc_div ceil_div floor_div
>> and round_div (same for mod):
>>
>> (for op in trunc_div ceil_div floor_div round_div
>>   (match_and_simplify
>>      (op @0 integer_onep)
>>      @0))
>>
>> (good example for match.pd to exercise the code)
>>
>> Can you fix the cartesian product thing (it should only simplify the
>> patch)?
> This version of the patch, removes cartesian_product, and reuses
> id_base::id for user-defined symbols.
>
> eg:
> (for op in plus minus
>   (match_and_simplify
>     (op (op @0 @1) @2)
>     (op @0 @0)))
>
> generates following patterns:
> (plus (plus @0 @1) @2) -> (plus @0 @0)
> (minus (minus @0 @1) @2) -> (minus @0 @0)
> Is this correct ?
>
> I added the (for op in trunc_div floor_div ceil_div round_div ..)
> pattern in match.pd
> This works for trunc_div, I am not sure how to generate
> floor_div/ceil_div/round_div
> from C test-case.
>
> I added the following rotate pattern in match.pd:
> /* (x << CNT1) OP (x >> CNT2) -> x r<< CNT1 OP being +, |, ^ */
> (for op in plus bit_ior bit_xor
> (match_and_simplify
>   (op:c (lshift @0 INTEGER_CST_P@1) (rshift @0 INTEGER_CST_P@2))
>   if (tree_fits_uhwi_p (@1) && tree_fits_uhwi_p (@2)
>       && tree_to_uhwi (@1) + tree_to_uhwi (@2) == TYPE_PRECISION (type))
>   (lrotate @0 @1)))
>
> Is this correct ?
>
> * genmatch.c (id_base::id_kind): New enum value USER_DEFINED.
>     (e_operation::e_operation): Add default argument add_new_id.
>     (simplify): Remove member matchers.
>     (simplify): New member match.
>     (print_matches): Adjust to changes in simplify.
>     (decision_tree::insert): Likewise.
>     (parse_match_and_simplify): Likewise.
>     (lower_commutative): New function.
>     (check_operator): Likewise.
>     (replace_id): Likewise.
>     (eat_ident): Likewise.
>     (parse_for): Likewise.
>     (parse_expr): Call check_operator.
>     (main): Call parse_for, lower_commutative.
>
> * match.pd: Add pattern for div, and rotate pattern.
>
> [gcc/testsuite/gcc.dg/tree-ssa]
> * match-rotate.c: New test-case.
Added nested for, and adjusted few constant folding patterns in
match.pd to use for.
Unfortunately, I haven't been able to figure out how to generate
CEIL_DIV_EXPR, FLOOR_DIV_EXPR,
ROUND_DIV_EXPR, from a c test-case. I came across this link:
https://gcc.gnu.org/bugzilla/show_bug.cgi?format=multiple&id=46679
It says it's not possible to generate floor/ceil/round from C.
In that case how do we test for this (maybe another front-end
generates floor/ceil ?)

* genmatch.c (id_base::id_kind): Add new enum value USER_DEFINED.
  (e_operation::e_operation): New default argument add_new_id. Adjust
to add id in hash table.
  (simplify): Remove matchers member. New member match.
  (print_matches): Adjust to changes in simplify.
  (decision_tree::insert): Likewise.
  (lower_commutative): New function.
  (check_operator): Likewise.
  (replace_id): Likewise.
  (eat_ident): Likewise.
  (parse_for): Likewise.
  (parse_pattern): Likewise.
  (check_no_user_id): Likewise.
  (check_no_user_id): Likewise, overloaded to take simplify as first argument.
  (parse_expr): Call check_operator.
  (main): call parse_pattern, lower_commutative, check_no_user_id.

* match.pd: Adjust few constant folding patterns to use for.

[gcc/testsuite/gcc.dg/tree-ssa]
* match-rotate.c: New test-case.

Thanks and Regards,
Prathamesh
>
> Thanks and Regards,
> Prathamesh
>
>>
>> Thanks,
>> Richard.
>>
>>> * genmatch.c (e_operation::e_operation): New constructor.
>>> (e_operation::user_id): New member.
>>> (e_operation::get_op): New member function.
>>> (simplify::matchers): Remove.
>>> (simplify::match): New member.
>>> (lower_commutative): New function.
>>> (check_operator): Likewise.
>>> (replace_user_id): Likewise.
>>> (decision_tree::insert): Adjust to changes in simplify.
>>> (eat_ident): New function.
>>> (parse_expr): Call to check_operator.
>>> (parse_for): New function.
>>> (main): Add calls to parse_for, lower_commutative.
>>>
>>> Thanks and Regards,
>>> Prathamesh
>>
Index: gcc/genmatch.c
===================================================================
--- gcc/genmatch.c	(revision 212366)
+++ gcc/genmatch.c	(working copy)
@@ -116,7 +116,7 @@ END_BUILTINS
 
 struct id_base : typed_free_remove<id_base>
 {
-  enum id_kind { CODE, FN } kind;
+  enum id_kind { CODE, FN, USER_DEFINED } kind;
 
   id_base (id_kind, const char *);
 
@@ -135,6 +135,7 @@ id_base::hash (const value_type *op)
 {
   return op->hashval;
 }
+
 inline int
 id_base::equal (const value_type *op1,
 			const compare_type *op2)
@@ -169,6 +170,7 @@ struct fn_id : public id_base
   enum built_in_function fn;
 };
 
+
 static void
 add_operator (enum tree_code code, const char *id,
 	      const char *tcc, unsigned nargs)
@@ -217,7 +219,7 @@ struct predicate : public operand
 };
 
 struct e_operation {
-  e_operation (const char *id, bool is_commutative_ = false);
+  e_operation (const char *id, bool is_commutative_ = false, bool add_new_id = true);
   id_base *op;
   bool is_commutative;
 };
@@ -254,11 +256,10 @@ struct capture : public operand
   virtual void gen_transform (FILE *f, const char *, bool);
 };
 
-
-e_operation::e_operation (const char *id, bool is_commutative_)
+e_operation::e_operation (const char *id, bool is_commutative_, bool add_new_id)
 {
-  id_base tem (id_base::CODE, id);
   is_commutative = is_commutative_;
+  id_base tem (id_base::CODE, id);
 
   op = operators.find_with_hash (&tem, tem.hashval);
   if (op)
@@ -287,19 +288,23 @@ e_operation::e_operation (const char *id
       return;
     }
 
-  fatal ("expected operator, got %s", id);
+  if (add_new_id == false)
+    fatal ("%s is not an operator/built-in function", id);
+
+  op = new id_base (id_base::USER_DEFINED, id);
+  operators.find_slot_with_hash (op, op->hashval, INSERT);
 }
 
 struct simplify {
   simplify (const char *name_,
-	    vec<operand *> matchers_, source_location match_location_,
+	    operand *match_, source_location match_location_,
 	    struct operand *ifexpr_, source_location ifexpr_location_,
 	    struct operand *result_, source_location result_location_)
-      : name (name_), matchers (matchers_), match_location (match_location_),
+      : name (name_), match (match_), match_location (match_location_),
       ifexpr (ifexpr_), ifexpr_location (ifexpr_location_),
       result (result_), result_location (result_location_) {}
   const char *name;
-  vec<operand *> matchers;  // vector to hold commutative expressions
+  operand *match; 
   source_location match_location;
   struct operand *ifexpr;
   source_location ifexpr_location;
@@ -452,19 +457,9 @@ print_operand (operand *o, FILE *f = std
 void
 print_matches (struct simplify *s, FILE *f = stderr)
 {
-  if (s->matchers.length () == 1)
-    return;
-
   fprintf (f, "for expression: ");
-  print_operand (s->matchers[0], f);  // s->matchers[0] is equivalent to original expression
+  print_operand (s->match, f); 
   putc ('\n', f);
-
-  fprintf (f, "commutative expressions:\n");
-  for (unsigned i = 0; i < s->matchers.length (); ++i)
-    {
-      print_operand (s->matchers[i], f);
-      putc ('\n', f);
-    }
 }
 
 void
@@ -552,6 +547,104 @@ commutate (operand *op)
   return ret;
 }
 
+void
+lower_commutative (simplify *s, vec<simplify *>& simplifiers)
+{
+  vec<operand *> matchers = commutate (s->match);
+  for (unsigned i = 0; i < matchers.length (); ++i)
+    {
+      simplify *ns = new simplify (s->name, matchers[i], s->match_location,
+				   s->ifexpr, s->ifexpr_location,
+				   s->result, s->result_location);
+      simplifiers.safe_push (ns);
+    }
+}
+
+void
+check_operator (id_base *op, unsigned n_ops, const cpp_token *token = 0)
+{
+  if (!op)
+    return;
+
+  if (op->kind != id_base::CODE)
+    return;
+
+  operator_id *opr = static_cast<operator_id *> (op);
+  if (opr->get_required_nargs () == n_ops)
+    return;
+
+  if (token)
+    fatal_at (token, "%s expects %u operands, got %u operands", opr->id, opr->get_required_nargs (), n_ops);
+  else
+    fatal ("%s expects %u operands, got %u operands", opr->id, opr->get_required_nargs (), n_ops);
+}
+        
+operand *
+replace_id (operand *o, const char *user_id, const char *oper)
+{
+  if (o->type == operand::OP_CAPTURE)
+    {
+      capture *c = static_cast<capture *> (o);
+      if (!c->what)
+	return c;
+      capture *nc = new capture (c->where, replace_id (c->what, user_id, oper));
+      return nc;
+    }
+
+  if (o->type != operand::OP_EXPR)
+    return o;
+
+  expr *e = static_cast<expr *> (o);
+  expr *ne;
+
+  if (e->operation->op->kind == id_base::USER_DEFINED && strcmp (e->operation->op->id, user_id) == 0)
+    {
+      struct e_operation *operation = new e_operation (oper, e->operation->is_commutative, false);
+      check_operator (operation->op, e->ops.length ());
+      ne = new expr (operation);
+    }
+  else
+    ne = new expr (e->operation);
+
+  for (unsigned i = 0; i < e->ops.length (); ++i)
+    ne->append_op (replace_id (e->ops[i], user_id, oper));
+
+  return ne;
+}
+  
+void
+check_no_user_id (operand *o)
+{
+  if (o->type == operand::OP_CAPTURE)
+    {
+      capture *c = static_cast<capture *> (o);
+      if (c->what && c->what->type == operand::OP_EXPR)
+	{
+	  o = c->what;
+	  goto check_expr; 
+	}
+      return; 
+    }
+
+  if (o->type != operand::OP_EXPR)
+    return;
+
+check_expr:
+  expr *e = static_cast<expr *> (o);
+  if (e->operation->op->kind == id_base::USER_DEFINED)
+    fatal ("%s is not defined in for", e->operation->op->id);
+
+  for (unsigned i = 0; i < e->ops.length (); ++i)
+    check_no_user_id (e->ops[i]);
+}
+
+void
+check_no_user_id (simplify *s)
+{
+  check_no_user_id (s->match);
+  check_no_user_id (s->result);
+}
+
 /* Code gen off the AST.  */
 
 void
@@ -828,17 +921,14 @@ decision_tree::insert (struct simplify *
 {
   dt_operand *indexes[dt_simplify::capture_max];
 
-  for (unsigned i = 0; i < s->matchers.length (); ++i)
-    {
-      if (s->matchers[i]->type != operand::OP_EXPR)
-	continue;
+  if (s->match->type != operand::OP_EXPR)
+    return; 
 
-      for (unsigned j = 0; j < dt_simplify::capture_max; ++j)
-	indexes[j] = 0; 
+  for (unsigned j = 0; j < dt_simplify::capture_max; ++j)
+    indexes[j] = 0; 
 
-      dt_node *p = decision_tree::insert_operand (root, s->matchers[i], indexes);
-      p->append_simplify (s, pattern_no, indexes);
-    }            
+  dt_node *p = decision_tree::insert_operand (root, s->match, indexes);
+  p->append_simplify (s, pattern_no, indexes);
 }
 
 void
@@ -1707,6 +1797,16 @@ get_ident (cpp_reader *r)
   return (const char *)CPP_HASHNODE (token->val.node.node)->ident.str;
 }
 
+static void
+eat_ident (cpp_reader *r, const char *s)
+{
+  const cpp_token *token = expect (r, CPP_NAME);
+  const char *t = (const char *) CPP_HASHNODE (token->val.node.node)->ident.str;
+
+  if (strcmp (s, t)) 
+    fatal_at (token, "expected %s got %s\n", s, t);
+}
+
 /* Read the next token from R and assert it is of type CPP_NUMBER and
    return its value.  */
 
@@ -1735,6 +1835,7 @@ parse_capture (cpp_reader *r, operand *o
   return new capture (get_number (r), op);
 }
 
+
 /* Parse
      expr = (operation[capture] op...)  */
 static struct operand *
@@ -1774,13 +1875,7 @@ parse_expr (cpp_reader *r)
       const cpp_token *token = peek (r);
       if (token->type == CPP_CLOSE_PAREN)
 	{
-	  if (e->operation->op->kind == id_base::CODE)
-	    {
-	      operator_id *opr = static_cast <operator_id *> (e->operation->op);
-	      if (e->ops.length () != opr->get_required_nargs ())
-		fatal_at (token, "got %d operands instead of the required %d",
-			  e->ops.length (), opr->get_required_nargs ());
-	    }
+	  check_operator (e->operation->op, e->ops.length (), token); 
 	  if (is_commutative)
 	    {
 	      if (e->ops.length () == 2)
@@ -1877,6 +1972,7 @@ parse_op (cpp_reader *r)
   return op;
 }
 
+
 /* Parse
      (define_match_and_simplify "<ident>"
         <op> <op>)  */
@@ -1912,10 +2008,44 @@ parse_match_and_simplify (cpp_reader *r,
       ifexpr = parse_c_expr (r, CPP_OPEN_PAREN);
     }
   token = peek (r);
-  return new simplify (id, commutate (match), match_location,
+  return new simplify (id, match, match_location,
 		       ifexpr, ifexpr_location, parse_op (r), token->src_loc);
 }
 
+void
+parse_for (cpp_reader *r, source_location match_location, vec<simplify *>& simplifiers) 
+{
+  const char *user_id = get_ident (r);
+  eat_ident (r, "in");
+  void parse_pattern (cpp_reader *, vec<simplify *>&);
+
+  vec<const char *> opers = vNULL;
+
+  while (1)
+    {
+      const cpp_token *token = peek (r);
+      if (token->type != CPP_NAME)
+	break;
+      opers.safe_push (get_ident (r));
+    }
+
+  vec<simplify *> for_simplifiers = vNULL;
+  parse_pattern (r, for_simplifiers);
+
+  for (unsigned i = 0; i < opers.length (); ++i)
+    {
+      for (unsigned j = 0; j < for_simplifiers.length (); ++j)
+	{
+	  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]);
+	  simplify *ns = new simplify (s->name, match_op, s->match_location,
+				       s->ifexpr, s->ifexpr_location,
+				       result_op, s->result_location);
+	  simplifiers.safe_push (ns);
+	}
+    }
+}
 
 static size_t
 round_alloc_size (size_t s)
@@ -1923,6 +2053,23 @@ round_alloc_size (size_t s)
   return s;
 }
 
+void
+parse_pattern (cpp_reader *r, vec<simplify *>& simplifiers)
+{
+  /* All clauses start with '('.  */
+  eat_token (r, CPP_OPEN_PAREN);
+  const cpp_token *token = peek (r);
+  const char *id = get_ident (r);
+  if (strcmp (id, "match_and_simplify") == 0)
+    simplifiers.safe_push (parse_match_and_simplify (r, token->src_loc));
+  else if (strcmp (id, "for") == 0)
+    parse_for (r, token->src_loc, simplifiers); 
+  else
+    fatal_at (token, "expected 'match_and_simplify' or 'for'");
+
+  eat_token (r, CPP_CLOSE_PAREN);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1974,42 +2121,35 @@ main(int argc, char **argv)
 
   vec<simplify *> simplifiers = vNULL;
 
-  do
-    {
-      token = peek (r);
-      if (token->type == CPP_EOF)
-	break;
-
-      /* All clauses start with '('.  */
-      eat_token (r, CPP_OPEN_PAREN);
-
-      const char *id = get_ident (r);
-      if (strcmp (id, "match_and_simplify") == 0)
-	simplifiers.safe_push (parse_match_and_simplify (r, token->src_loc));
-      else
-	fatal_at (token, "expected 'match_and_simplify'");
+  while (peek (r)->type != CPP_EOF)
+    parse_pattern (r, simplifiers);
 
-      eat_token (r, CPP_CLOSE_PAREN);
+  for (unsigned i = 0; i < simplifiers.length (); ++i)
+    {
+      fprintf (stderr, "pattern = %u\n", i);
+      check_no_user_id (simplifiers[i]);
     }
-  while (1);
-
+  vec<simplify *> out_simplifiers = vNULL;
   for (unsigned i = 0; i < simplifiers.length (); ++i)
-    print_matches (simplifiers[i]);
+    lower_commutative (simplifiers[i], out_simplifiers);
+
+  for (unsigned i = 0; i < out_simplifiers.length (); ++i)
+    print_matches (out_simplifiers[i]);
 
   decision_tree dt;
-  for (unsigned i = 0; i < simplifiers.length (); ++i)
-    dt.insert (simplifiers[i], i);
+  for (unsigned i = 0; i < out_simplifiers.length (); ++i)
+    dt.insert (out_simplifiers[i], i);
 
   dt.print (stderr);
  
   if (gimple)
     {
-      write_header (stdout, simplifiers, "gimple-match-head.c");
+      write_header (stdout, out_simplifiers, "gimple-match-head.c");
       dt.gen_gimple (stdout);
     }
   else
     {
-      write_header (stdout, simplifiers, "generic-match-head.c");
+      write_header (stdout, out_simplifiers, "generic-match-head.c");
       dt.gen_generic (stdout);
     }
 
Index: gcc/match.pd
===================================================================
--- gcc/match.pd	(revision 212366)
+++ gcc/match.pd	(working copy)
@@ -22,29 +22,26 @@ along with GCC; see the file COPYING3.
 <http://www.gnu.org/licenses/>.  */
 
 /* Simple constant foldings to substitute gimple_fold_stmt_to_constant_2.  */
-(match_and_simplify
-  (plus @0 integer_zerop)
-  @0)
-(match_and_simplify
-  (pointer_plus @0 integer_zerop)
-  @0)
-(match_and_simplify
-  (minus @0 integer_zerop)
-  @0)
+(for op in plus pointer_plus minus bit_ior bit_xor
+  (match_and_simplify
+    (op @0 integer_zerop)
+    @0))
+
 (match_and_simplify
   (minus @0 @0)
   { build_zero_cst (type); })
+
 (match_and_simplify
   (mult @0 integer_zerop@1)
   @1)
-(match_and_simplify
-  (mult @0 integer_onep)
-  @0)
+
 /* Make sure to preserve divisions by zero.  This is the reason why
    we don't simplify x / x to 1 or 0 / x to 0.  */
-(match_and_simplify
-  (trunc_div @0 integer_onep)
-  @0)
+(for op in mult trunc_div ceil_div floor_div round_div
+  (match_and_simplify
+    (op @0 integer_onep)
+    @0))
+
 (match_and_simplify
   (trunc_mod @0 integer_onep)
   { build_zero_cst (type); })
@@ -55,9 +52,6 @@ along with GCC; see the file COPYING3.
   if (!integer_zerop (@1))
   @0)
 (match_and_simplify
-  (bit_ior @0 integer_zerop)
-  @0)
-(match_and_simplify
   (bit_ior @0 integer_all_onesp@1)
   @1)
 (match_and_simplify
@@ -67,9 +61,6 @@ along with GCC; see the file COPYING3.
   (bit_and @0 integer_zerop@1)
   @1)
 (match_and_simplify
-  (bit_xor @0 integer_zerop)
-  @0)
-(match_and_simplify
   (bit_xor @0 @0)
   { build_zero_cst (type); })
 /* tree-ssa/ifc-pr44710.c requires a < b ? c : d to fold to 1.
@@ -358,6 +349,15 @@ along with GCC; see the file COPYING3.
   if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
   { build_int_cst (type, 0); })
 
+/* (x << CNT1) OP (x >> CNT2) -> x r<< CNT1 OP being +, |, ^ */
+(for op in plus bit_ior bit_xor 
+(match_and_simplify
+  (op:c (lshift @0 INTEGER_CST_P@1) (rshift @0 INTEGER_CST_P@2))
+  if (tree_fits_uhwi_p (@1) && tree_fits_uhwi_p (@2)
+      && tree_to_uhwi (@1) + tree_to_uhwi (@2) == TYPE_PRECISION (type))
+  (lrotate @0 @1)))
+
+
 /* ????s
 
    We cannot reasonably match vector CONSTRUCTORs or vector constants
Index: gcc/testsuite/gcc.dg/tree-ssa/match-rotate.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/match-rotate.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/match-rotate.c	(working copy)
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-forwprop1-details" }  */
+
+unsigned char
+rotate_1 (unsigned char x)
+{
+  unsigned char t1 = x << 5;
+  unsigned char t2 = x >> 3;
+  unsigned char rotate_1_val = t1 + t2;
+  return rotate_1_val;
+}
+/* { dg-final { scan-tree-dump "gimple_match_and_simplified to rotate_1_val_\\d\+ = x_\\d\+\\(D\\) r<< 5" "forwprop1" } } */
+
+unsigned char
+rotate_2 (unsigned char x)
+{
+  unsigned char t1 = x << 4;
+  unsigned char t2 = x >> 3;
+  unsigned char rotate_2_val = t1 + t2;
+  return rotate_2_val;
+}
+/* { dg-final { scan-tree-dump-not "gimple_match_and_simplified to rotate_2_val_\\d\+ = x_\\d\+\\(D\\) r<< 5" "forwprop1" } } */
+
+unsigned char
+rotate_3 (unsigned char x)
+{
+  unsigned char t1 = x << 5;
+  unsigned char t2 = x >> 3;
+  unsigned char rotate_3_val = t1 | t2;
+  return rotate_3_val;
+}
+/* { dg-final { scan-tree-dump "gimple_match_and_simplified to rotate_3_val_\\d\+ = x_\\d\+\\(D\\) r<< 5" "forwprop1" } } */
+
+unsigned char
+rotate_4 (unsigned char x)
+{
+  unsigned char t1 = x << 5;
+  unsigned char t2 = x >> 3;
+  unsigned char rotate_4_val = t1 ^ t2;
+  return rotate_4_val;
+}
+/* { dg-final { scan-tree-dump "gimple_match_and_simplified to rotate_4_val_\\d\+ = x_\\d\+\\(D\\) r<< 5" "forwprop1" } } */
+
+/* { dg-final { cleanup-tree-dump "forwprop1" } } */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]