This adds a ! marker to result expressions that should simplify
(and if not fail the simplification).  This can for example be
used like

(simplify
  (plus (vec_cond:s @0 @1 @2) @3)
  (vec_cond @0 (plus! @1 @3) (plus! @2 @3)))

to make the simplification only apply in case both plus operations
in the result end up simplified to a simple operand.

Bootstrap & regtest running on x86_64-unknown-linux-gnu.

2020-07-31  Richard Biener  <rguent...@suse.de>

        * genmatch.c (expr::force_leaf): Add and initialize.
        (expr::gen_transform): Honor force_leaf by passing
        NULL as sequence argument to maybe_push_res_to_seq.
        (parser::parse_expr): Allow ! marker on result expression
        operations.
        * doc/match-and-simplify.texi: Amend.
---
 gcc/doc/match-and-simplify.texi | 15 +++++++++++++++
 gcc/genmatch.c                  | 19 ++++++++++++++++---
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/gcc/doc/match-and-simplify.texi b/gcc/doc/match-and-simplify.texi
index 1df8b90e7c4..41980acbfe9 100644
--- a/gcc/doc/match-and-simplify.texi
+++ b/gcc/doc/match-and-simplify.texi
@@ -361,6 +361,21 @@ 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 explicitely.
 
+Another modifier for generated expressions is @code{!} which
+tells the machinery to only consider the simplification in case
+the marked expression simplified to a simple operand.  Consider
+for example
+
+@smallexample
+(simplify
+  (plus (vec_cond:s @@0 @@1 @@2) @@3)
+  (vec_cond @@0 (plus! @@1 @@3) (plus! @@2 @@3)))
+@end smallexample
+
+which moves the outer @code{plus} operation to the inner arms
+of the @code{vec_cond} expression but only if the actual plus
+operations both simplify.
+
 As intermediate conversions are often optional there is a way to
 avoid the need to repeat patterns both with and without such
 conversions.  Namely you can mark a conversion as being optional
diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 0a8cba62e0c..88459d9686e 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -697,12 +697,13 @@ public:
   expr (id_base *operation_, location_t loc, bool is_commutative_ = false)
     : operand (OP_EXPR, loc), operation (operation_),
       ops (vNULL), expr_type (NULL), is_commutative (is_commutative_),
-      is_generic (false), force_single_use (false), opt_grp (0) {}
+      is_generic (false), force_single_use (false), force_leaf (false),
+      opt_grp (0) {}
   expr (expr *e)
     : operand (OP_EXPR, e->location), operation (e->operation),
       ops (vNULL), expr_type (e->expr_type), is_commutative 
(e->is_commutative),
       is_generic (e->is_generic), force_single_use (e->force_single_use),
-      opt_grp (e->opt_grp) {}
+      force_leaf (e->force_leaf), opt_grp (e->opt_grp) {}
   void append_op (operand *op) { ops.safe_push (op); }
   /* The operator and its operands.  */
   id_base *operation;
@@ -717,6 +718,9 @@ public:
   /* Whether pushing any stmt to the sequence should be conditional
      on this expression having a single-use.  */
   bool force_single_use;
+  /* Whether in the result expression this should be a leaf node
+     with any children simplified down to simple operands.  */
+  bool force_leaf;
   /* If non-zero, the group for optional handling.  */
   unsigned char opt_grp;
   virtual void gen_transform (FILE *f, int, const char *, bool, int,
@@ -2520,7 +2524,8 @@ expr::gen_transform (FILE *f, int indent, const char 
*dest, bool gimple,
       fprintf (f, ");\n");
       fprintf_indent (f, indent, "tem_op.resimplify (lseq, valueize);\n");
       fprintf_indent (f, indent,
-                     "_r%d = maybe_push_res_to_seq (&tem_op, lseq);\n", depth);
+                     "_r%d = maybe_push_res_to_seq (&tem_op, %s);\n", depth,
+                     !force_leaf ? "lseq" : "NULL");
       fprintf_indent (f, indent,
                      "if (!_r%d) return false;\n",
                      depth);
@@ -4240,6 +4245,14 @@ parser::parse_expr ()
   bool force_capture = false;
   const char *expr_type = NULL;
 
+  if (!parsing_match_operand
+      && token->type == CPP_NOT
+      && !(token->flags & PREV_WHITE))
+    {
+      eat_token (CPP_NOT);
+      e->force_leaf = true;
+    }
+
   if (token->type == CPP_COLON
       && !(token->flags & PREV_WHITE))
     {
-- 
2.26.2

Reply via email to