On Mon, Mar 3, 2014 at 3:32 PM, Richard Biener
<richard.guent...@gmail.com> wrote:
> On Sun, Mar 2, 2014 at 9:13 PM, Prathamesh Kulkarni
> <bilbotheelffri...@gmail.com> wrote:
>> Hi, I am an undergraduate student at University of Pune, India, and would
>> like to work on moving folding patterns from fold-const.c to gimple.
>
> I've seen the entry on our GSoC project page and edited it to discourage
> people from working on that line.  See
>
> http://gcc.gnu.org/ml/gcc/2014-02/msg00516.html
>
> for why.  I think that open-coding the transforms isn't maintainable
> in the long run.
>
>> If I understand correctly, constant folding is done on GENERIC (by
>> routines in fold-const.c), and then GENERIC is lowered to GIMPLE. The
>> purpose of this project,
>> is to have constant folding to be performed on GIMPLE instead (in
>> gimple-fold.c?)
>>
>> I have a few elementary questions to ask:
>>
>> a) A contrived example:
>> Consider a C expression, a = ~0 (assume a is int)
>> In GENERIC, this would roughly be represented as:
>> modify_expr<var_decl "a", <bit_not_expr<integer_cst 0>>>
>> this gets folded to:
>> modify_expr<var_decl "a", integer_cst -1>
>> and the corresponding gimple tuple generated is (-fdump-tree-gimple-raw):
>> gimple_assign <integer_cst, x, -1, NULL, NULL>
>>
>> So, instead of folding performed on GENERIC, it should be
>> done on GIMPLE.
>> So a tuple like the following should be generated by gimplification:
>> <bit_not_expr, a, 0, NULL, NULL>
>> and folded to (by call to fold_stmt):
>> <integer_cst, a, -1, NUL, NULL>
>> Is this the expected behavior ?
>>
>> I have attached a rough/incomplete patch (only stage1 compiled cc1), that
>> does the following foldings on bit_not_expr:
>> a) ~ INTEGER_CST => folded
>> b) ~~x => x
>> c) ~(-x) => x - 1
>> (For the moment, I put case BIT_NOT_EXPR: return NULL_TREE
>> in fold_unary_loc to avoid folding in GENERIC on bit_not_expr)
>>
>> Is the patch going in the correct direction ? Or have I completely missed
>> the point here ? I would be grateful to receive suggestions, and start 
>> working
>> on a fair patch.
>
> I think you implement what was suggested by Kai (and previously
> by me and Andrew, before I changed my mind).
>
Hi Richard,
Thanks for your reply and for pointing me out to this thread
http://gcc.gnu.org/ml/gcc/2014-02/msg00516.html

I agree it's better to generate patterns from a meta-description
instead of hand-coding, and the idea seems interesting to me.

I was playing around with the patch and did few trivial modifications
(please find the patch attached):
a) use obstack in parse_c_expr.

b) use @ inside c code, instead of directly writing captures
(like $<num> in bison):
example:
/* Match and simplify CST + CST to CST'.  */
(define_match_and_simplify baz
  (PLUS_EXPR INTEGER_CST_P@0 INTEGER_CST_P@1)
  { int_const_binop (PLUS_EXPR, @0, @1); })

c) Not sure if this is a good idea, conditional matching.
for example:
/* match (A * B) and simplify to
 * B if integer_zerop B is true ( A * 0 => 0)
 * A if integer_onep B is true  (A * 1 => A)
 */
(define_match_and_simplify multexpr
  (MULT_EXPR integral_op_p@0 integral_op_p@1)
  [
    (integer_zerop@1 @1)
    (integer_onep@1  @0)
  ])
Maybe condition can be generalized to be any operand instead of
testing predicate on capture operand ?

I would be grateful to receive some direction for working on this project.
>From the thread, I see a few possibilities:
a) Moving patterns from tree-ssa-forwprop
b) Extending the DSL (handle commutative operators, conditionally
enabling patterns ?)
c) Targeting GENERIC (Generating patterns in fold-const.c from the
description ?)
d) This is a bit silly, but maybe perform more error checking ?
for example the following pattern is currently accepted:
(define_match px
  (PLUS_EXPR @0 @1 @2))

I wanted to apply to gsoc for this project and I was wondering if you
would you be willing to mentor me if I did?

I have a fluent grasp on C and working knowledge of flex, bison, C++,
POSIX api, binutils and shell scripting (bash),
I have been through most of dragon book, built an interpreter
for a "c-like" language and a C-code generator for a toy language
similar to python.

As far as gcc goes, I had attended IIT Bombay gcc workshop 2013:
http://www.cse.iitb.ac.in/grc/gcc-workshop-13/
and have been through the online docs.

I have a couple of one-liner patches committed:
http://gcc.gnu.org/ml/gcc-patches/2014-02/msg00490.html
http://gcc.gnu.org/ml/gcc-patches/2014-02/msg01144.html

A few pending patches:
http://gcc.gnu.org/ml/gcc-patches/2014-02/msg00143.html
http://gcc.gnu.org/ml/gcc-patches/2014-02/msg00143.html
http://gcc.gnu.org/ml/gcc-patches/2014-02/msg01220.html
http://gcc.gnu.org/ml/gcc/2014-01/msg00268.html

and a couple of rejected ones:
http://gcc.gnu.org/ml/gcc-patches/2014-02/msg00957.html
http://gcc.gnu.org/ml/gcc-patches/2014-02/msg01366.html

Please do let me know what you think.

Thanks and Regards,
Prathamesh

> Richard.
>
>> On the following test-case:
>> int main()
>> {
>>   int a, b, c;
>>   a = ~~~~b;
>>   c = ~-a;
>>   return 0;
>> }
>>
>> The following GIMPLE is generated:
>> main ()
>> gimple_bind <
>>   int D.1748;
>>   int D.1749;
>>   int D.1750;
>>   int D.1751;
>>   int D.1752;
>>   int a;
>>   int b;
>>   int c;
>>
>>   gimple_assign <var_decl, D.1749, b, NULL, NULL>
>>   gimple_assign <var_decl, a, D.1749, NULL, NULL>
>>   gimple_assign <plus_expr, c, a, -1, NULL>
>>   gimple_assign <integer_cst, D.1752, 0, NULL, NULL>
>>   gimple_return <D.1752>
>>>
>>
>> The patch generates two tuples for a = ~~~~b,
>> where only one is needed, and extra temporaries, which
>> are not removed after the folding. How should I go about
>> removing that (should I worry about that since subsequent passes,
>> shall remove those ?)
>>
>> b) Some front-ends, C, for example, requires constant folding in certain 
>> places,
>> like case statement. If constant folding is completely moved off to gimple,
>> how shall this be handled ? Shall we gimplify the expression immediately if
>> it's required to be evaluated ?
>>
>> Thanks and Regards,
>> Prathamesh
Index: gcc/genmatch.c
===================================================================
--- gcc/genmatch.c	(revision 0)
+++ gcc/genmatch.c	(working copy)
@@ -0,0 +1,610 @@
+
+/* Grammar
+
+     capture = '@' number
+     op = predicate | expr [capture]
+     match = 'define_match' name expr
+     c_expr = '{' ... '}'
+     genexpr = '(' code genop... ')'
+     genop = capture | genexpr | c_expr
+     transform = 'define_match_and_transform' name expr genop
+
+     Match (A + B) - B
+     (define_match plusminus
+       (PLUS_EXPR (MINUS_EXPR integral_op_p@0 @1) @1))
+
+     Match and simplify (A + B) - B -> A
+     (define_match_and_simplify foo
+       (PLUS_EXPR (MINUS_EXPR integral_op_p@0 @1) @1)
+       @0)
+
+     Match and simplify (CST + A) + CST to CST' + A
+     (define_match_and_simplify bar
+       (PLUS_EXPR INTEGER_CST_P@0 (PLUS_EXPR @1 INTEGER_CST_P@2))
+       (PLUS_EXPR { int_const_binop (PLUS_EXPR, captures[0], captures[2]); } @1))
+*/
+
+#include "bconfig.h"
+#include "system.h"
+#include "coretypes.h"
+#include <cpplib.h>
+#include "errors.h"
+#include "hashtab.h"
+#include "vec.h"
+
+enum op_type { OP_PREDICATE, OP_EXPR, OP_CAPTURE, OP_C_EXPR, OP_COND };
+
+struct operand {
+  operand (enum op_type type_) : type (type_) {}
+  enum op_type type;
+  virtual void gen_gimple_match (FILE *f, const char *) = 0;
+  virtual void gen_gimple_transform (FILE *f) = 0;
+};
+
+struct predicate : public operand
+{
+  predicate (const char *ident_) : operand (OP_PREDICATE), ident (ident_) {}
+  const char *ident;
+  virtual void gen_gimple_match (FILE *f, const char *);
+  virtual void gen_gimple_transform (FILE *) { gcc_unreachable (); }
+};
+
+struct expr : public operand
+{
+  expr (const char *operation_)
+    : operand (OP_EXPR), operation (operation_), num_ops (0) {}
+  void append_op (operand *op) { ops[num_ops++] = op; }
+  const char *operation;
+  unsigned num_ops;
+  operand *ops[4];
+  virtual void gen_gimple_match (FILE *f, const char *);
+  virtual void gen_gimple_transform (FILE *f);
+};
+
+struct c_expr : public operand
+{
+  c_expr (const char *code_)
+    : operand (OP_EXPR), code (code_) {}
+  const char *code;
+  virtual void gen_gimple_match (FILE *, const char *) { gcc_unreachable (); }
+  virtual void gen_gimple_transform (FILE *f);
+};
+
+struct capture : public operand
+{
+  capture (const char *where_, operand *what_)
+      : operand (OP_CAPTURE), where (where_), what (what_) {}
+  const char *where;
+  operand *what;
+  virtual void gen_gimple_match (FILE *f, const char *);
+  virtual void gen_gimple_transform (FILE *f);
+};
+
+struct condition_pair {
+  condition_pair (struct predicate *pred_, struct operand *op_, struct capture *capt_)
+    : pred (pred_), op (op_), capt (capt_) {}
+  struct predicate *pred;
+  struct operand *op;
+  struct capture *capt; 
+};
+
+struct condition : public operand
+{
+  condition (const vec<struct condition_pair>& conds_)
+    : operand (OP_COND), conds (conds_) {}
+  vec<struct condition_pair> conds;
+  virtual void gen_gimple_match (FILE *f, const char *c) {} 
+  virtual void gen_gimple_transform (FILE *f); 
+};
+
+struct match {
+  match (const char *name_, struct operand *op_);
+  const char *name;
+  struct operand *op;
+  void gen_gimple_match (FILE *f);
+  virtual void gen_gimple (FILE *f) { gen_gimple_match (f); }
+};
+
+struct simplify : public match {
+  simplify (const char *name_, struct operand *op_, struct operand *op2_)
+      : match (name_, op_), op2 (op2_) {} 
+  struct operand *op2;
+  virtual void gen_gimple (FILE *f);
+};
+
+match::match (const char *name_, operand *op_)
+{
+  name = name_;
+  op = op_;
+}
+
+void
+predicate::gen_gimple_match (FILE *f, const char *op)
+{
+  fprintf (f, "if (!%s (%s)) return false;\n", ident, op);
+}
+
+void
+expr::gen_gimple_match (FILE *f, const char *name)
+{
+  fprintf (f, "{\n");
+  fprintf (f, "gimple def_stmt = SSA_NAME_DEF_STMT (%s);\n", name);
+  fprintf (f, "if (is_gimple_assign (def_stmt)\n"
+	   "\t&& gimple_assign_rhs_code (def_stmt) == %s)\n", operation);
+  fprintf (f, "  {\n");
+  fprintf (f, "gcc_assert (gimple_num_ops (def_stmt) == %d + 1);\n", num_ops);
+  for (unsigned i = 0; i < num_ops; ++i)
+    {
+      fprintf (f, "   {\n"); 
+      fprintf (f, "     tree op = gimple_assign_rhs%d (def_stmt);\n", i + 1); 
+      fprintf (f, "     if (valueize && TREE_CODE (op) == SSA_NAME)\n");
+      fprintf (f, "       {\n"); 
+      fprintf (f, "         op = valueize (op);\n");
+      fprintf (f, "         if (!op) return false;\n");
+      fprintf (f, "       }\n");
+      ops[i]->gen_gimple_match (f, "op");
+      fprintf (f, "   }\n");
+    }
+  fprintf (f, "}\n");
+  fprintf (f, "}\n");
+}
+
+void
+expr::gen_gimple_transform (FILE *f)
+{
+  fprintf (f, "({\n");
+  fprintf (f, "  if (!seq) return NULL_TREE;\n");
+  fprintf (f, "  tree ops[%d];\n", num_ops);
+  for (unsigned i = 0; i < num_ops; ++i)
+    {
+      fprintf (f, "   ops[%u] = ", i);
+      ops[i]->gen_gimple_transform (f);
+      fprintf (f, ";\n");
+    }
+  fprintf (f, "  tree res = make_ssa_name (TREE_TYPE (ops[0]), NULL);\n"
+	   "  gimple stmt = gimple_build_assign_with_ops (%s, res",
+	   operation);
+  for (unsigned i = 0; i < num_ops; ++i)
+    fprintf (f, ", ops[%u]", i);
+  fprintf (f, ");\n");
+  fprintf (f, "  gimple_seq_add_stmt_without_update (seq, stmt);\n");
+  fprintf (f, "  res;\n");
+  fprintf (f, "})");
+}
+
+void
+c_expr::gen_gimple_transform (FILE *f)
+{
+  fputs (code, f); 
+}
+
+void
+capture::gen_gimple_transform (FILE *f)
+{
+  fprintf (f, "captures[%s]", this->where);
+}
+
+void
+capture::gen_gimple_match (FILE *f, const char *op)
+{
+  if (this->what)
+    this->what->gen_gimple_match (f, op);
+  fprintf (f, "if (!captures[%s])\n"
+	   "  captures[%s] = %s;\n"
+	   "else if (captures[%s] != %s)\n"
+	   "  return false;", this->where, this->where, op, this->where, op);
+}
+
+
+
+void
+match::gen_gimple_match (FILE *f)
+{
+  fprintf (f, "bool\nmatch_%s (tree name, tree *captures, tree (*valueize)(tree))\n"
+	  "{\n", this->name);
+  this->op->gen_gimple_match (f, "name");
+  fprintf (f, "  return true;\n");
+  fprintf (f, "}\n");
+}
+
+void
+condition::gen_gimple_transform (FILE *f)
+{
+  unsigned i;
+  unsigned len = this->conds.length ();
+
+  fprintf (f, "({ tree op = NULL_TREE;\n");
+
+  fprintf (f, "if (%s (", this->conds[0].pred->ident);
+  this->conds[0].capt->gen_gimple_transform (f);
+  fprintf (f, "))");
+  fprintf (f, "op = ");
+  this->conds[0].op->gen_gimple_transform (f);
+  fprintf (f, ";\n");
+  
+  for (i = 1; i < len; i++)
+    {
+      fprintf (f, "else if (%s (", this->conds[i].pred->ident);
+      this->conds[i].capt->gen_gimple_transform (f);
+      fprintf (f, "))");
+      fprintf (f, "op = ");
+      this->conds[i].op->gen_gimple_transform (f);
+      fprintf (f, ";\n");
+    }     
+  fprintf (f, "op;})\n"); 
+} 
+
+void
+simplify::gen_gimple (FILE *f)
+{
+  fprintf (f, "static ");
+  this->gen_gimple_match (f);
+  fprintf (f, "static tree\n"
+	   "simplify_%s (tree name, gimple_seq *seq, tree (*valueize)(tree))\n"
+	  "{\n", this->name);
+  fprintf (f, "  tree captures[4] = {};\n"
+	   "  if (!match_%s (name, captures, valueize)) return NULL_TREE;\n",
+	   this->name);
+  fprintf (f, "  return ");
+  this->op2->gen_gimple_transform (f);
+  fprintf (f, ";\n}\n");
+}
+
+static const cpp_token *
+next (cpp_reader *r)
+{
+  const cpp_token *token;
+  do
+    {
+      token = cpp_get_token (r);
+    }
+  while (token->type == CPP_PADDING
+	 && token->type != CPP_EOF);
+#if 0
+  /* DEBUG */
+  if (token->type != CPP_EOF)
+    printf ("got token '%s'\n", cpp_token_as_text (r, token));
+#endif
+  return token;
+}
+
+static const cpp_token *
+peek (cpp_reader *r)
+{
+  const cpp_token *token;
+  unsigned i = 0;
+  do
+    {
+      token = cpp_peek_token (r, i++);
+    }
+  while (token->type == CPP_PADDING);
+#if 0
+  /* DEBUG */
+  if (token->type != CPP_EOF)
+    printf ("next token '%s'\n", cpp_token_as_text (r, token));
+#endif
+  return token;
+}
+
+static bool
+is_ident (const cpp_token *token, const char *id)
+{
+  return strcmp ((const char *)CPP_HASHNODE (token->val.node.node)->ident.str,
+		 id) == 0;
+}
+
+static size_t
+round_alloc_size (size_t s)
+{
+  return s;
+}
+
+
+static const cpp_token *
+expect (cpp_reader *r, enum cpp_ttype tk)
+{
+  const cpp_token *token = next (r);
+  if (token->type != tk)
+    fatal ("error: expected %s, got %s",
+	   cpp_type2name (tk, 0), cpp_type2name (token->type, 0));
+
+  return token;
+}
+
+static void
+eat_token (cpp_reader *r, enum cpp_ttype tk)
+{
+  expect (r, tk);
+}
+
+const char *
+get_string (cpp_reader *r)
+{
+  const cpp_token *token = expect (r, CPP_STRING);
+  return (const char *)token->val.str.text;
+}
+
+const char *
+get_ident (cpp_reader *r)
+{
+  const cpp_token *token = expect (r, CPP_NAME);
+  return (const char *)CPP_HASHNODE (token->val.node.node)->ident.str;
+}
+
+const char *
+get_number (cpp_reader *r)
+{
+  const cpp_token *token = expect (r, CPP_NUMBER);
+  return (const char *)token->val.str.text;
+}
+
+static const char *
+parse_operation (cpp_reader *r)
+{
+  return get_ident (r);
+}
+
+static struct operand * parse_op (cpp_reader *r);
+
+/* Parse
+     expr = operation op...  */
+static struct operand *
+parse_expr (cpp_reader *r)
+{
+  expr *e = new expr (parse_operation (r));
+  do
+    {
+      const cpp_token *token = peek (r);
+      if (token->type == CPP_CLOSE_PAREN)
+	return e;
+      e->append_op (parse_op (r));
+    }
+  while (1);
+  return e;
+}
+
+static struct operand *
+parse_capture (cpp_reader *r, operand *op)
+{
+  eat_token (r, CPP_ATSIGN);
+  return new capture (get_number (r), op);
+}
+
+
+static operand *
+parse_c_expr (cpp_reader *r)
+{
+  /* ???  Use an obstack to build the string.  */
+  const cpp_token *token;
+  char *code; 
+  struct obstack ob;
+
+  obstack_init (&ob);
+  obstack_grow (&ob, "({", 2);
+
+  do
+    {
+      token = next (r);
+      char *tk = (char *)cpp_token_as_text (r, token);
+      
+      if (token->flags & PREV_WHITE)
+	obstack_grow (&ob, " ", 1); 
+      if (tk[0] == '@' && tk[1] == '\0')
+	{
+	  const char *num = get_number(r);
+	  obstack_grow (&ob, "captures[", strlen ("captures["));
+	  obstack_grow (&ob, num, strlen (num));
+	  obstack_grow (&ob, "]", 1);
+	}
+	else
+          obstack_grow (&ob, tk, strlen (tk)); 
+    }
+  while (token->type != CPP_CLOSE_BRACE);
+//  code = (char *)xmalloc (code, strlen (code) + 1 + 1);
+  obstack_grow0 (&ob, ")", 1);
+  code = xstrdup ((const char *) obstack_finish (&ob));
+  obstack_free (&ob, obstack_finish (&ob));
+  return new c_expr (code);
+
+}
+
+/* Parse
+     op = predicate | ( expr ) */
+
+static struct operand *
+parse_op (cpp_reader *r)
+{
+  const cpp_token *token = peek (r);
+  struct operand *op = NULL;
+  if (token->type == CPP_OPEN_PAREN)
+    {
+      eat_token (r, CPP_OPEN_PAREN);
+      op = parse_expr (r);
+      eat_token (r, CPP_CLOSE_PAREN);
+    }
+  else if (token->type == CPP_OPEN_BRACE)
+    {
+      eat_token (r, CPP_OPEN_BRACE);
+      op = parse_c_expr (r);
+    }
+  else if (token->type == CPP_NAME)
+    op = new predicate (get_ident (r));
+  else if (token->type == CPP_ATSIGN)
+    op = parse_capture (r, op);
+  else
+    fatal ("expected expression or predicate");
+
+  token = peek (r);
+  if (token->type == CPP_ATSIGN
+      && !(token->flags & PREV_WHITE))
+    op = parse_capture (r, op);
+
+  return op;
+}
+
+/*
+ * opcond: cond | op
+ * cond: '[' cond-list ']'
+ * cond-list: condition |
+              cond-list condition
+ * condition: '(' predicate capture operand ')'
+ */
+
+static struct operand *
+parse_condition_or_op (cpp_reader *r)
+{
+  const cpp_token *token = peek (r);
+  struct operand *op = NULL;
+  vec<struct condition_pair> conds = vNULL;
+
+  if (token->type == CPP_OPEN_SQUARE)
+    {
+      eat_token (r, CPP_OPEN_SQUARE);
+      do
+	{
+	  eat_token (r, CPP_OPEN_PAREN);
+	  struct predicate *pred = new predicate (get_ident (r));
+	  struct capture *capt = (struct capture *) parse_capture (r, NULL);
+	  struct operand *result = parse_op (r);
+	  struct condition_pair c(pred, result, capt);
+	  conds.safe_push (c);
+	  eat_token (r, CPP_CLOSE_PAREN);
+	 
+	  token = peek (r);
+	  if (token->type == CPP_CLOSE_SQUARE)
+	    {
+	      eat_token (r, CPP_CLOSE_SQUARE);
+	      break;
+	    }
+	}
+      while (1);
+      op = new condition (conds); 
+    }
+  else
+    op = parse_op (r);
+
+  return op;
+}      
+
+/* Parse
+     (define_match "<ident>"
+        <op>)  */
+
+static match *
+parse_match (cpp_reader *r)
+{
+  return new match (get_ident (r), parse_op (r));
+}
+
+/* Parse
+     (define_match_and_simplify "<ident>"
+        <op> <op>)  */
+
+static simplify *
+parse_match_and_simplify (cpp_reader *r)
+{
+  return new simplify (get_ident (r), parse_op (r), parse_condition_or_op (r)); 
+}
+
+static void
+write_gimple (FILE *f, vec<match *>& matchers, vec<simplify *>& simplifiers)
+{
+  fprintf (f,
+"#include \"config.h\"\n"
+"#include \"system.h\"\n"
+"#include \"coretypes.h\"\n"
+"#include \"tree.h\"\n"
+"#include \"stringpool.h\"\n"
+"#include \"flags.h\"\n"
+"#include \"function.h\"\n"
+"#include \"basic-block.h\"\n"
+"#include \"tree-ssa-alias.h\"\n"
+"#include \"internal-fn.h\"\n"
+"#include \"gimple-expr.h\"\n"
+"#include \"is-a.h\"\n"
+"#include \"gimple.h\"\n"
+"#include \"gimple-ssa.h\"\n"
+"#include \"tree-ssanames.h\"\n"
+"\n"
+"#define INTEGER_CST_P(node) TREE_CODE(node) == INTEGER_CST\n"
+"#define integral_op_p(node) INTEGRAL_TYPE_P(TREE_TYPE(node))\n"
+"\n");
+
+  /* Write matchers and simplifiers.  */
+  for (unsigned i = 0; i < matchers.length (); ++i)
+    matchers[i]->gen_gimple (f);
+  for (unsigned i = 0; i < simplifiers.length (); ++i)
+    simplifiers[i]->gen_gimple (f);
+
+  /* Write the catch-all simplifier.  */
+  fprintf (f, "tree\ngimple_match_and_simplify (tree name, gimple_seq *seq, tree (*valueize)(tree))\n"
+	   "{\n"
+	   "  tree res;\n");
+  for (unsigned i = 0; i < simplifiers.length (); ++i)
+    fprintf (f, "  res = simplify_%s (name, seq, valueize);\n"
+	     "  if (res) return res;\n", simplifiers[i]->name);
+  fprintf (f, "  return NULL_TREE;\n"
+	   "}\n");
+}
+
+int main(int argc, char **argv)
+{
+  cpp_reader *r;
+  const cpp_token *token;
+  struct line_maps *line_table;
+  
+  progname = "genmatch";
+
+  if (argc != 2)
+    return 1;
+
+  line_table = XCNEW (struct line_maps);
+  linemap_init (line_table);
+  line_table->reallocator = xrealloc;
+  line_table->round_alloc_size = round_alloc_size;
+
+  r = cpp_create_reader (CLK_GNUC99, NULL, line_table);
+
+  if (!cpp_read_main_file (r, argv[1]))
+    return 1;
+
+#if 0
+  do
+    {
+      const cpp_token *token = cpp_get_token (r);
+      fprintf (stdout, "'%s'\n", cpp_token_as_text (r, token));
+    }
+  while (token->type != CPP_EOF);
+#endif
+
+  vec<match *> matchers = vNULL;
+  vec<simplify *> simplifiers = vNULL;
+
+  do
+    {
+      token = peek (r);
+      if (token->type == CPP_EOF)
+	break;
+
+      /* All clauses start with '('.  */
+      eat_token (r, CPP_OPEN_PAREN);
+
+      token = next (r);
+      if (is_ident (token, "define_match"))
+	matchers.safe_push (parse_match (r));
+      else if (is_ident (token, "define_match_and_simplify"))
+	simplifiers.safe_push (parse_match_and_simplify (r));
+      else
+	exit (1);
+
+      eat_token (r, CPP_CLOSE_PAREN);
+    }
+  while (1);
+
+  write_gimple (stdout, matchers, simplifiers);
+
+  cpp_finish (r, NULL);
+  cpp_destroy (r);
+
+  return 0;
+}
Index: gcc/match.pd
===================================================================
--- gcc/match.pd	(revision 0)
+++ gcc/match.pd	(working copy)
@@ -0,0 +1,30 @@
+/* Match (A - B) + B only.  */
+(define_match plusminus
+  (PLUS_EXPR (MINUS_EXPR integral_op_p@0 @1) @1))
+
+/* Match and simplify (A - B) + B -> A.  */
+(define_match_and_simplify foo
+  (PLUS_EXPR (MINUS_EXPR integral_op_p@0 @1) @1)
+  @0)
+
+/* Match and simplify CST + CST to CST'.  */
+(define_match_and_simplify baz
+  (PLUS_EXPR INTEGER_CST_P@0 INTEGER_CST_P@1)
+  { int_const_binop (PLUS_EXPR, @0, @1); })
+
+/* Match and simplify (CST + A) + CST to CST' + A.  */
+(define_match_and_simplify bar
+  (PLUS_EXPR INTEGER_CST_P@0 (PLUS_EXPR @1 INTEGER_CST_P@2))
+  (PLUS_EXPR { int_const_binop (PLUS_EXPR, captures[0], captures[2]); } @1))
+
+/* match (A * B) and simplify to
+ * B if integer_zerop B is true (A * 0 => 0)
+ * A if integer_onep B is true (A * 1 => A)
+ */
+(define_match_and_simplify multexpr
+  (MULT_EXPR integral_op_p@0 integral_op_p@1)
+  [
+    (integer_zerop@1 @1)
+    (integer_onep@1  @0)
+  ])
+

Reply via email to