summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authordavidxl <davidxl@138bc75d-0d04-0410-961f-82ee72b054a4>2010-10-15 23:16:59 +0000
committerdavidxl <davidxl@138bc75d-0d04-0410-961f-82ee72b054a4>2010-10-15 23:16:59 +0000
commit4028020e9f517e272f3f9889d35f74cac6bbbb29 (patch)
tree410cb95a75eba97ac187d4846c518ab3ab669b4e /gcc
parentb7e7fbc12445264857d83f3fa321c2a4d7e9cb79 (diff)
downloadgcc-4028020e9f517e272f3f9889d35f74cac6bbbb29.tar.gz
uninit var analysis enhancement
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@165530 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/uninit-pred-3_a.C77
-rw-r--r--gcc/testsuite/g++.dg/uninit-pred-3_b.C87
-rw-r--r--gcc/tree-ssa-uninit.c187
5 files changed, 321 insertions, 42 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0d3d9b26ef3..d7ffbbb412f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 43f2aa0b45d..bc57cde8938 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/g++.dg/uninit-pred-3_a.C b/gcc/testsuite/g++.dg/uninit-pred-3_a.C
new file mode 100644
index 00000000000..91014079004
--- /dev/null
+++ b/gcc/testsuite/g++.dg/uninit-pred-3_a.C
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/uninit-pred-3_b.C b/gcc/testsuite/g++.dg/uninit-pred-3_b.C
new file mode 100644
index 00000000000..cfe2113bb6e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/uninit-pred-3_b.C
@@ -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);
+}
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index 78b88e9bd93..01ff43165d3 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -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;
-
- if (!MASK_TEST_BIT (uninit_opnds, i))
- continue;
-
- 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. */
+ all_pruned = prune_uninit_phi_opnds_in_unrealizable_paths (phi,
+ uninit_opnds,
+ flag_def,
+ boundary_cst,
+ cmp_code,
+ visited_phis,
+ &visited_flag_phis);
- 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;
- }
- }
+ if (visited_flag_phis)
+ BITMAP_FREE (visited_flag_phis);
- return true;
+ return all_pruned;
}
/* Returns true if TC is AND or OR */