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

Reply via email to