]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-ssa-uninit.c
PR fortran/95090 - ICE: identifier overflow
[thirdparty/gcc.git] / gcc / tree-ssa-uninit.c
index e019ecc9d29e019af64fdf2b077fb7b4c80fb4a1..cc785bd9d8c0d51db2c0cd00258954c965a8fee5 100644 (file)
@@ -1,5 +1,5 @@
 /* Predicate aware uninitialized variable warning.
-   Copyright (C) 2001-2017 Free Software Foundation, Inc.
+   Copyright (C) 2001-2020 Free Software Foundation, Inc.
    Contributed by Xinliang David Li <davidxl@google.com>
 
 This file is part of GCC.
@@ -31,8 +31,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "gimple-iterator.h"
 #include "tree-ssa.h"
-#include "params.h"
 #include "tree-cfg.h"
+#include "cfghooks.h"
 
 /* This implements the pass that does predicate aware warning on uses of
    possibly uninitialized variables.  The pass first collects the set of
@@ -177,6 +177,7 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
   cfun_loc = DECL_SOURCE_LOCATION (cfun->decl);
   xloc = expand_location (location);
   floc = expand_location (cfun_loc);
+  auto_diagnostic_group d;
   if (warning_at (location, wc, gmsgid, expr))
     {
       TREE_NO_WARNING (expr) = 1;
@@ -273,29 +274,56 @@ warn_uninitialized_vars (bool warn_possibly_uninitialized)
              && gimple_has_location (stmt))
            {
              tree rhs = gimple_assign_rhs1 (stmt);
+             tree lhs = gimple_assign_lhs (stmt);
+             bool has_bit_insert = false;
+             use_operand_p luse_p;
+             imm_use_iterator liter;
+
              if (TREE_NO_WARNING (rhs))
                continue;
 
              ao_ref ref;
              ao_ref_init (&ref, rhs);
 
-             /* Do not warn if it can be initialized outside this function.  */
+             /* Do not warn if the base was marked so or this is a
+                hard register var.  */
              tree base = ao_ref_base (&ref);
-             if (!VAR_P (base)
-                 || DECL_HARD_REGISTER (base)
-                 || is_global_var (base)
+             if ((VAR_P (base)
+                  && DECL_HARD_REGISTER (base))
                  || TREE_NO_WARNING (base))
                continue;
 
              /* Do not warn if the access is fully outside of the
                 variable.  */
-             if (ref.size != -1
-                 && ref.max_size == ref.size
-                 && (ref.offset + ref.size <= 0
-                     || (ref.offset >= 0
-                         && TREE_CODE (DECL_SIZE (base)) == INTEGER_CST
-                         && compare_tree_int (DECL_SIZE (base),
-                                              ref.offset) <= 0)))
+             poly_int64 decl_size;
+             if (DECL_P (base)
+                 && known_size_p (ref.size)
+                 && ((known_eq (ref.max_size, ref.size)
+                      && known_le (ref.offset + ref.size, 0))
+                     || (known_ge (ref.offset, 0)
+                         && DECL_SIZE (base)
+                         && poly_int_tree_p (DECL_SIZE (base), &decl_size)
+                         && known_le (decl_size, ref.offset))))
+               continue;
+
+             /* Do not warn if the access is then used for a BIT_INSERT_EXPR. */
+             if (TREE_CODE (lhs) == SSA_NAME)
+               FOR_EACH_IMM_USE_FAST (luse_p, liter, lhs)
+                 {
+                   gimple *use_stmt = USE_STMT (luse_p);
+                    /* BIT_INSERT_EXPR first operand should not be considered
+                      a use for the purpose of uninit warnings.  */
+                   if (gassign *ass = dyn_cast <gassign *> (use_stmt))
+                     {
+                       if (gimple_assign_rhs_code (ass) == BIT_INSERT_EXPR
+                           && luse_p->use == gimple_assign_rhs1_ptr (ass))
+                         {
+                           has_bit_insert = true;
+                           break;
+                         }
+                     }
+                 }
+             if (has_bit_insert)
                continue;
 
              /* Limit the walking to a constant number of stmts after
@@ -305,11 +333,12 @@ warn_uninitialized_vars (bool warn_possibly_uninitialized)
                  && oracle_cnt > vdef_cnt * 2)
                limit = 32;
              check_defs_data data;
+             bool fentry_reached = false;
              data.found_may_defs = false;
              use = gimple_vuse (stmt);
              int res = walk_aliased_vdefs (&ref, use,
                                            check_defs, &data, NULL,
-                                           NULL, limit);
+                                           &fentry_reached, limit);
              if (res == -1)
                {
                  oracle_cnt += limit;
@@ -318,6 +347,16 @@ warn_uninitialized_vars (bool warn_possibly_uninitialized)
              oracle_cnt += res;
              if (data.found_may_defs)
                continue;
+             /* Do not warn if it can be initialized outside this function.
+                If we did not reach function entry then we found killing
+                clobbers on all paths to entry.  */
+             if (fentry_reached
+                 /* ???  We'd like to use ref_may_alias_global_p but that
+                    excludes global readonly memory and thus we get bougs
+                    warnings from p = cond ? "a" : "b" for example.  */
+                 && (!VAR_P (base)
+                     || is_global_var (base)))
+               continue;
 
              /* We didn't find any may-defs so on all paths either
                 reached function entry or a killing clobber.  */
@@ -505,10 +544,7 @@ compute_control_dep_chain (basic_block bb, basic_block dep_bb,
   bool found_cd_chain = false;
   size_t cur_chain_len = 0;
 
-  if (EDGE_COUNT (bb->succs) < 2)
-    return false;
-
-  if (*num_calls > PARAM_VALUE (PARAM_UNINIT_CONTROL_DEP_ATTEMPTS))
+  if (*num_calls > param_uninit_control_dep_attempts)
     return false;
   ++*num_calls;
 
@@ -633,6 +669,11 @@ convert_control_dep_chain_into_preds (vec<edge> *dep_chains,
          e = one_cd_chain[j];
          guard_bb = e->src;
          gsi = gsi_last_bb (guard_bb);
+         /* Ignore empty forwarder blocks.  */
+         if (empty_block_p (guard_bb) && single_succ_p (guard_bb))
+           continue;
+         /* An empty basic block here is likely a PHI, and is not one
+            of the cases we handle below.  */
          if (gsi_end_p (gsi))
            {
              has_valid_pred = false;
@@ -683,7 +724,7 @@ convert_control_dep_chain_into_preds (vec<edge> *dep_chains,
              for (idx = 0; idx < gimple_switch_num_labels (gs); ++idx)
                {
                  tree tl = gimple_switch_label (gs, idx);
-                 if (e->dest == label_to_block (CASE_LABEL (tl)))
+                 if (e->dest == label_to_block (cfun, CASE_LABEL (tl)))
                    {
                      if (!l)
                        l = tl;
@@ -795,7 +836,7 @@ collect_phi_def_edges (gphi *phi, basic_block cd_root,
          if (dump_file && (dump_flags & TDF_DETAILS))
            {
              fprintf (dump_file, "\n[CHECK] Found def edge %d in ", (int) i);
-             print_gimple_stmt (dump_file, phi, 0, 0);
+             print_gimple_stmt (dump_file, phi, 0);
            }
          edges->safe_push (opnd_edge);
        }
@@ -813,7 +854,7 @@ collect_phi_def_edges (gphi *phi, basic_block cd_root,
                {
                  fprintf (dump_file, "\n[CHECK] Found def edge %d in ",
                           (int) i);
-                 print_gimple_stmt (dump_file, phi, 0, 0);
+                 print_gimple_stmt (dump_file, phi, 0);
                }
              edges->safe_push (opnd_edge);
            }
@@ -878,38 +919,49 @@ find_def_preds (pred_chain_union *preds, gphi *phi)
   return has_valid_pred;
 }
 
+/* Dump a pred_info.  */
+
+static void
+dump_pred_info (pred_info one_pred)
+{
+  if (one_pred.invert)
+    fprintf (dump_file, " (.NOT.) ");
+  print_generic_expr (dump_file, one_pred.pred_lhs);
+  fprintf (dump_file, " %s ", op_symbol_code (one_pred.cond_code));
+  print_generic_expr (dump_file, one_pred.pred_rhs);
+}
+
+/* Dump a pred_chain.  */
+
+static void
+dump_pred_chain (pred_chain one_pred_chain)
+{
+  size_t np = one_pred_chain.length ();
+  for (size_t j = 0; j < np; j++)
+    {
+      dump_pred_info (one_pred_chain[j]);
+      if (j < np - 1)
+       fprintf (dump_file, " (.AND.) ");
+      else
+       fprintf (dump_file, "\n");
+    }
+}
+
 /* Dumps the predicates (PREDS) for USESTMT.  */
 
 static void
 dump_predicates (gimple *usestmt, pred_chain_union preds, const char *msg)
 {
-  size_t i, j;
-  pred_chain one_pred_chain = vNULL;
   fprintf (dump_file, "%s", msg);
-  print_gimple_stmt (dump_file, usestmt, 0, 0);
-  fprintf (dump_file, "is guarded by :\n\n");
+  if (usestmt)
+    {
+      print_gimple_stmt (dump_file, usestmt, 0);
+      fprintf (dump_file, "is guarded by :\n\n");
+    }
   size_t num_preds = preds.length ();
-  /* Do some dumping here:  */
-  for (i = 0; i < num_preds; i++)
+  for (size_t i = 0; i < num_preds; i++)
     {
-      size_t np;
-
-      one_pred_chain = preds[i];
-      np = one_pred_chain.length ();
-
-      for (j = 0; j < np; j++)
-       {
-         pred_info one_pred = one_pred_chain[j];
-         if (one_pred.invert)
-           fprintf (dump_file, " (.NOT.) ");
-         print_generic_expr (dump_file, one_pred.pred_lhs, 0);
-         fprintf (dump_file, " %s ", op_symbol_code (one_pred.cond_code));
-         print_generic_expr (dump_file, one_pred.pred_rhs, 0);
-         if (j < np - 1)
-           fprintf (dump_file, " (.AND.) ");
-         else
-           fprintf (dump_file, "\n");
-       }
+      dump_pred_chain (preds[i]);
       if (i < num_preds - 1)
        fprintf (dump_file, "(.OR.)\n");
       else
@@ -958,52 +1010,32 @@ get_cmp_code (enum tree_code orig_cmp_code, bool swap_cond, bool invert)
   return tc;
 }
 
-/* Returns true if VAL falls in the range defined by BOUNDARY and CMPC, i.e.
-   all values in the range satisfies (x CMPC BOUNDARY) == true.  */
+/* Returns whether VAL CMPC BOUNDARY is true.  */
 
 static bool
 is_value_included_in (tree val, tree boundary, enum tree_code cmpc)
 {
   bool inverted = false;
-  bool is_unsigned;
   bool result;
 
   /* Only handle integer constant here.  */
   if (TREE_CODE (val) != INTEGER_CST || TREE_CODE (boundary) != INTEGER_CST)
     return true;
 
-  is_unsigned = TYPE_UNSIGNED (TREE_TYPE (val));
-
   if (cmpc == GE_EXPR || cmpc == GT_EXPR || cmpc == NE_EXPR)
     {
       cmpc = invert_tree_comparison (cmpc, false);
       inverted = true;
     }
 
-  if (is_unsigned)
-    {
-      if (cmpc == EQ_EXPR)
-       result = tree_int_cst_equal (val, boundary);
-      else if (cmpc == LT_EXPR)
-       result = tree_int_cst_lt (val, boundary);
-      else
-       {
-         gcc_assert (cmpc == LE_EXPR);
-         result = tree_int_cst_le (val, boundary);
-       }
-    }
+  if (cmpc == EQ_EXPR)
+    result = tree_int_cst_equal (val, boundary);
+  else if (cmpc == LT_EXPR)
+    result = tree_int_cst_lt (val, boundary);
   else
     {
-      if (cmpc == EQ_EXPR)
-       result = tree_int_cst_equal (val, boundary);
-      else if (cmpc == LT_EXPR)
-       result = tree_int_cst_lt (val, boundary);
-      else
-       {
-         gcc_assert (cmpc == LE_EXPR);
-         result = (tree_int_cst_equal (val, boundary)
-                   || tree_int_cst_lt (val, boundary));
-       }
+      gcc_assert (cmpc == LE_EXPR);
+      result = tree_int_cst_le (val, boundary);
     }
 
   if (inverted)
@@ -1012,6 +1044,26 @@ is_value_included_in (tree val, tree boundary, enum tree_code cmpc)
   return result;
 }
 
+/* Returns whether VAL satisfies (x CMPC BOUNDARY) predicate.  CMPC can be
+   either one of the range comparison codes ({GE,LT,EQ,NE}_EXPR and the like),
+   or BIT_AND_EXPR.  EXACT_P is only meaningful for the latter.  It modifies the
+   question from whether VAL & BOUNDARY != 0 to whether VAL & BOUNDARY == VAL.
+   For other values of CMPC, EXACT_P is ignored.  */
+
+static bool
+value_sat_pred_p (tree val, tree boundary, enum tree_code cmpc,
+                 bool exact_p = false)
+{
+  if (cmpc != BIT_AND_EXPR)
+    return is_value_included_in (val, boundary, cmpc);
+
+  wide_int andw = wi::to_wide (val) & wi::to_wide (boundary);
+  if (exact_p)
+    return andw == wi::to_wide (val);
+  else
+    return andw.to_uhwi ();
+}
+
 /* Returns true if PRED is common among all the predicate
    chains (PREDS) (and therefore can be factored out).
    NUM_PRED_CHAIN is the size of array PREDS.  */
@@ -1411,7 +1463,7 @@ pred_expr_equal_p (pred_info x1, tree x2)
 
 /* Returns true of the domain of single predicate expression
    EXPR1 is a subset of that of EXPR2.  Returns false if it
-   can not be proved.  */
+   cannot be proved.  */
 
 static bool
 is_pred_expr_subset_of (pred_info expr1, pred_info expr2)
@@ -1435,21 +1487,24 @@ is_pred_expr_subset_of (pred_info expr1, pred_info expr2)
   if (expr2.invert)
     code2 = invert_tree_comparison (code2, false);
 
-  if ((code1 == EQ_EXPR || code1 == BIT_AND_EXPR) && code2 == BIT_AND_EXPR)
-    return wi::eq_p (expr1.pred_rhs,
-                    wi::bit_and (expr1.pred_rhs, expr2.pred_rhs));
-
-  if (code1 != code2 && code2 != NE_EXPR)
+  if (code2 == NE_EXPR && code1 == NE_EXPR)
     return false;
 
-  if (is_value_included_in (expr1.pred_rhs, expr2.pred_rhs, code2))
-    return true;
+  if (code2 == NE_EXPR)
+    return !value_sat_pred_p (expr2.pred_rhs, expr1.pred_rhs, code1);
+
+  if (code1 == EQ_EXPR)
+    return value_sat_pred_p (expr1.pred_rhs, expr2.pred_rhs, code2);
+
+  if (code1 == code2)
+    return value_sat_pred_p (expr1.pred_rhs, expr2.pred_rhs, code2,
+                            code1 == BIT_AND_EXPR);
 
   return false;
 }
 
 /* Returns true if the domain of PRED1 is a subset
-   of that of PRED2.  Returns false if it can not be proved so.  */
+   of that of PRED2.  Returns false if it cannot be proved so.  */
 
 static bool
 is_pred_chain_subset_of (pred_chain pred1, pred_chain pred2)
@@ -1511,8 +1566,8 @@ is_included_in (pred_chain one_pred, pred_chain_union preds)
    individual predicate chains (won't be a compile time problem
    as the chains are pretty short).  When the function returns
    false, it does not necessarily mean *PREDS1 is not a superset
-   of *PREDS2, but mean it may not be so since the analysis can
-   not prove it.  In such cases, false warnings may still be
+   of *PREDS2, but mean it may not be so since the analysis cannot
+   prove it.  In such cases, false warnings may still be
    emitted.  */
 
 static bool
@@ -1533,16 +1588,6 @@ is_superset_of (pred_chain_union preds1, pred_chain_union preds2)
   return true;
 }
 
-/* Returns true if TC is AND or OR.  */
-
-static inline bool
-is_and_or_or_p (enum tree_code tc, tree type)
-{
-  return (tc == BIT_IOR_EXPR
-         || (tc == BIT_AND_EXPR
-             && (type == 0 || TREE_CODE (type) == BOOLEAN_TYPE)));
-}
-
 /* Returns true if X1 is the negate of X2.  */
 
 static inline bool
@@ -2221,12 +2266,19 @@ normalize_preds (pred_chain_union preds, gimple *use_or_def, bool is_use)
 }
 
 /* Return TRUE if PREDICATE can be invalidated by any individual
-   predicate in WORKLIST.  */
+   predicate in USE_GUARD.  */
 
 static bool
 can_one_predicate_be_invalidated_p (pred_info predicate,
                                    pred_chain use_guard)
 {
+  if (dump_file && dump_flags & TDF_DETAILS)
+    {
+      fprintf (dump_file, "Testing if this predicate: ");
+      dump_pred_info (predicate);
+      fprintf (dump_file, "\n...can be invalidated by a USE guard of: ");
+      dump_pred_chain (use_guard);
+    }
   for (size_t i = 0; i < use_guard.length (); ++i)
     {
       /* NOTE: This is a very simple check, and only understands an
@@ -2235,7 +2287,15 @@ can_one_predicate_be_invalidated_p (pred_info predicate,
         invalidate with say [i > 5] or [i == 8].  There is certainly
         room for improvement here.  */
       if (pred_neg_p (predicate, use_guard[i]))
-       return true;
+       {
+         if (dump_file && dump_flags & TDF_DETAILS)
+           {
+             fprintf (dump_file, "  Predicate was invalidated by: ");
+             dump_pred_info (use_guard[i]);
+             fputc ('\n', dump_file);
+           }
+         return true;
+       }
     }
   return false;
 }
@@ -2249,12 +2309,22 @@ can_chain_union_be_invalidated_p (pred_chain_union uninit_pred,
 {
   if (uninit_pred.is_empty ())
     return false;
+  if (dump_file && dump_flags & TDF_DETAILS)
+    dump_predicates (NULL, uninit_pred,
+                    "Testing if anything here can be invalidated: ");
   for (size_t i = 0; i < uninit_pred.length (); ++i)
     {
       pred_chain c = uninit_pred[i];
-      for (size_t j = 0; j < c.length (); ++j)
-       if (!can_one_predicate_be_invalidated_p (c[j], use_guard))
-         return false;
+      size_t j;
+      for (j = 0; j < c.length (); ++j)
+       if (can_one_predicate_be_invalidated_p (c[j], use_guard))
+         break;
+
+      /* If we were unable to invalidate any predicate in C, then there
+        is a viable path from entry to the PHI where the PHI takes
+        an uninitialized value and continues to a use of the PHI.  */
+      if (j == c.length ())
+       return false;
     }
   return true;
 }
@@ -2296,7 +2366,7 @@ uninit_uses_cannot_happen (gphi *phi, unsigned uninit_opnds,
 
       /* Build the control dependency chain for uninit operand `i'...  */
       uninit_preds = vNULL;
-      if (!compute_control_dep_chain (find_dom (e->src),
+      if (!compute_control_dep_chain (ENTRY_BLOCK_PTR_FOR_FN (cfun),
                                      e->src, dep_chains, &num_chains,
                                      &cur_chain, &num_calls))
        {
@@ -2304,10 +2374,16 @@ uninit_uses_cannot_happen (gphi *phi, unsigned uninit_opnds,
          break;
        }
       /* ...and convert it into a set of predicates.  */
-      convert_control_dep_chain_into_preds (dep_chains, num_chains,
-                                           &uninit_preds);
+      bool has_valid_preds
+       = convert_control_dep_chain_into_preds (dep_chains, num_chains,
+                                               &uninit_preds);
       for (size_t j = 0; j < num_chains; ++j)
        dep_chains[j].release ();
+      if (!has_valid_preds)
+       {
+         ret = false;
+         break;
+       }
       simplify_preds (&uninit_preds, NULL, false);
       uninit_preds = normalize_preds (uninit_preds, NULL, false);
 
@@ -2330,7 +2406,7 @@ uninit_uses_cannot_happen (gphi *phi, unsigned uninit_opnds,
    USE_STMT is guarded with a predicate set not overlapping with
    predicate sets of all runtime paths that do not have a definition.
 
-   Returns false if it is not or it can not be determined.  USE_BB is
+   Returns false if it is not or it cannot be determined.  USE_BB is
    the bb of the use (for phi operand use, the bb is not the bb of
    the phi stmt, but the src bb of the operand edge).
 
@@ -2459,7 +2535,7 @@ find_uninit_use (gphi *phi, unsigned uninit_opnds,
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
          fprintf (dump_file, "[CHECK]: Found unguarded use: ");
-         print_gimple_stmt (dump_file, use_stmt, 0, 0);
+         print_gimple_stmt (dump_file, use_stmt, 0);
        }
       /* Found one real use, return.  */
       if (gimple_code (use_stmt) != GIMPLE_PHI)
@@ -2475,7 +2551,7 @@ find_uninit_use (gphi *phi, unsigned uninit_opnds,
          if (dump_file && (dump_flags & TDF_DETAILS))
            {
              fprintf (dump_file, "[WORKLIST]: Update worklist with phi: ");
-             print_gimple_stmt (dump_file, use_stmt, 0, 0);
+             print_gimple_stmt (dump_file, use_stmt, 0);
            }
 
          worklist->safe_push (as_a<gphi *> (use_stmt));
@@ -2517,7 +2593,7 @@ warn_uninitialized_phi (gphi *phi, vec<gphi *> *worklist,
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "[CHECK]: examining phi: ");
-      print_gimple_stmt (dump_file, phi, 0, 0);
+      print_gimple_stmt (dump_file, phi, 0);
     }
 
   /* Now check if we have any use of the value without proper guard.  */
@@ -2619,7 +2695,7 @@ pass_late_warn_uninitialized::execute (function *fun)
                if (dump_file && (dump_flags & TDF_DETAILS))
                  {
                    fprintf (dump_file, "[WORKLIST]: add to initial list: ");
-                   print_gimple_stmt (dump_file, phi, 0, 0);
+                   print_gimple_stmt (dump_file, phi, 0);
                  }
                break;
              }
@@ -2661,7 +2737,7 @@ execute_early_warn_uninitialized (void)
 
   warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize);
 
-  /* Post-dominator information can not be reliably updated.  Free it
+  /* Post-dominator information cannot be reliably updated.  Free it
      after the use.  */
 
   free_dominance_info (CDI_POST_DOMINATORS);