OSDN Git Service

uninit var analysis enhancement
authordavidxl <davidxl@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 15 Oct 2010 23:16:59 +0000 (23:16 +0000)
committerdavidxl <davidxl@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 15 Oct 2010 23:16:59 +0000 (23:16 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@165530 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/uninit-pred-3_a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/uninit-pred-3_b.C [new file with mode: 0644]
gcc/tree-ssa-uninit.c

index 0d3d9b2..d7ffbbb 100644 (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.
index 43f2aa0..bc57cde 100644 (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.
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 (file)
index 0000000..9101407
--- /dev/null
@@ -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 (file)
index 0000000..cfe2113
--- /dev/null
@@ -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);
+}
index 78b88e9..01ff431 100644 (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;
-
-      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 */