parent
d527c90aa5
commit
2edb37a65e
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue