/* Predicate aware uninitialized variable warning.
- Copyright (C) 2001-2018 Free Software Foundation, Inc.
+ Copyright (C) 2001-2019 Free Software Foundation, Inc.
Contributed by Xinliang David Li <davidxl@google.com>
This file is part of GCC.
#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
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;
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))
return false;
++*num_calls;
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;
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;
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);
- 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);
- fprintf (dump_file, " %s ", op_symbol_code (one_pred.cond_code));
- print_generic_expr (dump_file, one_pred.pred_rhs);
- 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
/* 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)
}
/* 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)
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
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
}
/* 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
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;
}
{
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;
}
/* 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))
{
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);
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).
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);