The following patch introduces a new syntax to initialize temporaries
used in c-exprs (such as if conditionals).  So a simplify pattern is now

     'simplify' [ <ident> ] <expr> <result-op>

with

     <result-op> = <op> | <if> | <with>
     <if> = '(' 'if' '(' <c-expr> ')' <result-op> ')'
     <with> = '(' 'with' '{' <c-expr> '}' <result-op> ')'

which allows nearly literal translation of 
tree-ssa-forwprop.c:combine_conversions like in the patch below.

Code generation is shared with ifs which makes the patch simple
but that also requires -Wno-unused-variable as we are tieing
all ifexprs to the final simplify instead of placing them
appropriately nested inside the decision tree (an optimization
for later which requires quite some changes to the way we
collect simplifiers).

Bootstrap and regtest is still ongoing on x86_64-unknown-linux-gnu.

Richard.

2014-08-26  Richard Biener  <rguent...@suse.de>

        * Makefile.in (gimple-match.o-warn): Add -Wno-unused-variable.
        (generic-match.o-warn): Likewise.
        * genmatch.c (struct if_or_with): New.
        (struct simplify): Change ifexpr vector to a vector of
        if_or_with.
        (dt_simplify::gen): Adjust.
        (parse_simplify): Parse (with {} op).
        * match.pd ((T1)(~(T2)X) into ~(T1)X): Move to...
        * match-conversions.pd: ...this new file.  Implement basic
        conversion simplification.

Index: gcc/Makefile.in
===================================================================
*** gcc/Makefile.in.orig        2014-08-26 12:08:22.997747892 +0200
--- gcc/Makefile.in     2014-08-26 12:09:30.712743230 +0200
*************** gengtype-lex.o-warn = -Wno-error
*** 200,205 ****
--- 200,207 ----
  libgcov-util.o-warn = -Wno-error
  libgcov-driver-tool.o-warn = -Wno-error
  libgcov-merge-tool.o-warn = -Wno-error
+ gimple-match.o-warn = -Wno-unused-variable
+ generic-match.o-warn = -Wno-unused-variable
  
  # All warnings have to be shut off in stage1 if the compiler used then
  # isn't gcc; configure determines that.  WARN_CFLAGS will be either
Index: gcc/genmatch.c
===================================================================
*** gcc/genmatch.c.orig 2014-08-26 12:08:22.999747891 +0200
--- gcc/genmatch.c      2014-08-26 12:30:42.732655652 +0200
*************** e_operation::e_operation (const char *id
*** 380,389 ****
    operators->find_slot_with_hash (op, op->hashval, INSERT);
  }
  
  struct simplify {
    simplify (const char *name_,
            operand *match_, source_location match_location_,
!           struct operand *result_, source_location result_location_, 
vec<operand *> ifexpr_vec_ = vNULL)
        : name (name_), match (match_), match_location (match_location_),
        result (result_), result_location (result_location_),
        ifexpr_vec (ifexpr_vec_) {}
--- 380,397 ----
    operators->find_slot_with_hash (op, op->hashval, INSERT);
  }
  
+ struct if_or_with {
+     if_or_with (operand *cexpr_, source_location location_, bool is_with_)
+       : location (location_), cexpr (cexpr_), is_with (is_with_) {}
+     source_location location;
+     operand *cexpr;
+     bool is_with;
+ };
+ 
  struct simplify {
    simplify (const char *name_,
            operand *match_, source_location match_location_,
!           struct operand *result_, source_location result_location_, 
vec<if_or_with> ifexpr_vec_ = vNULL)
        : name (name_), match (match_), match_location (match_location_),
        result (result_), result_location (result_location_),
        ifexpr_vec (ifexpr_vec_) {}
*************** struct simplify {
*** 393,399 ****
    source_location match_location;
    struct operand *result;
    source_location result_location;
!   vec<operand *> ifexpr_vec;
  };
  
  struct dt_node
--- 401,407 ----
    source_location match_location;
    struct operand *result;
    source_location result_location;
!   vec<if_or_with> ifexpr_vec;
  };
  
  struct dt_node
*************** dt_simplify::gen (FILE *f, bool gimple)
*** 1705,1727 ****
        fprintf (f, "captures[%u] = %s;\n", i, indexes[i]->get_name (opname));
        }
  
    if (s->ifexpr_vec != vNULL)
      {
!       fprintf (f, "if (");
!       if (s->ifexpr_vec.length () == 1)
!       s->ifexpr_vec[0]->gen_transform (f, NULL, true, 1, "type");
!       else
!       // we add in LIFO order, so traverse backwards
!       for (unsigned i = s->ifexpr_vec.length (); i; --i)
!         {
!           fprintf (f, "(");
!           s->ifexpr_vec[i - 1]->gen_transform (f, NULL, true, 1, "type");
!           fprintf (f, ")");
!           if (i > 1)
!             fprintf (f, "\n&& ");
!         }
!       fprintf (f, ")\n");
        fprintf (f, "{\n");
      }
  
    if (gimple)
--- 1713,1762 ----
        fprintf (f, "captures[%u] = %s;\n", i, indexes[i]->get_name (opname));
        }
  
+   unsigned n_braces = 0;
    if (s->ifexpr_vec != vNULL)
      {
!       // we add in LIFO order, so traverse backwards
!       for (int i = s->ifexpr_vec.length () - 1; i >= 0; --i)
!       {
!         if_or_with &w = s->ifexpr_vec[i];
!         output_line_directive (f, w.location);
!         if (w.is_with)
!           {
!             fprintf (f, "{\n");
!             w.cexpr->gen_transform (f, NULL, true, 1, "type");
!             n_braces++;
!           }
!         else
!           {
!             fprintf (f, "if (");
!             if (i == 0 || s->ifexpr_vec[i-1].is_with)
!               w.cexpr->gen_transform (f, NULL, true, 1, "type");
!             else
!               {
!                 int j = i;
!                 do
!                   {
!                     if (j != i)
!                       {
!                         fprintf (f, "\n");
!                         output_line_directive (f, s->ifexpr_vec[j].location);
!                         fprintf (f, "&& ");
!                       }
!                     fprintf (f, "(");
!                     s->ifexpr_vec[j].cexpr->gen_transform (f, NULL,
!                                                            true, 1, "type");
!                     fprintf (f, ")");
!                     --j;
!                   }
!                 while (j >= 0 && !s->ifexpr_vec[j].is_with);
!                 i = j + 1;
!               }
!             fprintf (f, ")\n");
!           }
!       }
        fprintf (f, "{\n");
+       n_braces++;
      }
  
    if (gimple)
*************** dt_simplify::gen (FILE *f, bool gimple)
*** 1785,1791 ****
        gcc_unreachable ();
      }
  
!   if (s->ifexpr_vec != vNULL)
      fprintf (f, "}\n");
  
    fprintf (f, "}\n");
--- 1820,1826 ----
        gcc_unreachable ();
      }
  
!   for (unsigned i = 0; i < n_braces; ++i)
      fprintf (f, "}\n");
  
    fprintf (f, "}\n");
*************** parse_expr (cpp_reader *r)
*** 2142,2148 ****
  /* Parse [({] .... [})] literally recording everything as string and only
     replacing captures.  */
  
! static operand *
  parse_c_expr (cpp_reader *r, cpp_ttype start)
  {
    /* ???  Use an obstack to build the string.  */
--- 2177,2183 ----
  /* Parse [({] .... [})] literally recording everything as string and only
     replacing captures.  */
  
! static c_expr *
  parse_c_expr (cpp_reader *r, cpp_ttype start)
  {
    /* ???  Use an obstack to build the string.  */
*************** parse_op (cpp_reader *r)
*** 2240,2249 ****
  
  /* Return a reversed copy of V.  */
  
! static vec<operand *>
! copy_reverse (vec<operand *> v)
  {
!   vec<operand *> c = vNULL;
    for (int i = v.length ()-1; i >= 0; --i)
      c.safe_push (v[i]);
    return c;
--- 2275,2285 ----
  
  /* Return a reversed copy of V.  */
  
! template <class T>
! static vec<T>
! copy_reverse (vec<T> v)
  {
!   vec<T> c = vNULL;
    for (int i = v.length ()-1; i >= 0; --i)
      c.safe_push (v[i]);
    return c;
*************** copy_reverse (vec<operand *> v)
*** 2252,2259 ****
  /* Parse
       'simplify' [ <ident> ] <expr> <result-op>
     with
!      <result-op> = <op> | <cond-result>
!      <cond-result> = '(' 'if' '(' <c-expr> ')' <result-op> ')'
     and fill SIMPLIFIERS with the results.  */
  
  static void
--- 2288,2296 ----
  /* Parse
       'simplify' [ <ident> ] <expr> <result-op>
     with
!      <result-op> = <op> | <if> | <with>
!      <if> = '(' 'if' '(' <c-expr> ')' <result-op> ')'
!      <with> = '(' 'with' '{' <c-expr> '}' <result-op> ')'
     and fill SIMPLIFIERS with the results.  */
  
  static void
*************** parse_simplify (cpp_reader *r, source_lo
*** 2278,2284 ****
  
    token = peek (r);
  
!   auto_vec<operand *> ifexprs;
    while (1)
      {
        if (token->type == CPP_OPEN_PAREN)
--- 2315,2321 ----
  
    token = peek (r);
  
!   auto_vec<if_or_with> ifexprs;
    while (1)
      {
        if (token->type == CPP_OPEN_PAREN)
*************** parse_simplify (cpp_reader *r, source_lo
*** 2287,2293 ****
          if (peek_ident (r, "if"))
            {
              eat_ident (r, "if");
!             ifexprs.safe_push (parse_c_expr (r, CPP_OPEN_PAREN));
            }
          else
            {
--- 2324,2339 ----
          if (peek_ident (r, "if"))
            {
              eat_ident (r, "if");
!             ifexprs.safe_push (if_or_with (parse_c_expr (r, CPP_OPEN_PAREN),
!                                            token->src_loc, false));
!           }
!         else if (peek_ident (r, "with"))
!           {
!             eat_ident (r, "with");
!             /* Parse (with c-expr expr) as (if-with (true) expr).  */
!             c_expr *e = parse_c_expr (r, CPP_OPEN_BRACE);
!             e->nr_stmts = 0;
!             ifexprs.safe_push (if_or_with (e, token->src_loc, true));
            }
          else
            {
*************** parse_for (cpp_reader *r, source_locatio
*** 2383,2391 ****
              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]);
!             vec<operand *> ifexpr_vec = vNULL;
              for (unsigned j = 0; j < s->ifexpr_vec.length (); ++j)
!               ifexpr_vec.safe_push (replace_id (s->ifexpr_vec[j], user_id, 
opers[i]));
              simplify *ns = new simplify (s->name, match_op, s->match_location,
                                           result_op, s->result_location, 
ifexpr_vec);
  
--- 2429,2437 ----
              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]);
!             vec<if_or_with> ifexpr_vec = vNULL;
              for (unsigned j = 0; j < s->ifexpr_vec.length (); ++j)
!               ifexpr_vec.safe_push (if_or_with (replace_id 
(s->ifexpr_vec[j].cexpr, user_id, opers[i]), s->ifexpr_vec[j].location, 
s->ifexpr_vec[j].is_with));
              simplify *ns = new simplify (s->name, match_op, s->match_location,
                                           result_op, s->result_location, 
ifexpr_vec);
  
*************** parse_for (cpp_reader *r, source_locatio
*** 2396,2402 ****
  }
  
  void
! parse_if (cpp_reader *r, vec<simplify *>& simplifiers)
  {
    operand *ifexpr = parse_c_expr (r, CPP_OPEN_PAREN);
  
--- 2442,2448 ----
  }
  
  void
! parse_if (cpp_reader *r, source_location loc, vec<simplify *>& simplifiers)
  {
    operand *ifexpr = parse_c_expr (r, CPP_OPEN_PAREN);
  
*************** parse_if (cpp_reader *r, vec<simplify *>
*** 2416,2422 ****
      }
  
    for (unsigned i = pos; i < simplifiers.length (); ++i)
!     simplifiers[i]->ifexpr_vec.safe_push (ifexpr);
  }
  
  static size_t
--- 2462,2468 ----
      }
  
    for (unsigned i = pos; i < simplifiers.length (); ++i)
!     simplifiers[i]->ifexpr_vec.safe_push (if_or_with (ifexpr, loc, false));
  }
  
  static size_t
*************** parse_pattern (cpp_reader *r, vec<simpli
*** 2437,2443 ****
    else if (strcmp (id, "for") == 0)
      parse_for (r, token->src_loc, simplifiers); 
    else if (strcmp (id, "if") == 0)
!     parse_if (r, simplifiers);
    else
      fatal_at (token, "expected 'simplify' or 'for' or 'if'");
  
--- 2483,2489 ----
    else if (strcmp (id, "for") == 0)
      parse_for (r, token->src_loc, simplifiers); 
    else if (strcmp (id, "if") == 0)
!     parse_if (r, token->src_loc, simplifiers);
    else
      fatal_at (token, "expected 'simplify' or 'for' or 'if'");
  
Index: gcc/match.pd
===================================================================
*** gcc/match.pd.orig   2014-08-26 12:08:22.999747891 +0200
--- gcc/match.pd        2014-08-26 12:09:30.713743229 +0200
*************** along with GCC; see the file COPYING3.
*** 107,126 ****
    (abs @0))
  
  
- /* From fold_unary.  */
- 
- /* Convert (T1)(~(T2)X) into ~(T1)X if T1 and T2 are integral types
-    of the same precision, and X is an integer type not narrower than
-    types T1 or T2, i.e. the cast (T2)X isn't an extension.  */
- (simplify
-  (convert (bit_not@0 (convert @1)))
-  (if (INTEGRAL_TYPE_P (type)
-       && INTEGRAL_TYPE_P (TREE_TYPE (@0))
-       && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (@0))
-       && INTEGRAL_TYPE_P (TREE_TYPE (@1))
-       && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@1)))
-   (bit_not (convert @1))))
- 
  
  #include "match-plusminus.pd"
  #include "match-bitwise.pd"
--- 107,112 ----
*************** along with GCC; see the file COPYING3.
*** 128,133 ****
--- 114,120 ----
  #include "match-builtin.pd"
  #include "match-constant-folding.pd"
  #include "match-comparison.pd"
+ #include "match-conversions.pd"
  
  /* ????s
  
Index: gcc/match-conversions.pd
===================================================================
*** /dev/null   1970-01-01 00:00:00.000000000 +0000
--- gcc/match-conversions.pd    2014-08-26 12:19:53.714700337 +0200
***************
*** 0 ****
--- 1,145 ----
+ #if GIMPLE
+ /* Basic strip-useless-type-conversions.  */
+ (simplify
+   (convert @0)
+   (if (useless_type_conversion_p (type, TREE_TYPE (@0)))
+    @0))
+ #endif
+ 
+ 
+ /* From fold_unary in order of appearance.  */
+ 
+ #if GENERIC
+ /* For GIMPLE this is convered by the useless_type_conversion stripping.  */
+ (simplify
+   (convert @0)
+   (if (type == TREE_TYPE (@0))
+    @0))
+ #endif
+ 
+ /* Convert (T1)(~(T2)X) into ~(T1)X if T1 and T2 are integral types
+    of the same precision, and X is an integer type not narrower than
+    types T1 or T2, i.e. the cast (T2)X isn't an extension.  */
+ (simplify
+  (convert (bit_not@0 (convert @1)))
+  (if (INTEGRAL_TYPE_P (type)
+       && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (@0))
+       && INTEGRAL_TYPE_P (TREE_TYPE (@1))
+       && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@1)))
+   (bit_not (convert @1))))
+ 
+ 
+ /* From tree-ssa-forwprop.c:combine_conversions.  */
+ 
+ /* Combine two conversions in a row.  */
+ (for ocvt in convert float fix_trunc
+  (for icvt in convert float
+   (simplify
+    (ocvt (icvt@1 @0))
+    (with
+     {
+       tree inside_type = TREE_TYPE (@0);
+       tree inter_type = TREE_TYPE (@1);
+       int inside_int = INTEGRAL_TYPE_P (inside_type);
+       int inside_ptr = POINTER_TYPE_P (inside_type);
+       int inside_float = FLOAT_TYPE_P (inside_type);
+       int inside_vec = TREE_CODE (inside_type) == VECTOR_TYPE;
+       unsigned int inside_prec = TYPE_PRECISION (inside_type);
+       int inside_unsignedp = TYPE_UNSIGNED (inside_type);
+       int inter_int = INTEGRAL_TYPE_P (inter_type);
+       int inter_ptr = POINTER_TYPE_P (inter_type);
+       int inter_float = FLOAT_TYPE_P (inter_type);
+       int inter_vec = TREE_CODE (inter_type) == VECTOR_TYPE;
+       unsigned int inter_prec = TYPE_PRECISION (inter_type);
+       int inter_unsignedp = TYPE_UNSIGNED (inter_type);
+       int final_int = INTEGRAL_TYPE_P (type);
+       int final_ptr = POINTER_TYPE_P (type);
+       int final_float = FLOAT_TYPE_P (type);
+       int final_vec = TREE_CODE (type) == VECTOR_TYPE;
+       unsigned int final_prec = TYPE_PRECISION (type);
+       int final_unsignedp = TYPE_UNSIGNED (type);
+     }
+    /* In addition to the cases of two conversions in a row
+       handled below, if we are converting something to its own
+       type via an object of identical or wider precision, neither
+       conversion is needed.  */
+    (if (useless_type_conversion_p (type, inside_type)
+       && (((inter_int || inter_ptr) && final_int)
+           || (inter_float && final_float))
+       && inter_prec >= final_prec)
+       /* But useless_type_conversion_p is not strict enough for
+          GENERIC so leave a conversion to the final type here.  */
+       (convert @0))
+ 
+    /* Likewise, if the intermediate and initial types are either both
+       float or both integer, we don't need the middle conversion if the
+       former is wider than the latter and doesn't change the signedness
+       (for integers).  Avoid this if the final type is a pointer since
+       then we sometimes need the middle conversion.  Likewise if the
+       final type has a precision not equal to the size of its mode.  */
+    (if (((inter_int && inside_int)
+        || (inter_float && inside_float)
+        || (inter_vec && inside_vec))
+       && inter_prec >= inside_prec
+       && (inter_float || inter_vec
+           || inter_unsignedp == inside_unsignedp)
+       && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
+             && TYPE_MODE (type) == TYPE_MODE (inter_type))
+       && ! final_ptr
+       && (! final_vec || inter_prec == inside_prec))
+     (convert @0))
+ 
+    /* If we have a sign-extension of a zero-extended value, we can
+       replace that by a single zero-extension.  Likewise if the
+       final conversion does not change precision we can drop the
+       intermediate conversion.  */
+    (if (inside_int && inter_int && final_int
+       && ((inside_prec < inter_prec && inter_prec < final_prec
+            && inside_unsignedp && !inter_unsignedp)
+           || final_prec == inter_prec))
+     (convert @0))
+ 
+    /* Two conversions in a row are not needed unless:
+       - some conversion is floating-point (overstrict for now), or
+       - some conversion is a vector (overstrict for now), or
+       - the intermediate type is narrower than both initial and
+         final, or
+       - the intermediate type and innermost type differ in signedness,
+         and the outermost type is wider than the intermediate, or
+       - the initial type is a pointer type and the precisions of the
+         intermediate and final types differ, or
+       - the final type is a pointer type and the precisions of the
+         initial and intermediate types differ.  */
+    (if (! inside_float && ! inter_float && ! final_float
+       && ! inside_vec && ! inter_vec && ! final_vec
+       && (inter_prec >= inside_prec || inter_prec >= final_prec)
+       && ! (inside_int && inter_int
+             && inter_unsignedp != inside_unsignedp
+             && inter_prec < final_prec)
+       && ((inter_unsignedp && inter_prec > inside_prec)
+           == (final_unsignedp && final_prec > inter_prec))
+       && ! (inside_ptr && inter_prec != final_prec)
+       && ! (final_ptr && inside_prec != inter_prec)
+       && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
+             && TYPE_MODE (type) == TYPE_MODE (inter_type)))
+     (convert @0))
+ 
+    /* A truncation to an unsigned type should be canonicalized as
+       bitwise and of a mask.  */
+    (if (final_int && inter_int && inside_int
+       && final_prec == inside_prec
+       && final_prec > inter_prec
+       && inter_unsignedp)
+     (convert (bit_and @0 { wide_int_to_tree
+             (inside_type,
+              wi::mask (inter_prec, false,
+                        TYPE_PRECISION (inside_type))); })))
+ 
+    /* If we are converting an integer to a floating-point that can
+       represent it exactly and back to an integer, we can skip the
+       floating-point conversion.  */
+    (if (inside_int && inter_float && final_int &&
+       (unsigned) significand_size (TYPE_MODE (inter_type))
+       >= inside_prec - !inside_unsignedp)
+     (convert @0))))))

Reply via email to