re PR middle-end/61409 (-Wmaybe-uninitialized false-positive with -O2)

PR middle-end/61409
	* tree-ssa-uninit.c: Define new global max_phi_args.
	(compute_uninit_opnds_pos): Use max_phi_args.
	(prune_uninit_phi_opnds): Same.
	(use_pred_not_overlap_with_undef_path_pred): Remove reference to
	missing NUM_PREDS in function comment.
	(can_one_predicate_be_invalidated_p): New.
	(can_chain_union_be_invalidated_p): New.
	(flatten_out_predicate_chains): New.
	(uninit_ops_invalidate_phi_use): New.
	(is_use_properly_guarded): Call uninit_ops_invalidate_phi_use.

From-SVN: r242639
This commit is contained in:
Aldy Hernandez 2016-11-20 18:34:06 +00:00 committed by Aldy Hernandez
parent 40fd269ab1
commit 358a95e462
3 changed files with 207 additions and 7 deletions

View File

@ -1,3 +1,17 @@
2016-08-25 Aldy Hernandez <aldyh@redhat.com>
PR middle-end/61409
* tree-ssa-uninit.c: Define new global max_phi_args.
(compute_uninit_opnds_pos): Use max_phi_args.
(prune_uninit_phi_opnds): Same.
(use_pred_not_overlap_with_undef_path_pred): Remove reference to
missing NUM_PREDS in function comment.
(can_one_predicate_be_invalidated_p): New.
(can_chain_union_be_invalidated_p): New.
(flatten_out_predicate_chains): New.
(uninit_ops_invalidate_phi_use): New.
(is_use_properly_guarded): Call uninit_ops_invalidate_phi_use.
2016-11-20 Marc Glisse <marc.glisse@inria.fr>
* fold-const.c (fold_comparison): Ignore EXACT_DIV_EXPR.

View File

@ -0,0 +1,25 @@
/* { dg-do compile } */
/* { dg-options "-O2 -Wuninitialized" } */
int *rw;
int line_height;
int pixel_width;
int text_cols;
int width1, width2, width3;
void *pointer;
void f (int i, int j)
{
void *ptr;
if (i)
{
if (j)
return;
ptr = pointer;
}
pixel_width = 1234 + width1 + 2 * width2 + 2 * width3;
*rw = text_cols + line_height;
if (i)
rw=ptr; /* { dg-bogus "uninitialized" "bogus warning" } */
}

View File

@ -44,6 +44,9 @@ along with GCC; see the file COPYING3. If not see
default definitions or by checking if the predicate set that guards the
defining paths is a superset of the use predicate. */
/* Max PHI args we can handle in pass. */
const unsigned max_phi_args = 32;
/* Pointer set of potentially undefined ssa names, i.e.,
ssa names that are defined by phi with operands that
are not defined or potentially undefined. */
@ -314,7 +317,7 @@ compute_uninit_opnds_pos (gphi *phi)
n = gimple_phi_num_args (phi);
/* Bail out for phi with too many args. */
if (n > 32)
if (n > max_phi_args)
return 0;
for (i = 0; i < n; ++i)
@ -1031,7 +1034,7 @@ prune_uninit_phi_opnds (gphi *phi, unsigned uninit_opnds, gphi *flag_def,
{
unsigned i;
for (i = 0; i < MIN (32, gimple_phi_num_args (flag_def)); i++)
for (i = 0; i < MIN (max_phi_args, gimple_phi_num_args (flag_def)); i++)
{
tree flag_arg;
@ -1192,11 +1195,10 @@ prune_uninit_phi_opnds (gphi *phi, unsigned uninit_opnds, gphi *flag_def,
transformation which eliminates the merge point thus makes
path sensitive analysis unnecessary.)
NUM_PREDS is the number is the number predicate chains, PREDS is
the array of chains, PHI is the phi node whose incoming (undefined)
paths need to be pruned, and UNINIT_OPNDS is the bitmap holding
uninit operand positions. VISITED_PHIS is the pointer set of phi
stmts being checked. */
PHI is the phi node whose incoming (undefined) paths need to be
pruned, and UNINIT_OPNDS is the bitmap holding uninit operand
positions. VISITED_PHIS is the pointer set of phi stmts being
checked. */
static bool
use_pred_not_overlap_with_undef_path_pred (pred_chain_union preds,
@ -2148,6 +2150,158 @@ normalize_preds (pred_chain_union preds, gimple *use_or_def, bool is_use)
return norm_preds;
}
/* Return TRUE if PREDICATE can be invalidated by any individual
predicate in WORKLIST. */
static bool
can_one_predicate_be_invalidated_p (pred_info predicate,
vec<pred_info *> worklist)
{
for (size_t i = 0; i < worklist.length (); ++i)
{
pred_info *p = worklist[i];
/* NOTE: This is a very simple check, and only understands an
exact opposite. So, [i == 0] is currently only invalidated
by [.NOT. i == 0] or [i != 0]. Ideally we should also
invalidate with say [i > 5] or [i == 8]. There is certainly
room for improvement here. */
if (pred_neg_p (predicate, *p))
return true;
}
return false;
}
/* Return TRUE if all USE_PREDS can be invalidated by some predicate
in WORKLIST. */
static bool
can_chain_union_be_invalidated_p (pred_chain_union use_preds,
vec<pred_info *> worklist)
{
/* Remember:
PRED_CHAIN_UNION = PRED_CHAIN1 || PRED_CHAIN2 || PRED_CHAIN3
PRED_CHAIN = PRED_INFO1 && PRED_INFO2 && PRED_INFO3, etc.
We need to invalidate the entire PRED_CHAIN_UNION, which means,
invalidating every PRED_CHAIN in this union. But to invalidate
an individual PRED_CHAIN, all we need to invalidate is _any_ one
PRED_INFO, by boolean algebra !PRED_INFO1 || !PRED_INFO2... */
for (size_t i = 0; i < use_preds.length (); ++i)
{
pred_chain c = use_preds[i];
bool entire_pred_chain_invalidated = false;
for (size_t j = 0; j < c.length (); ++j)
if (can_one_predicate_be_invalidated_p (c[i], worklist))
{
entire_pred_chain_invalidated = true;
break;
}
if (!entire_pred_chain_invalidated)
return false;
}
return true;
}
/* Flatten out all the factors in all the pred_chain_union's in PREDS
into a WORKLIST of individual PRED_INFO's.
N is the number of pred_chain_union's in PREDS.
Since we are interested in the inverse of the PRED_CHAIN's, by
boolean algebra, an inverse turns those PRED_CHAINS into unions,
which means we can flatten all the factors out for easy access. */
static void
flatten_out_predicate_chains (pred_chain_union preds[], size_t n,
vec<pred_info *> *worklist)
{
for (size_t i = 0; i < n; ++i)
{
pred_chain_union u = preds[i];
for (size_t j = 0; j < u.length (); ++j)
{
pred_chain c = u[j];
for (size_t k = 0; k < c.length (); ++k)
worklist->safe_push (&c[k]);
}
}
}
/* Return TRUE if executing the path to some uninitialized operands in
a PHI will invalidate the use of the PHI result later on.
UNINIT_OPNDS is a bit vector specifying which PHI arguments have
arguments which are considered uninitialized.
USE_PREDS is the pred_chain_union specifying the guard conditions
for the use of the PHI result.
What we want to do is disprove each of the guards in the factors of
the USE_PREDS. So if we have:
# USE_PREDS guards of:
# 1. i > 5 && i < 100
# 2. j > 10 && j < 88
Then proving that the control dependenies for the UNINIT_OPNDS are:
# [i <= 5]
# .OR. [i >= 100]
#
...we can prove that the 1st guard above in USE_PREDS is invalid.
Similarly for the 2nd guard. We return TRUE if we can disprove
both of the guards in USE_PREDS above. */
static bool
uninit_ops_invalidate_phi_use (gphi *phi, unsigned uninit_opnds,
pred_chain_union use_preds)
{
/* Look for the control dependencies of all the uninitialized
operands and build predicates describing them. */
unsigned i;
pred_chain_union uninit_preds[max_phi_args];
memset (uninit_preds, 0, sizeof (pred_chain_union) * max_phi_args);
for (i = 0; i < MIN (max_phi_args, gimple_phi_num_args (phi)); i++)
{
if (!MASK_TEST_BIT (uninit_opnds, i))
continue;
edge e = gimple_phi_arg_edge (phi, i);
vec<edge> dep_chains[MAX_NUM_CHAINS];
auto_vec<edge, MAX_CHAIN_LEN + 1> cur_chain;
size_t num_chains = 0;
int num_calls = 0;
/* Build the control dependency chain for `i'... */
if (compute_control_dep_chain (find_dom (e->src),
e->src,
dep_chains,
&num_chains,
&cur_chain,
&num_calls))
{
/* ...and convert it into a set of predicates. */
convert_control_dep_chain_into_preds (dep_chains, num_chains,
&uninit_preds[i]);
for (size_t j = 0; j < num_chains; ++j)
dep_chains[j].release ();
simplify_preds (&uninit_preds[i], NULL, false);
uninit_preds[i]
= normalize_preds (uninit_preds[i], NULL, false);
}
}
/* Munge all the predicates into one worklist, and see if we can
invalidate all the chains in USE_PREDs with the predicates in
WORKLIST. */
auto_vec<pred_info *> worklist;
flatten_out_predicate_chains (uninit_preds, i, &worklist);
bool ret = can_chain_union_be_invalidated_p (use_preds, worklist);
return ret;
}
/* Computes the predicates that guard the use and checks
if the incoming paths that have empty (or possibly
empty) definition can be pruned/filtered. The function returns
@ -2203,6 +2357,13 @@ is_use_properly_guarded (gimple *use_stmt,
= use_pred_not_overlap_with_undef_path_pred (preds, phi, uninit_opnds,
visited_phis);
/* We might be able to prove that if the control dependencies
for UNINIT_OPNDS are true, that the control dependencies for
USE_STMT can never be true. */
if (!is_properly_guarded)
is_properly_guarded |= uninit_ops_invalidate_phi_use (phi, uninit_opnds,
preds);
if (is_properly_guarded)
{
destroy_predicate_vecs (&preds);