]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-ssa-math-opts.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / tree-ssa-math-opts.c
index 1f28679ef2e8fc79202d9c77dc2d1cc14b9236e0..c4a6492b50df25b4cf296a75bd51e5af34eeacc7 100644 (file)
@@ -115,6 +115,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "targhooks.h"
 #include "domwalk.h"
+#include "tree-ssa-math-opts.h"
 
 /* This structure represents one basic block that either computes a
    division, or is a common dominator for basic block that compute a
@@ -1284,7 +1285,7 @@ execute_cse_sincos_1 (tree name)
         and, in subsequent rounds, that the built_in type is the same
         type, or a compatible type.  */
       if (type != t && !types_compatible_p (type, t))
-       RETURN_FROM_IMM_USE_STMT (use_iter, false);
+       return false;
     }
   if (seen_cos + seen_sin + seen_cexpi <= 1)
     return false;
@@ -1527,7 +1528,7 @@ powi_as_mults_1 (gimple_stmt_iterator *gsi, location_t loc, tree type,
 /* Convert ARG0**N to a tree of multiplications of ARG0 with itself.
    This function needs to be kept in sync with powi_cost above.  */
 
-static tree
+tree
 powi_as_mults (gimple_stmt_iterator *gsi, location_t loc,
               tree arg0, HOST_WIDE_INT n)
 {
@@ -1536,9 +1537,9 @@ powi_as_mults (gimple_stmt_iterator *gsi, location_t loc,
   tree target;
 
   if (n == 0)
-    return build_real (type, dconst1);
+    return build_one_cst (type);
 
-  memset (cache, 0,  sizeof (cache));
+  memset (cache, 0, sizeof (cache));
   cache[1] = arg0;
 
   result = powi_as_mults_1 (gsi, loc, type, (n < 0) ? -n : n, cache);
@@ -3251,8 +3252,8 @@ convert_mult_to_fma (gimple *mul_stmt, tree op1, tree op2,
 
   bool check_defer
     = (state->m_deferring_p
-       && (tree_to_shwi (TYPE_SIZE (type))
-          <= param_avoid_fma_max_bits));
+       && maybe_le (tree_to_poly_int64 (TYPE_SIZE (type)),
+                   param_avoid_fma_max_bits));
   bool defer = check_defer;
   bool seen_negate_p = false;
   /* Make sure that the multiplication statement becomes dead after
@@ -3471,7 +3472,7 @@ convert_mult_to_fma (gimple *mul_stmt, tree op1, tree op2,
    optimize the x_4(D) != 0 condition to 1.  */
 
 static void
-maybe_optimize_guarding_check (gimple **mul_stmts, gimple *cond_stmt,
+maybe_optimize_guarding_check (vec<gimple *> &mul_stmts, gimple *cond_stmt,
                               gimple *div_stmt, bool *cfg_changed)
 {
   basic_block bb = gimple_bb (cond_stmt);
@@ -3525,37 +3526,34 @@ maybe_optimize_guarding_check (gimple **mul_stmts, gimple *cond_stmt,
              != TYPE_PRECISION (TREE_TYPE (rhs2))))
        return;
     }
-  gimple_stmt_iterator gsi = gsi_for_stmt (div_stmt);
-  gsi_prev_nondebug (&gsi);
-  if (!gsi_end_p (gsi))
+  gimple_stmt_iterator gsi = gsi_after_labels (bb);
+  mul_stmts.quick_push (div_stmt);
+  if (is_gimple_debug (gsi_stmt (gsi)))
+    gsi_next_nondebug (&gsi);
+  unsigned cast_count = 0;
+  while (gsi_stmt (gsi) != cond_stmt)
     {
       /* If original mul_stmt has a single use, allow it in the same bb,
         we are looking then just at __builtin_mul_overflow_p.
         Though, in that case the original mul_stmt will be replaced
         by .MUL_OVERFLOW, REALPART_EXPR and IMAGPART_EXPR stmts.  */
-      for (int i = 2; i >= 0; --i)
-       {
-         if (gsi_stmt (gsi) != mul_stmts[i])
-           return;
-         gsi_prev_nondebug (&gsi);
-       }
-      /* Allow up to 2 extra casts.  Given the way we check PHIs,
-        nothing from this bb should be consumed by any other bb
-        anyway.  */
-      for (int i = 0; i < 2 && !gsi_end_p (gsi); i++)
+      gimple *mul_stmt;
+      unsigned int i;
+      bool ok = false;
+      FOR_EACH_VEC_ELT (mul_stmts, i, mul_stmt)
        {
-         gimple *g = gsi_stmt (gsi);
-         if (!gimple_assign_cast_p (g))
-           return;
-         gsi_prev_nondebug (&gsi);
+         if (gsi_stmt (gsi) == mul_stmt)
+           {
+             ok = true;
+             break;
+           }
        }
-      if (!gsi_end_p (gsi))
+      if (!ok && gimple_assign_cast_p (gsi_stmt (gsi)) && ++cast_count < 4)
+       ok = true;
+      if (!ok)
        return;
+      gsi_next_nondebug (&gsi);
     }
-  gsi = gsi_for_stmt (div_stmt);
-  gsi_next_nondebug (&gsi);
-  if (gsi_stmt (gsi) != cond_stmt)
-    return;
   if (gimple_code (cond_stmt) == GIMPLE_COND)
     {
       basic_block succ_bb = other_edge->dest;
@@ -3633,22 +3631,43 @@ maybe_optimize_guarding_check (gimple **mul_stmts, gimple *cond_stmt,
   *cfg_changed = true;
 }
 
+/* Helper function for arith_overflow_check_p.  Return true
+   if VAL1 is equal to VAL2 cast to corresponding integral type
+   with other signedness or vice versa.  */
+
+static bool
+arith_cast_equal_p (tree val1, tree val2)
+{
+  if (TREE_CODE (val1) == INTEGER_CST && TREE_CODE (val2) == INTEGER_CST)
+    return wi::eq_p (wi::to_wide (val1), wi::to_wide (val2));
+  else if (TREE_CODE (val1) != SSA_NAME || TREE_CODE (val2) != SSA_NAME)
+    return false;
+  if (gimple_assign_cast_p (SSA_NAME_DEF_STMT (val1))
+      && gimple_assign_rhs1 (SSA_NAME_DEF_STMT (val1)) == val2)
+    return true;
+  if (gimple_assign_cast_p (SSA_NAME_DEF_STMT (val2))
+      && gimple_assign_rhs1 (SSA_NAME_DEF_STMT (val2)) == val1)
+    return true;
+  return false;
+}
+
 /* Helper function of match_arith_overflow.  Return 1
    if USE_STMT is unsigned overflow check ovf != 0 for
    STMT, -1 if USE_STMT is unsigned overflow check ovf == 0
    and 0 otherwise.  */
 
 static int
-arith_overflow_check_p (gimple *stmt, gimple *&use_stmt, tree maxval,
-                       tree *other)
+arith_overflow_check_p (gimple *stmt, gimple *cast_stmt, gimple *&use_stmt,
+                       tree maxval, tree *other)
 {
   enum tree_code ccode = ERROR_MARK;
   tree crhs1 = NULL_TREE, crhs2 = NULL_TREE;
   enum tree_code code = gimple_assign_rhs_code (stmt);
-  tree lhs = gimple_assign_lhs (stmt);
+  tree lhs = gimple_assign_lhs (cast_stmt ? cast_stmt : stmt);
   tree rhs1 = gimple_assign_rhs1 (stmt);
   tree rhs2 = gimple_assign_rhs2 (stmt);
   tree multop = NULL_TREE, divlhs = NULL_TREE;
+  gimple *cur_use_stmt = use_stmt;
 
   if (code == MULT_EXPR)
     {
@@ -3658,7 +3677,16 @@ arith_overflow_check_p (gimple *stmt, gimple *&use_stmt, tree maxval,
        return 0;
       if (gimple_assign_rhs1 (use_stmt) != lhs)
        return 0;
-      if (gimple_assign_rhs2 (use_stmt) == rhs1)
+      if (cast_stmt)
+       {
+         if (arith_cast_equal_p (gimple_assign_rhs2 (use_stmt), rhs1))
+           multop = rhs2;
+         else if (arith_cast_equal_p (gimple_assign_rhs2 (use_stmt), rhs2))
+           multop = rhs1;
+         else
+           return 0;
+       }
+      else if (gimple_assign_rhs2 (use_stmt) == rhs1)
        multop = rhs2;
       else if (operand_equal_p (gimple_assign_rhs2 (use_stmt), rhs2, 0))
        multop = rhs1;
@@ -3670,26 +3698,26 @@ arith_overflow_check_p (gimple *stmt, gimple *&use_stmt, tree maxval,
       if (!divlhs)
        return 0;
       use_operand_p use;
-      if (!single_imm_use (divlhs, &use, &use_stmt))
+      if (!single_imm_use (divlhs, &use, &cur_use_stmt))
        return 0;
     }
-  if (gimple_code (use_stmt) == GIMPLE_COND)
+  if (gimple_code (cur_use_stmt) == GIMPLE_COND)
     {
-      ccode = gimple_cond_code (use_stmt);
-      crhs1 = gimple_cond_lhs (use_stmt);
-      crhs2 = gimple_cond_rhs (use_stmt);
+      ccode = gimple_cond_code (cur_use_stmt);
+      crhs1 = gimple_cond_lhs (cur_use_stmt);
+      crhs2 = gimple_cond_rhs (cur_use_stmt);
     }
-  else if (is_gimple_assign (use_stmt))
+  else if (is_gimple_assign (cur_use_stmt))
     {
-      if (gimple_assign_rhs_class (use_stmt) == GIMPLE_BINARY_RHS)
+      if (gimple_assign_rhs_class (cur_use_stmt) == GIMPLE_BINARY_RHS)
        {
-         ccode = gimple_assign_rhs_code (use_stmt);
-         crhs1 = gimple_assign_rhs1 (use_stmt);
-         crhs2 = gimple_assign_rhs2 (use_stmt);
+         ccode = gimple_assign_rhs_code (cur_use_stmt);
+         crhs1 = gimple_assign_rhs1 (cur_use_stmt);
+         crhs2 = gimple_assign_rhs2 (cur_use_stmt);
        }
-      else if (gimple_assign_rhs_code (use_stmt) == COND_EXPR)
+      else if (gimple_assign_rhs_code (cur_use_stmt) == COND_EXPR)
        {
-         tree cond = gimple_assign_rhs1 (use_stmt);
+         tree cond = gimple_assign_rhs1 (cur_use_stmt);
          if (COMPARISON_CLASS_P (cond))
            {
              ccode = TREE_CODE (cond);
@@ -3759,10 +3787,24 @@ arith_overflow_check_p (gimple *stmt, gimple *&use_stmt, tree maxval,
         r = a * b; _1 = r / b; _1 == a
         r = a * b; _1 = r / a; _1 != b
         r = a * b; _1 = r / b; _1 != a.  */
-      if (code == MULT_EXPR
-         && ((crhs1 == divlhs && operand_equal_p (crhs2, multop, 0))
-             || (crhs2 == divlhs && crhs1 == multop)))
-       return ccode == NE_EXPR ? 1 : -1;
+      if (code == MULT_EXPR)
+       {
+         if (cast_stmt)
+           {
+             if ((crhs1 == divlhs && arith_cast_equal_p (crhs2, multop))
+                 || (crhs2 == divlhs && arith_cast_equal_p (crhs1, multop)))
+               {
+                 use_stmt = cur_use_stmt;
+                 return ccode == NE_EXPR ? 1 : -1;
+               }
+           }
+         else if ((crhs1 == divlhs && operand_equal_p (crhs2, multop, 0))
+                  || (crhs2 == divlhs && crhs1 == multop))
+           {
+             use_stmt = cur_use_stmt;
+             return ccode == NE_EXPR ? 1 : -1;
+           }
+       }
       break;
     default:
       break;
@@ -3837,6 +3879,8 @@ match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
   gimple *add_stmt = NULL;
   bool add_first = false;
   gimple *cond_stmt = NULL;
+  gimple *cast_stmt = NULL;
+  tree cast_lhs = NULL_TREE;
 
   gcc_checking_assert (code == PLUS_EXPR
                       || code == MINUS_EXPR
@@ -3860,7 +3904,7 @@ match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
        continue;
 
       tree other = NULL_TREE;
-      if (arith_overflow_check_p (stmt, use_stmt, NULL_TREE, &other))
+      if (arith_overflow_check_p (stmt, NULL, use_stmt, NULL_TREE, &other))
        {
          if (code == BIT_NOT_EXPR)
            {
@@ -3875,12 +3919,51 @@ match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
            }
          ovf_use_seen = true;
        }
-      else
-       use_seen = true;
+      else 
+       {
+         use_seen = true;
+         if (code == MULT_EXPR
+             && cast_stmt == NULL
+             && gimple_assign_cast_p (use_stmt))
+           {
+             cast_lhs = gimple_assign_lhs (use_stmt);
+             if (INTEGRAL_TYPE_P (TREE_TYPE (cast_lhs))
+                 && !TYPE_UNSIGNED (TREE_TYPE (cast_lhs))
+                 && (TYPE_PRECISION (TREE_TYPE (cast_lhs))
+                     == TYPE_PRECISION (TREE_TYPE (lhs))))
+               cast_stmt = use_stmt;
+             else
+               cast_lhs = NULL_TREE;
+           }
+       }
       if (ovf_use_seen && use_seen)
        break;
     }
 
+  if (!ovf_use_seen
+      && code == MULT_EXPR
+      && cast_stmt)
+    {
+      if (TREE_CODE (rhs1) != SSA_NAME
+         || (TREE_CODE (rhs2) != SSA_NAME && TREE_CODE (rhs2) != INTEGER_CST))
+       return false;
+      FOR_EACH_IMM_USE_FAST (use_p, iter, cast_lhs)
+       {
+         use_stmt = USE_STMT (use_p);
+         if (is_gimple_debug (use_stmt))
+           continue;
+
+         if (arith_overflow_check_p (stmt, cast_stmt, use_stmt,
+                                     NULL_TREE, NULL))
+           ovf_use_seen = true;
+       }
+    }
+  else
+    {
+      cast_stmt = NULL;
+      cast_lhs = NULL_TREE;
+    }
+
   tree maxval = NULL_TREE;
   if (!ovf_use_seen
       || (code != MULT_EXPR && (code == BIT_NOT_EXPR ? use_seen : !use_seen))
@@ -3888,7 +3971,7 @@ match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
          && optab_handler (uaddv4_optab,
                            TYPE_MODE (type)) == CODE_FOR_nothing)
       || (code == MULT_EXPR
-         && optab_handler (umulv4_optab,
+         && optab_handler (cast_stmt ? mulv4_optab : umulv4_optab,
                            TYPE_MODE (type)) == CODE_FOR_nothing))
     {
       if (code != PLUS_EXPR)
@@ -3947,7 +4030,7 @@ match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
          if (is_gimple_debug (use_stmt))
            continue;
 
-         if (arith_overflow_check_p (stmt, use_stmt, maxval, NULL))
+         if (arith_overflow_check_p (stmt, NULL, use_stmt, maxval, NULL))
            {
              ovf_use_seen = true;
              use_bb = gimple_bb (use_stmt);
@@ -4066,6 +4149,42 @@ match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
   if (code == BIT_NOT_EXPR)
     *gsi = gsi_for_stmt (cond_stmt);
 
+  auto_vec<gimple *, 8> mul_stmts;
+  if (code == MULT_EXPR && cast_stmt)
+    {
+      type = TREE_TYPE (cast_lhs);
+      gimple *g = SSA_NAME_DEF_STMT (rhs1);
+      if (gimple_assign_cast_p (g)
+         && useless_type_conversion_p (type,
+                                       TREE_TYPE (gimple_assign_rhs1 (g)))
+         && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (g)))
+       rhs1 = gimple_assign_rhs1 (g);
+      else
+       {
+         g = gimple_build_assign (make_ssa_name (type), NOP_EXPR, rhs1);
+         gsi_insert_before (gsi, g, GSI_SAME_STMT);
+         rhs1 = gimple_assign_lhs (g);
+         mul_stmts.quick_push (g);
+       }
+      if (TREE_CODE (rhs2) == INTEGER_CST)
+       rhs2 = fold_convert (type, rhs2);
+      else
+       {
+         g = SSA_NAME_DEF_STMT (rhs2);
+         if (gimple_assign_cast_p (g)
+             && useless_type_conversion_p (type,
+                                           TREE_TYPE (gimple_assign_rhs1 (g)))
+             && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (g)))
+           rhs2 = gimple_assign_rhs1 (g);
+         else
+           {
+             g = gimple_build_assign (make_ssa_name (type), NOP_EXPR, rhs2);
+             gsi_insert_before (gsi, g, GSI_SAME_STMT);
+             rhs2 = gimple_assign_lhs (g);
+             mul_stmts.quick_push (g);
+           }
+       }
+    }
   tree ctype = build_complex_type (type);
   gcall *g = gimple_build_call_internal (code == MULT_EXPR
                                         ? IFN_MUL_OVERFLOW
@@ -4075,14 +4194,13 @@ match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
   tree ctmp = make_ssa_name (ctype);
   gimple_call_set_lhs (g, ctmp);
   gsi_insert_before (gsi, g, GSI_SAME_STMT);
-  tree new_lhs = maxval ? make_ssa_name (type) : lhs;
-  gimple *mul_stmts[3] = { NULL, NULL, NULL };
+  tree new_lhs = (maxval || cast_stmt) ? make_ssa_name (type) : lhs;
   gassign *g2;
   if (code != BIT_NOT_EXPR)
     {
       g2 = gimple_build_assign (new_lhs, REALPART_EXPR,
                                build1 (REALPART_EXPR, type, ctmp));
-      if (maxval)
+      if (maxval || cast_stmt)
        {
          gsi_insert_before (gsi, g2, GSI_SAME_STMT);
          if (add_first)
@@ -4092,8 +4210,14 @@ match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
        gsi_replace (gsi, g2, true);
       if (code == MULT_EXPR)
        {
-         mul_stmts[0] = g;
-         mul_stmts[1] = g2;
+         mul_stmts.quick_push (g);
+         mul_stmts.quick_push (g2);
+         if (cast_stmt)
+           {
+             g2 = gimple_build_assign (lhs, NOP_EXPR, new_lhs);
+             gsi_replace (gsi, g2, true);
+             mul_stmts.quick_push (g2);
+           }
        }
     }
   tree ovf = make_ssa_name (type);
@@ -4104,15 +4228,16 @@ match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
   else
     gsi_insert_before (gsi, g2, GSI_SAME_STMT);
   if (code == MULT_EXPR)
-    mul_stmts[2] = g2;
+    mul_stmts.quick_push (g2);
 
-  FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
+  FOR_EACH_IMM_USE_STMT (use_stmt, iter, cast_lhs ? cast_lhs : lhs)
     {
       if (is_gimple_debug (use_stmt))
        continue;
 
       gimple *orig_use_stmt = use_stmt;
-      int ovf_use = arith_overflow_check_p (stmt, use_stmt, maxval, NULL);
+      int ovf_use = arith_overflow_check_p (stmt, cast_stmt, use_stmt,
+                                           maxval, NULL);
       if (ovf_use == 0)
        {
          gcc_assert (code != BIT_NOT_EXPR);