uninit var analysis enhancement

From-SVN: r165530
This commit is contained in:
Xinliang David Li 2010-10-15 23:16:59 +00:00 committed by Xinliang David Li
parent d527c90aa5
commit 2edb37a65e
5 changed files with 321 additions and 42 deletions

View File

@ -1,3 +1,10 @@
2010-10-15 Xinliang David Li <davidxl@google.com>
* tree-ssa-uninit.c (prune_uninit_phi_opnds_in_unrealizable_paths): New
function.
(use_pred_not_overlap_with_undef_path_pred): Outline phi arg pruning
into a recursive function.
2010-10-15 Uros Bizjak <ubizjak@gmail.com>
* config/i386/i386.md (*movdfcc_1_rex64): Correct mode attribute.

View File

@ -1,3 +1,8 @@
2010-10-15 Xinliang David Li <davidxl@google.com>
* g++.dg/uninit-pred-3_a.C: New test.
* g++.dg/uninit-pred-3_b.C: New test.
2010-10-15 Nicola Pero <nicola.pero@meta-innovation.com>
* objc.dg/gnu-api-2-object.m: New.

View File

@ -0,0 +1,77 @@
/* { dg-do compile } */
/* { dg-options "-Wuninitialized -O2" } */
/* Multiple initialization paths. */
typedef long long int64;
void incr ();
bool is_valid (int);
int get_time ();
class A
{
public:
A ();
~A () {
if (I) delete I;
}
private:
int* I;
};
bool get_url (A *);
bool get_url2 (A *);
class M {
public:
__attribute__ ((always_inline))
bool GetC (int *c) {
A details_str;
/* Intialization path 1 */
if (get_url (&details_str))
{
*c = get_time ();
return true;
}
/* insert dtor calls (inlined) into following return paths */
A tmp_str;
/* Intializtion path 2 */
if (get_url2 (&details_str))
{
*c = get_time ();
return true;
}
return false;
}
void do_sth();
void do_sth2();
void P (int64 t)
{
int cc;
if (!GetC (&cc)) /* return flag checked properly */
return;
if (cc <= 0) /* { dg-bogus "uninitialized" "uninitialized variable warning" } */
{
this->do_sth();
return;
}
do_sth2();
}
};
M* m;
void test(int x)
{
m = new M;
m->P(x);
}

View File

@ -0,0 +1,87 @@
/* { dg-do compile } */
/* { dg-options "-Wuninitialized -O2" } */
/* Multiple initialization paths. */
typedef long long int64;
void incr ();
bool is_valid (int);
int get_time ();
class A
{
public:
A ();
~A () {
if (I) delete I;
}
private:
int* I;
};
bool get_url (A *);
bool get_url2 (A *);
bool get_url3 (A *);
class M {
public:
__attribute__ ((always_inline))
bool GetC (int *c) {
A details_str;
/* Initialization path 1 */
if (get_url (&details_str))
{
*c = get_time ();
return true;
}
/* Destructor call before return*/
A tmp_str;
/* Initialization path 2 */
if (get_url2 (&details_str))
{
*c = get_time ();
return true;
}
/* Fail to initialize in this path but
still returns true */
if (get_url2 (&details_str))
{
/* Fail to initialize *c */
return true;
}
return false;
}
void do_sth();
void do_sth2();
void P (int64 t)
{
int cc; /* { dg-excess-errors "note: 'cc' was declared here" } */
if (!GetC (&cc))
return;
if (cc <= 0) /* { dg-warning "uninitialized" "uninitialized variable warning" } */
{
this->do_sth();
return;
}
do_sth2();
}
};
M* m;
void test(int x)
{
m = new M;
m->P(x);
}

View File

@ -785,6 +785,139 @@ is_use_properly_guarded (gimple use_stmt,
unsigned uninit_opnds,
struct pointer_set_t *visited_phis);
/* Returns true if all uninitialized opnds are pruned. Returns false
otherwise. PHI is the phi node with uninitialized operands,
UNINIT_OPNDS is the bitmap of the uninitialize operand positions,
FLAG_DEF is the statement defining the flag guarding the use of the
PHI output, BOUNDARY_CST is the const value used in the predicate
associated with the flag, CMP_CODE is the comparison code used in
the predicate, VISITED_PHIS is the pointer set of phis visited, and
VISITED_FLAG_PHIS is the pointer to the pointer set of flag definitions
that are also phis.
Example scenario:
BB1:
flag_1 = phi <0, 1> // (1)
var_1 = phi <undef, some_val>
BB2:
flag_2 = phi <0, flag_1, flag_1> // (2)
var_2 = phi <undef, var_1, var_1>
if (flag_2 == 1)
goto BB3;
BB3:
use of var_2 // (3)
Because some flag arg in (1) is not constant, if we do not look into the
flag phis recursively, it is conservatively treated as unknown and var_1
is thought to be flowed into use at (3). Since var_1 is potentially uninitialized
a false warning will be emitted. Checking recursively into (1), the compiler can
find out that only some_val (which is defined) can flow into (3) which is OK.
*/
static bool
prune_uninit_phi_opnds_in_unrealizable_paths (
gimple phi, unsigned uninit_opnds,
gimple flag_def, tree boundary_cst,
enum tree_code cmp_code,
struct pointer_set_t *visited_phis,
bitmap *visited_flag_phis)
{
unsigned i;
for (i = 0; i < MIN (32, gimple_phi_num_args (flag_def)); i++)
{
tree flag_arg;
if (!MASK_TEST_BIT (uninit_opnds, i))
continue;
flag_arg = gimple_phi_arg_def (flag_def, i);
if (!is_gimple_constant (flag_arg))
{
gimple flag_arg_def, phi_arg_def;
tree phi_arg;
unsigned uninit_opnds_arg_phi;
if (TREE_CODE (flag_arg) != SSA_NAME)
return false;
flag_arg_def = SSA_NAME_DEF_STMT (flag_arg);
if (gimple_code (flag_arg_def) != GIMPLE_PHI)
return false;
phi_arg = gimple_phi_arg_def (phi, i);
if (TREE_CODE (phi_arg) != SSA_NAME)
return false;
phi_arg_def = SSA_NAME_DEF_STMT (phi_arg);
if (gimple_code (phi_arg_def) != GIMPLE_PHI)
return false;
if (gimple_bb (phi_arg_def) != gimple_bb (flag_arg_def))
return false;
if (!*visited_flag_phis)
*visited_flag_phis = BITMAP_ALLOC (NULL);
if (bitmap_bit_p (*visited_flag_phis,
SSA_NAME_VERSION (gimple_phi_result (flag_arg_def))))
return false;
bitmap_set_bit (*visited_flag_phis,
SSA_NAME_VERSION (gimple_phi_result (flag_arg_def)));
/* Now recursively prune the uninitialized phi args. */
uninit_opnds_arg_phi = compute_uninit_opnds_pos (phi_arg_def);
if (!prune_uninit_phi_opnds_in_unrealizable_paths (
phi_arg_def, uninit_opnds_arg_phi,
flag_arg_def, boundary_cst, cmp_code,
visited_phis, visited_flag_phis))
return false;
bitmap_clear_bit (*visited_flag_phis,
SSA_NAME_VERSION (gimple_phi_result (flag_arg_def)));
continue;
}
/* Now check if the constant is in the guarded range. */
if (is_value_included_in (flag_arg, boundary_cst, cmp_code))
{
tree opnd;
gimple opnd_def;
/* Now that we know that this undefined edge is not
pruned. If the operand is defined by another phi,
we can further prune the incoming edges of that
phi by checking the predicates of this operands. */
opnd = gimple_phi_arg_def (phi, i);
opnd_def = SSA_NAME_DEF_STMT (opnd);
if (gimple_code (opnd_def) == GIMPLE_PHI)
{
edge opnd_edge;
unsigned uninit_opnds2
= compute_uninit_opnds_pos (opnd_def);
gcc_assert (!MASK_EMPTY (uninit_opnds2));
opnd_edge = gimple_phi_arg_edge (phi, i);
if (!is_use_properly_guarded (phi,
opnd_edge->src,
opnd_def,
uninit_opnds2,
visited_phis))
return false;
}
else
return false;
}
}
return true;
}
/* A helper function that determines if the predicate set
of the use is not overlapping with that of the uninit paths.
The most common senario of guarded use is in Example 1:
@ -873,6 +1006,8 @@ use_pred_not_overlap_with_undef_path_pred (
bool swap_cond = false;
bool invert = false;
VEC(use_pred_info_t, heap) *the_pred_chain;
bitmap visited_flag_phis = NULL;
bool all_pruned = false;
gcc_assert (num_preds > 0);
/* Find within the common prefix of multiple predicate chains
@ -935,50 +1070,18 @@ use_pred_not_overlap_with_undef_path_pred (
if (cmp_code == ERROR_MARK)
return false;
for (i = 0; i < sizeof (unsigned); i++)
{
tree flag_arg;
all_pruned = prune_uninit_phi_opnds_in_unrealizable_paths (phi,
uninit_opnds,
flag_def,
boundary_cst,
cmp_code,
visited_phis,
&visited_flag_phis);
if (!MASK_TEST_BIT (uninit_opnds, i))
continue;
if (visited_flag_phis)
BITMAP_FREE (visited_flag_phis);
flag_arg = gimple_phi_arg_def (flag_def, i);
if (!is_gimple_constant (flag_arg))
return false;
/* Now check if the constant is in the guarded range. */
if (is_value_included_in (flag_arg, boundary_cst, cmp_code))
{
tree opnd;
gimple opnd_def;
/* Now that we know that this undefined edge is not
pruned. If the operand is defined by another phi,
we can further prune the incoming edges of that
phi by checking the predicates of this operands. */
opnd = gimple_phi_arg_def (phi, i);
opnd_def = SSA_NAME_DEF_STMT (opnd);
if (gimple_code (opnd_def) == GIMPLE_PHI)
{
edge opnd_edge;
unsigned uninit_opnds2
= compute_uninit_opnds_pos (opnd_def);
gcc_assert (!MASK_EMPTY (uninit_opnds2));
opnd_edge = gimple_phi_arg_edge (phi, i);
if (!is_use_properly_guarded (phi,
opnd_edge->src,
opnd_def,
uninit_opnds2,
visited_phis))
return false;
}
else
return false;
}
}
return true;
return all_pruned;
}
/* Returns true if TC is AND or OR */