[PATCH v2 1/3] match: allow c variable for the code/operation of the result [PR126912]

Andrea Pinski <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
This allows a C variable for the code of the result
to reduce how many for loops are needed and reduces the code size of
the generated files by a factor of 6 (in some cases).
This should allow for arm to build again at -O0.

Currently this only allows if the variable contains `code` in it.
If the identifier has cmp in it; genmatch assumes it will be a
tcc_comparison for type resultion.

I can add support for combined_fn and internal_fn later if needed.
From looking into the match patterns right now; there is a few but none
use a for loop for cases but rather just a few (3/4) if statements. So it
was not high on my list of things to support currently.

Bootstrapped and tested on x86_64-linux-gnu.

	PR middle-end/126912
gcc/ChangeLog:

	* doc/match-and-simplify.texi: Document new syntax.
	* genmatch.cc (class c_code_id): New class.
	(c_code_id::get_c_code_id): New method.
	(c_ids): New hashtable.
	(test): Handle C_CODE_ID.
	(lower_for): Handle c_code_id.
	(get_operand_type): Check cmp of c_code_id.
	(expr::gen_transform): Likewise.
	(dt_simplify::gen_1): Handle C_CODE_ID like CODE.
	(parser::parse_operation): Add bool res argument. For unknown id
	see if this can be a c code id for res.
	(parser::parse_expr): Add bool res argument. Pass down to parse_op
	and parse_operation.
	(parser::parse_op): Add bool res argument.
	Pass down to parse_expr and parse_op.
	(parser::parse_result): Pass true to parse_op and parse_expr.
	(parser::parse_simplify): Pass false to parse_op.
	(main): Allocate and free c_ids.
	* match.pd (`(a CMP1 b) bitop (a CMP2 b)`): Remove rcmp
	loop and update for the new syntax.
	(other comparison loops): Update for the new syntax.

Signed-off-by: Andrea Pinski <[email protected]>
---
 gcc/doc/match-and-simplify.texi |  13 ++++
 gcc/genmatch.cc                 | 114 ++++++++++++++++++++++++--------
 gcc/match.pd                    |  77 +++++++++------------
 3 files changed, 129 insertions(+), 75 deletions(-)

diff --git a/gcc/doc/match-and-simplify.texi b/gcc/doc/match-and-simplify.texi
index b187dd27561..4f171a36f69 100644
--- a/gcc/doc/match-and-simplify.texi
+++ b/gcc/doc/match-and-simplify.texi
@@ -361,6 +361,19 @@ Usually the types of the generated result expressions are
 determined from the context, but sometimes like in the above case
 it is required that you specify them explicitly.
 
+In the result of a simplify, a variable defined in @code{with} can be
+use as the resulting tree code if it contains @code{code} in the name.
+Comparisons results need to have cmp in its name to get the correct type for it.
+
+@smallexample
+ (simplify
+  (bit_xor (cmp @@0 @@1) integer_truep)
+  (with @{ enum tree_code rescmpcode = invert_tree_comparison
+            (cmp, HONOR_NANS (@@0)); @}
+    (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison)
+     (rescmpcode @@0 @@1))))
+@end smallexample
+
 Another modifier for generated expressions is @code{^} which
 tells the machinery to try more matches for some special cases.
 For example, normally the @code{cond} only allows the gimple
diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc
index 920cf27877d..44da9fa3970 100644
--- a/gcc/genmatch.cc
+++ b/gcc/genmatch.cc
@@ -1121,7 +1121,7 @@ comparison_code_p (enum tree_code code)
 class id_base : public nofree_ptr_hash<id_base>
 {
 public:
-  enum id_kind { CODE, FN, PREDICATE, USER, NULL_ID } kind;
+  enum id_kind { CODE, FN, PREDICATE, USER, C_CODE_ID, NULL_ID } kind;
 
   id_base (id_kind, const char *, int = -1);
 
@@ -1199,6 +1199,37 @@ public:
   vec<simplify *> matchers;
 };
 
+// Identifier that maps to a operator defined by a 'C' identifier.
+// Contains code in the id, also if contains cmp then it is a compare.
+
+class c_code_id : public id_base
+{
+public:
+  c_code_id (const char *id_)
+    : id_base (id_base::C_CODE_ID, xstrdup (id_)),
+      cmp (strstr (id_, "cmp")) {}
+  static id_base *get_c_code_id (const char *);
+  ~c_code_id() { delete const_cast<char*>(id); }
+  bool cmp;
+};
+
+static hash_table<id_base> *c_ids;
+
+id_base *
+c_code_id::get_c_code_id (const char *id)
+{
+  if (!strstr (id, "code"))
+    return nullptr;
+  id_base tem (id_base::C_CODE_ID, id);
+
+  id_base **op = c_ids->find_slot_with_hash (&tem, tem.hashval, INSERT);
+  if (!*op)
+   *op = new c_code_id (id);
+
+  return *op;
+}
+
+
 /* Identifier that maps to a operator defined by a 'for' directive.  */
 
 class user_id : public id_base
@@ -1244,6 +1275,14 @@ is_a_helper <user_id *>::test (id_base *id)
   return id->kind == id_base::USER;
 }
 
+template<>
+template<>
+inline bool
+is_a_helper <c_code_id *>::test (id_base *id)
+{
+  return id->kind == id_base::C_CODE_ID;
+}
+
 /* If ID has a pair of consecutive, commutative operands, return the
    index of the first, otherwise return -1.  */
 
@@ -2301,6 +2340,8 @@ lower_for (simplify *sin, vec<simplify *>& simplifiers)
 	      }
 	    else if (is_a <fn_id *> (ids[i]->substitutes[j]))
 	      ;
+	    else if (is_a <c_code_id *> (ids[i]->substitutes[j]))
+	      ;
 	    else
 	      can_delay_subst = false;
 	}
@@ -3222,8 +3263,10 @@ get_operand_type (id_base *op, unsigned pos,
   else if (*op == REALPART_EXPR
 	   || *op == IMAGPART_EXPR)
     return other_oprnd_type;
-  else if (is_a <operator_id *> (op)
-	   && strcmp (as_a <operator_id *> (op)->tcc, "tcc_comparison") == 0)
+  else if ((is_a <operator_id *> (op)
+	    && strcmp (as_a <operator_id *> (op)->tcc, "tcc_comparison") == 0)
+	   || (is_a <c_code_id *> (op)
+	       && as_a <c_code_id *>(op)->cmp))
     return other_oprnd_type;
   else if (*op == COND_EXPR
 	   && pos == 0)
@@ -3285,8 +3328,10 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
 		depth);
       type = optype;
     }
-  else if (is_a <operator_id *> (opr)
-	   && !strcmp (as_a <operator_id *> (opr)->tcc, "tcc_comparison"))
+  else if ((is_a <operator_id *> (opr)
+	     && !strcmp (as_a <operator_id *> (opr)->tcc, "tcc_comparison"))
+           || (is_a <c_code_id *> (opr)
+	       && as_a <c_code_id *> (opr)->cmp))
     {
       /* comparisons use boolean_type_node (or what gets in), but
          their operands need to figure out the types themselves.  */
@@ -3451,7 +3496,7 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
 	  fprintf_indent (f, indent + 2, "{\n");
 	  indent += 4;
 	}
-      if (opr->kind == id_base::CODE)
+      if (opr->kind == id_base::CODE || opr->kind == id_base::C_CODE_ID)
 	fprintf_indent (f, indent, "_r%d = fold_build%d_loc (loc, %s, %s",
 			depth, ops.length(), opr_name, type);
       else
@@ -3460,7 +3505,7 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple,
       for (unsigned i = 0; i < ops.length (); ++i)
 	fprintf (f, ", _o%d[%u]", depth, i);
       fprintf (f, ");\n");
-      if (opr->kind != id_base::CODE)
+      if (opr->kind != id_base::CODE && opr->kind != id_base::C_CODE_ID)
 	{
 	  fprintf_indent (f, indent, "if (!_r%d)\n", depth);
 	  fprintf_indent (f, indent, "  goto %s;\n", fail_label);
@@ -4630,7 +4675,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
 				"_r = non_lvalue_loc (loc, res_op0);\n");
 	      else
 		{
-		  if (is_a <operator_id *> (opr))
+		  if (is_a <operator_id *> (opr) || is_a <c_code_id *> (opr))
 		    fprintf_indent (f, indent,
 				    "_r = fold_build%d_loc (loc, %s, type",
 				    e->ops.length (),
@@ -4644,7 +4689,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result)
 		  for (unsigned j = 0; j < e->ops.length (); ++j)
 		    fprintf (f, ", res_op%d", j);
 		  fprintf (f, ");\n");
-		  if (!is_a <operator_id *> (opr))
+		  if (!is_a <operator_id *> (opr) && !is_a<c_code_id *> (opr))
 		    {
 		      fprintf_indent (f, indent, "if (!_r)\n");
 		      fprintf_indent (f, indent, "  goto %s;\n", fail_label);
@@ -5146,11 +5191,11 @@ private:
 
   unsigned get_internal_capture_id ();
 
-  id_base *parse_operation (unsigned char &);
+  id_base *parse_operation (unsigned char &, bool);
   operand *parse_capture (operand *, bool);
-  operand *parse_expr ();
+  operand *parse_expr (bool = false);
   c_expr *parse_c_expr (cpp_ttype);
-  operand *parse_op ();
+  operand *parse_op (bool);
 
   void record_operlist (location_t, user_id *);
 
@@ -5338,7 +5383,7 @@ parser::record_operlist (location_t loc, user_id *p)
    convert2?  */
 
 id_base *
-parser::parse_operation (unsigned char &opt_grp)
+parser::parse_operation (unsigned char &opt_grp, bool res)
 {
   const cpp_token *id_tok = peek ();
   char *alt_id = NULL;
@@ -5365,7 +5410,18 @@ parser::parse_operation (unsigned char &opt_grp)
     }
   id_base *op = get_operator (alt_id ? alt_id : id);
   if (!op)
-    fatal_at (id_tok, "unknown operator %s", alt_id ? alt_id : id);
+    {
+      // An unknown id that contains code in it is considered a C code identifier
+      if (res)
+	{
+	  if (id_base *op = c_code_id::get_c_code_id (id))
+	    {
+	      free (alt_id);
+	      return op;
+	    }
+	}
+      fatal_at (id_tok, "unknown operator %s", alt_id ? alt_id : id);
+    }
   if (alt_id)
     free (alt_id);
   user_id *p = dyn_cast<user_id *> (op);
@@ -5420,11 +5476,11 @@ parser::parse_capture (operand *op, bool require_existing)
      expr = '(' <operation>[capture][flag][type] <operand>... ')'  */
 
 class operand *
-parser::parse_expr ()
+parser::parse_expr (bool res)
 {
   const cpp_token *token = peek ();
   unsigned char opt_grp;
-  expr *e = new expr (parse_operation (opt_grp), token->src_loc);
+  expr *e = new expr (parse_operation (opt_grp, res), token->src_loc);
   token = peek ();
   operand *op;
   bool is_commutative = false;
@@ -5537,7 +5593,7 @@ parser::parse_expr ()
       else if (!(token->flags & PREV_WHITE))
 	fatal_at (token, "expected expression operand");
 
-      e->append_op (parse_op ());
+      e->append_op (parse_op (res));
     }
   while (1);
 }
@@ -5602,14 +5658,14 @@ parser::parse_c_expr (cpp_ttype start)
      op = predicate | expr | c_expr | capture  */
 
 class operand *
-parser::parse_op ()
+parser::parse_op (bool res)
 {
   const cpp_token *token = peek ();
   class operand *op = NULL;
   if (token->type == CPP_OPEN_PAREN)
     {
       eat_token (CPP_OPEN_PAREN);
-      op = parse_expr ();
+      op = parse_expr (res);
       eat_token (CPP_CLOSE_PAREN);
     }
   else if (token->type == CPP_OPEN_BRACE)
@@ -5695,7 +5751,7 @@ parser::parse_result (operand *result, predicate_id *matcher)
 {
   const cpp_token *token = peek ();
   if (token->type != CPP_OPEN_PAREN)
-    return parse_op ();
+    return parse_op (true);
 
   eat_token (CPP_OPEN_PAREN);
   if (peek_ident ("if"))
@@ -5709,15 +5765,15 @@ parser::parse_result (operand *result, predicate_id *matcher)
 	  if (peek ()->type == CPP_OPEN_PAREN)
 	    ife->falseexpr = parse_result (result, matcher);
 	  else if (peek ()->type != CPP_CLOSE_PAREN)
-	    ife->falseexpr = parse_op ();
+	    ife->falseexpr = parse_op (true);
 	}
       else if (peek ()->type != CPP_CLOSE_PAREN)
 	{
-	  ife->trueexpr = parse_op ();
+	  ife->trueexpr = parse_op (true);
 	  if (peek ()->type == CPP_OPEN_PAREN)
 	    ife->falseexpr = parse_result (result, matcher);
 	  else if (peek ()->type != CPP_CLOSE_PAREN)
-	    ife->falseexpr = parse_op ();
+	    ife->falseexpr = parse_op (true);
 	}
       /* If this if is immediately closed then it contains a
 	 manual matcher or is part of a predicate definition.  */
@@ -5752,7 +5808,7 @@ parser::parse_result (operand *result, predicate_id *matcher)
       if (peek ()->type == CPP_OPEN_PAREN)
 	ife->trueexpr = parse_result (result, matcher);
       else
-	ife->trueexpr = parse_op ();
+	ife->trueexpr = parse_op (true);
       eat_token (CPP_CLOSE_PAREN);
       if (peek ()->type != CPP_OPEN_PAREN
 	  || !peek_ident ("if", 2))
@@ -5771,7 +5827,7 @@ parser::parse_result (operand *result, predicate_id *matcher)
 		  if (peek ()->type == CPP_OPEN_PAREN)
 		    ife->trueexpr = parse_result (result, matcher);
 		  else
-		    ife->trueexpr = parse_op ();
+		    ife->trueexpr = parse_op (true);
 		  if (peek ()->type == CPP_OPEN_PAREN)
 		    fatal_at (peek(), "if inside switch cannot have an else");
 		  eat_token (CPP_CLOSE_PAREN);
@@ -5787,7 +5843,7 @@ parser::parse_result (operand *result, predicate_id *matcher)
 	  else
 	    {
 	      /* switch default clause */
-	      ife->falseexpr = parse_op ();
+	      ife->falseexpr = parse_op (true);
 	      eat_token (CPP_CLOSE_PAREN);
 	      return res;
 	    }
@@ -5799,7 +5855,7 @@ parser::parse_result (operand *result, predicate_id *matcher)
     {
       operand *op = result;
       if (!matcher)
-	op = parse_expr ();
+	op = parse_expr (true);
       eat_token (CPP_CLOSE_PAREN);
       return op;
     }
@@ -5826,7 +5882,7 @@ parser::parse_simplify (simplify::simplify_kind kind,
 
   const cpp_token *loc = peek ();
   parsing_match_operand = true;
-  class operand *match = parse_op ();
+  class operand *match = parse_op (false);
   finish_match_operand (match);
   parsing_match_operand = false;
   if (match->type == operand::OP_CAPTURE && !matcher)
@@ -6366,6 +6422,7 @@ main (int argc, char **argv)
 
   /* Pre-seed operators.  */
   operators = new hash_table<id_base> (1024);
+  c_ids = new hash_table<id_base> (4);
 #define DEFTREECODE(SYM, STRING, TYPE, NARGS) \
   add_operator (SYM, # SYM, # TYPE, NARGS);
 #define END_OF_BASE_TREE_CODES
@@ -6471,6 +6528,7 @@ main (int argc, char **argv)
   cpp_destroy (r);
 
   delete operators;
+  delete c_ids;
 
   return 0;
 }
diff --git a/gcc/match.pd b/gcc/match.pd
index eae8717bcfe..d255795c8dd 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -4006,20 +4006,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (for bitop (bit_and bit_ior)
  (for cmp1 (tcc_comparison)
   (for cmp2 (tcc_comparison)
-   (for rcmp (tcc_comparison)
-    (simplify
-     (bitop (cmp1 @0 @1) (cmp2 @0 @1))
-     (with {
-       tree_code rescode;
-       tree res;
-       bool honor_nans = HONOR_NANS (@0);
-       rescode = combine_comparisons (bitop, cmp1, cmp2,
-				      type, honor_nans, &res);
-      }
-      (if (rescode == INTEGER_CST)
-       { res; }
-       (if (rescode == rcmp)
-        (rcmp @0 @1)))))))))
+   (simplify
+    (bitop (cmp1 @0 @1) (cmp2 @0 @1))
+    (with {
+      tree_code rescmpcode;
+      tree res;
+      bool honor_nans = HONOR_NANS (@0);
+      rescmpcode = combine_comparisons (bitop, cmp1, cmp2,
+					type, honor_nans, &res);
+     }
+     (if (rescmpcode == INTEGER_CST)
+      { res; }
+      (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison)
+       (rescmpcode @0 @1))))))))
 
 /* (type)([0,1]@a != 0) -> (type)a
    (type)([0,1]@a == 1) -> (type)a
@@ -7781,8 +7780,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    operator using invert_tree_comparison we have to simulate
    that with expression code iteration.  */
 (for cmp (tcc_comparison)
-     icmp (inverted_tcc_comparison)
-     ncmp (inverted_tcc_comparison_with_nans)
  /* Ideally we'd like to combine the following two patterns
     and handle some more cases by using
       (logical_inverted_value (cmp @0 @1))
@@ -7793,39 +7790,29 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (if (VECTOR_TYPE_P (type)
        || (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1))
    /* Comparison inversion may be impossible for trapping math,
-      invert_tree_comparison will tell us.  But we can't use
-      a computed operator in the replacement tree thus we have
-      to play the trick below.  */
-   (with { enum tree_code ic = invert_tree_comparison
+      invert_tree_comparison will tell us.  */
+   (with { enum tree_code rescmpcode = invert_tree_comparison
              (cmp, HONOR_NANS (@0)); }
-    (if (ic == icmp)
-     (icmp @0 @1)
-     (if (ic == ncmp)
-      (ncmp @0 @1))))))
+    (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison)
+     (rescmpcode @0 @1)))))
  (simplify
   (bit_xor (cmp @0 @1) integer_truep)
-  (with { enum tree_code ic = invert_tree_comparison
+  (with { enum tree_code rescmpcode = invert_tree_comparison
             (cmp, HONOR_NANS (@0)); }
-   (if (ic == icmp)
-    (icmp @0 @1)
-    (if (ic == ncmp)
-     (ncmp @0 @1)))))
+    (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison)
+     (rescmpcode @0 @1))))
  /* ((cast)cmp) - 1 -> -(cast)icmp . */
  (simplify
   (plus (convert? (cmp@2 @0 @1)) integer_minus_onep)
   (if (TYPE_PRECISION (type) > 1
        && INTEGRAL_TYPE_P (TREE_TYPE (@2)) && TYPE_PRECISION (TREE_TYPE (@2)) == 1)
    /* Comparison inversion may be impossible for trapping math,
-      invert_tree_comparison will tell us.  But we can't use
-      a computed operator in the replacement tree thus we have
-      to play the trick below.  */
-   (with { enum tree_code ic = invert_tree_comparison
+      invert_tree_comparison will tell us.  */
+   (with { enum tree_code rescmpcode = invert_tree_comparison
              (cmp, HONOR_NANS (@0));
            tree cmptype = TREE_TYPE (@2); }
-    (if (ic == icmp)
-     (negate (convert (icmp:cmptype @0 @1)))
-     (if (ic == ncmp)
-      (negate (convert (ncmp:cmptype @0 @1))))))))
+    (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison)
+     (negate (convert (rescmpcode:cmptype @0 @1)))))))
  /* The following bits are handled by fold_binary_op_with_conditional_arg.  */
  (simplify
   (ne (cmp@2 @0 @1) integer_zerop)
@@ -7838,21 +7825,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (simplify
   (ne (cmp@2 @0 @1) integer_truep)
   (if (types_match (type, TREE_TYPE (@2)))
-   (with { enum tree_code ic = invert_tree_comparison
+   (with { enum tree_code rescmpcode = invert_tree_comparison
 	     (cmp, HONOR_NANS (@0)); }
-    (if (ic == icmp)
-     (icmp @0 @1)
-     (if (ic == ncmp)
-      (ncmp @0 @1))))))
+    (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison)
+     (rescmpcode @0 @1)))))
  (simplify
   (eq (cmp@2 @0 @1) integer_zerop)
   (if (types_match (type, TREE_TYPE (@2)))
-   (with { enum tree_code ic = invert_tree_comparison
+   (with { enum tree_code rescmpcode = invert_tree_comparison
 	     (cmp, HONOR_NANS (@0)); }
-    (if (ic == icmp)
-     (icmp @0 @1)
-     (if (ic == ncmp)
-      (ncmp @0 @1)))))))
+    (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison)
+     (rescmpcode @0 @1))))))
 
 /* Transform comparisons of the form X - Y CMP 0 to X CMP Y.
    ??? The transformation is valid for the other operators if overflow
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.