]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-ssa-forwprop.cc
forwprop: Further fixes for simplify_rotate [PR108440]
[thirdparty/gcc.git] / gcc / tree-ssa-forwprop.cc
index c8a867ae828cbccdf1cae311d8567c4493736a56..9290d1558e5628edd67f7ea321719b00fec6fff1 100644 (file)
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "internal-fn.h"
 #include "cgraph.h"
 #include "tree-ssa.h"
+#include "gimple-range.h"
 
 /* This pass propagates the RHS of assignment statements into use
    sites of the LHS of the assignment.  It's basically a specialized
@@ -1831,8 +1832,12 @@ defcodefor_name (tree name, enum tree_code *code, tree *arg1, tree *arg2)
    ((T) ((T2) X << Y)) | ((T) ((T2) X >> ((-Y) & (B - 1))))
    ((T) ((T2) X << (int) Y)) | ((T) ((T2) X >> (int) ((-Y) & (B - 1))))
 
-   transform these into (last 2 only if ranger can prove Y < B):
+   transform these into (last 2 only if ranger can prove Y < B
+   or Y = N * B):
    X r<< Y
+   or
+   X r<< (& & (B - 1))
+   The latter for the forms with T2 wider than T if ranger can't prove Y < B.
 
    Or for:
    (X << (Y & (B - 1))) | (X >> ((-Y) & (B - 1)))
@@ -1862,6 +1867,7 @@ simplify_rotate (gimple_stmt_iterator *gsi)
   gimple *g;
   gimple *def_arg_stmt[2] = { NULL, NULL };
   int wider_prec = 0;
+  bool add_masking = false;
 
   arg[0] = gimple_assign_rhs1 (stmt);
   arg[1] = gimple_assign_rhs2 (stmt);
@@ -1989,7 +1995,7 @@ simplify_rotate (gimple_stmt_iterator *gsi)
       tree cdef_arg1[2], cdef_arg2[2], def_arg2_alt[2];
       enum tree_code cdef_code[2];
       gimple *def_arg_alt_stmt[2] = { NULL, NULL };
-      bool check_range = false;
+      int check_range = 0;
       gimple *check_range_stmt = NULL;
       /* Look through conversion of the shift count argument.
         The C/C++ FE cast any shift count argument to integer_type_node.
@@ -2030,6 +2036,11 @@ simplify_rotate (gimple_stmt_iterator *gsi)
                || cdef_arg2[i] == def_arg2_alt[1 - i])
              {
                rotcnt = cdef_arg2[i];
+               check_range = -1;
+               if (cdef_arg2[i] == def_arg2[1 - i])
+                 check_range_stmt = def_arg_stmt[1 - i];
+               else
+                 check_range_stmt = def_arg_alt_stmt[1 - i];
                break;
              }
            defcodefor_name (cdef_arg2[i], &code, &tem, NULL);
@@ -2042,6 +2053,11 @@ simplify_rotate (gimple_stmt_iterator *gsi)
                    || tem == def_arg2_alt[1 - i]))
              {
                rotcnt = tem;
+               check_range = -1;
+               if (tem == def_arg2[1 - i])
+                 check_range_stmt = def_arg_stmt[1 - i];
+               else
+                 check_range_stmt = def_arg_alt_stmt[1 - i];
                break;
              }
          }
@@ -2074,7 +2090,7 @@ simplify_rotate (gimple_stmt_iterator *gsi)
                if (tem == def_arg2[1 - i] || tem == def_arg2_alt[1 - i])
                  {
                    rotcnt = tem;
-                   check_range = true;
+                   check_range = 1;
                    if (tem == def_arg2[1 - i])
                      check_range_stmt = def_arg_stmt[1 - i];
                    else
@@ -2093,7 +2109,7 @@ simplify_rotate (gimple_stmt_iterator *gsi)
                        || tem2 == def_arg2_alt[1 - i])
                      {
                        rotcnt = tem2;
-                       check_range = true;
+                       check_range = 1;
                        if (tem2 == def_arg2[1 - i])
                          check_range_stmt = def_arg_stmt[1 - i];
                        else
@@ -2138,17 +2154,44 @@ simplify_rotate (gimple_stmt_iterator *gsi)
          if (TREE_CODE (rotcnt) != SSA_NAME)
            return false;
          int_range_max r;
-         if (!get_global_range_query ()->range_of_expr (r, rotcnt,
-                                                        check_range_stmt))
-           return false;
+         range_query *q = get_range_query (cfun);
+         if (q == get_global_range_query ())
+           q = enable_ranger (cfun);
+         if (!q->range_of_expr (r, rotcnt, check_range_stmt))
+           {
+             if (check_range > 0)
+               return false;
+             r.set_varying (TREE_TYPE (rotcnt));
+           }
          int prec = TYPE_PRECISION (TREE_TYPE (rotcnt));
          signop sign = TYPE_SIGN (TREE_TYPE (rotcnt));
          wide_int min = wide_int::from (TYPE_PRECISION (rtype), prec, sign);
          wide_int max = wide_int::from (wider_prec - 1, prec, sign);
-         int_range<2> r2 (TREE_TYPE (rotcnt), min, max);
+         if (check_range < 0)
+           max = min;
+         int_range<1> r2 (TREE_TYPE (rotcnt), min, max);
          r.intersect (r2);
          if (!r.undefined_p ())
-           return false;
+           {
+             if (check_range > 0)
+               {
+                 int_range_max r3;
+                 for (int i = TYPE_PRECISION (rtype) + 1; i < wider_prec;
+                      i += TYPE_PRECISION (rtype))
+                   {
+                     int j = i + TYPE_PRECISION (rtype) - 2;
+                     min = wide_int::from (i, prec, sign);
+                     max = wide_int::from (MIN (j, wider_prec - 1),
+                                           prec, sign);
+                     int_range<1> r4 (TREE_TYPE (rotcnt), min, max);
+                     r3.union_ (r4);
+                   }
+                 r.intersect (r3);
+                 if (!r.undefined_p ())
+                   return false;
+               }
+             add_masking = true;
+           }
        }
       if (rotcnt == NULL_TREE)
        return false;
@@ -2163,6 +2206,15 @@ simplify_rotate (gimple_stmt_iterator *gsi)
       gsi_insert_before (gsi, g, GSI_SAME_STMT);
       rotcnt = gimple_assign_lhs (g);
     }
+  if (add_masking)
+    {
+      g = gimple_build_assign (make_ssa_name (TREE_TYPE (rotcnt)),
+                              BIT_AND_EXPR, rotcnt,
+                              build_int_cst (TREE_TYPE (rotcnt),
+                                             TYPE_PRECISION (rtype) - 1));
+      gsi_insert_before (gsi, g, GSI_SAME_STMT);
+      rotcnt = gimple_assign_lhs (g);
+    }
   lhs = gimple_assign_lhs (stmt);
   if (!useless_type_conversion_p (rtype, TREE_TYPE (def_arg1[0])))
     lhs = make_ssa_name (TREE_TYPE (def_arg1[0]));
@@ -3908,6 +3960,9 @@ pass_forwprop::execute (function *fun)
   cfg_changed |= gimple_purge_all_dead_eh_edges (to_purge);
   BITMAP_FREE (to_purge);
 
+  if (get_range_query (cfun) != get_global_range_query ())
+    disable_ranger (cfun);
+
   if (cfg_changed)
     todoflags |= TODO_cleanup_cfg;