re PR libstdc++/29286 (placement new does not change the dynamic type as it should)
authorIan Lance Taylor <iant@google.com>
Tue, 12 Jun 2007 17:47:37 +0000 (17:47 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 12 Jun 2007 17:47:37 +0000 (17:47 +0000)
./: PR libstdc++/29286
* tree.def: Add CHANGE_DYNAMIC_TYPE_EXPR.
* tree.h (CHANGE_DYNAMIC_TYPE_NEW_TYPE): Define.
(CHANGE_DYNAMIC_TYPE_LOCATION): Define.
(DECL_NO_TBAA_P): Define.
(struct tree_decl_common): Add no_tbaa_flag field.
* tree-ssa-structalias.c (struct variable_info): Add
no_tbaa_pruning field.
(new_var_info): Initialize no_tbaa_pruning field.
(unify_nodes): Copy no_tbaa_pruning field.
(find_func_aliases): Handle CHANGE_DYNAMIC_TYPE_EXPR.
(dump_solution_for_var): Print no_tbaa_pruning flag.
(set_uids_in_ptset): Add no_tbaa_pruning parameter.  Change all
callers.
(compute_tbaa_pruning): New static function.
(compute_points_to_sets): Remove CHANGE_DYNAMIC_TYPE_EXPR nodes.
Call compute_tbaa_pruning.
* tree-ssa-alias.c (may_alias_p): Test no_tbaa_flag for pointers.
* gimplify.c (gimplify_expr): Handle CHANGE_DYNAMIC_TYPE_EXPR.
* gimple-low.c (lower_stmt): Likewise.
* tree-gimple.c (is_gimple_stmt): Likewise.
* tree-ssa-operands.c (get_expr_operands): Likewise.
* tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Likewise.
* tree-inline.c (estimate_num_insns_1): Likewise.
(copy_result_decl_to_var): Likewise.
* expr.c (expand_expr_real_1): Likewise.
* tree-pretty-print.c (dump_generic_node): Likewise.
* tree-inline.c (copy_decl_to_var): Copy DECL_NO_TBAA_P flag.
* omp-low.c (omp_copy_decl_2): Likewise.
* print-tree.c (print_node): Print DECL_NO_TBAA_P flag.
* doc/c-tree.texi (Expression trees): Document
CHANGE_DYNAMIC_TYPE_EXPR.
cp/:
PR libstdc++/29286
* init.c (avoid_placement_new_aliasing): New static function.
(build_new_1): Call it.
testsuite/:
PR libstdc++/29286
* g++.dg/init/new16.C: New test.
* g++.dg/init/new17.C: New test.
* g++.dg/init/new18.C: New test.
* g++.dg/init/new19.C: New test.

Co-Authored-By: Daniel Berlin <dberlin@dberlin.org>
From-SVN: r125653

23 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/init.c
gcc/doc/c-tree.texi
gcc/expr.c
gcc/gimple-low.c
gcc/gimplify.c
gcc/omp-low.c
gcc/print-tree.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/init/new16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/new17.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/new18.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/new19.C [new file with mode: 0644]
gcc/tree-gimple.c
gcc/tree-inline.c
gcc/tree-pretty-print.c
gcc/tree-ssa-alias.c
gcc/tree-ssa-dce.c
gcc/tree-ssa-operands.c
gcc/tree-ssa-structalias.c
gcc/tree.def
gcc/tree.h

index 616bc5097e97e3bb504e606fd0633e874a50f9c8..d531d976f361a5dbac4f957e62a68135354b384f 100644 (file)
@@ -1,3 +1,39 @@
+2007-06-12  Ian Lance Taylor  <iant@google.com>
+           Daniel Berlin  <dberlin@dberlin.org>
+
+       PR libstdc++/29286
+       * tree.def: Add CHANGE_DYNAMIC_TYPE_EXPR.
+       * tree.h (CHANGE_DYNAMIC_TYPE_NEW_TYPE): Define.
+       (CHANGE_DYNAMIC_TYPE_LOCATION): Define.
+       (DECL_NO_TBAA_P): Define.
+       (struct tree_decl_common): Add no_tbaa_flag field.
+       * tree-ssa-structalias.c (struct variable_info): Add
+       no_tbaa_pruning field.
+       (new_var_info): Initialize no_tbaa_pruning field.
+       (unify_nodes): Copy no_tbaa_pruning field.
+       (find_func_aliases): Handle CHANGE_DYNAMIC_TYPE_EXPR.
+       (dump_solution_for_var): Print no_tbaa_pruning flag.
+       (set_uids_in_ptset): Add no_tbaa_pruning parameter.  Change all
+       callers.
+       (compute_tbaa_pruning): New static function.
+       (compute_points_to_sets): Remove CHANGE_DYNAMIC_TYPE_EXPR nodes.
+       Call compute_tbaa_pruning.
+       * tree-ssa-alias.c (may_alias_p): Test no_tbaa_flag for pointers.
+       * gimplify.c (gimplify_expr): Handle CHANGE_DYNAMIC_TYPE_EXPR.
+       * gimple-low.c (lower_stmt): Likewise.
+       * tree-gimple.c (is_gimple_stmt): Likewise.
+       * tree-ssa-operands.c (get_expr_operands): Likewise.
+       * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Likewise.
+       * tree-inline.c (estimate_num_insns_1): Likewise.
+       (copy_result_decl_to_var): Likewise.
+       * expr.c (expand_expr_real_1): Likewise.
+       * tree-pretty-print.c (dump_generic_node): Likewise.
+       * tree-inline.c (copy_decl_to_var): Copy DECL_NO_TBAA_P flag.
+       * omp-low.c (omp_copy_decl_2): Likewise.
+       * print-tree.c (print_node): Print DECL_NO_TBAA_P flag.
+       * doc/c-tree.texi (Expression trees): Document
+       CHANGE_DYNAMIC_TYPE_EXPR.
+
 2007-06-12  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * fold-const.c (fold_binary): Guard (X-X) -> 0 transformation
index 3f010ae77234799fb0790a5cb29210836cb984e7..f9ca0508ddc3404d816f9645a72169cc98ef7af7 100644 (file)
@@ -1,3 +1,9 @@
+2007-06-12  Ian Lance Taylor  <iant@google.com>
+
+       PR libstdc++/29286
+       * init.c (avoid_placement_new_aliasing): New static function.
+       (build_new_1): Call it.
+
 2007-06-11  Rafael Avila de Espindola  <espindola@google.com>
 
        * cp-objcp-common.h (LANG_HOOKS_SIGNED_TYPE): Remove.
index 3023cf09d4bdd190c786f33893405b23ff2888dc..aecbed967954c91808fbda9785bbad9f43c4977f 100644 (file)
@@ -1,6 +1,7 @@
 /* Handle initialization things in C++.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GCC.
@@ -1564,6 +1565,55 @@ build_raw_new_expr (tree placement, tree type, tree nelts, tree init,
   return new_expr;
 }
 
+/* Make sure that there are no aliasing issues with T, a placement new
+   expression applied to PLACEMENT, by recording the change in dynamic
+   type.  If placement new is inlined, as it is with libstdc++, and if
+   the type of the placement new differs from the type of the
+   placement location itself, then alias analysis may think it is OK
+   to interchange writes to the location from before the placement new
+   and from after the placement new.  We have to prevent type-based
+   alias analysis from applying.  PLACEMENT may be NULL, which means
+   that we couldn't capture it in a temporary variable, in which case
+   we use a memory clobber.  */
+
+static tree
+avoid_placement_new_aliasing (tree t, tree placement)
+{
+  tree type_change;
+
+  if (processing_template_decl)
+    return t;
+
+  /* If we are not using type based aliasing, we don't have to do
+     anything.  */
+  if (!flag_strict_aliasing)
+    return t;
+
+  /* If we have a pointer and a location, record the change in dynamic
+     type.  Otherwise we need a general memory clobber.  */
+  if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+      && placement != NULL_TREE
+      && TREE_CODE (TREE_TYPE (placement)) == POINTER_TYPE)
+    type_change = build_stmt (CHANGE_DYNAMIC_TYPE_EXPR,
+                             TREE_TYPE (t),
+                             placement);
+  else
+    {
+      /* Build a memory clobber.  */
+      type_change = build_stmt (ASM_EXPR,
+                               build_string (0, ""),
+                               NULL_TREE,
+                               NULL_TREE,
+                               tree_cons (NULL_TREE,
+                                          build_string (6, "memory"),
+                                          NULL_TREE));
+
+      ASM_VOLATILE_P (type_change) = 1;
+    }
+
+  return build2 (COMPOUND_EXPR, TREE_TYPE (t), type_change, t);
+}
+
 /* Generate code for a new-expression, including calling the "operator
    new" function, initializing the object, and, if an exception occurs
    during construction, cleaning up.  The arguments are as for
@@ -1607,6 +1657,7 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
      beginning of the storage allocated for an array-new expression in
      order to store the number of elements.  */
   tree cookie_size = NULL_TREE;
+  tree placement_var;
   /* True if the function we are calling is a placement allocation
      function.  */
   bool placement_allocation_fn_p;
@@ -1700,6 +1751,20 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
 
   alloc_fn = NULL_TREE;
 
+  /* If PLACEMENT is a simple pointer type, then copy it into
+     PLACEMENT_VAR.  */
+  if (processing_template_decl
+      || placement == NULL_TREE
+      || TREE_CHAIN (placement) != NULL_TREE
+      || TREE_CODE (TREE_TYPE (TREE_VALUE (placement))) != POINTER_TYPE)
+    placement_var = NULL_TREE;
+  else
+    {
+      placement_var = get_temp_regvar (TREE_TYPE (TREE_VALUE (placement)),
+                                      TREE_VALUE (placement));
+      placement = tree_cons (NULL_TREE, placement_var, NULL_TREE);
+    }
+
   /* Allocate the object.  */
   if (! placement && TYPE_FOR_JAVA (elt_type))
     {
@@ -1792,7 +1857,12 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
   /* In the simple case, we can stop now.  */
   pointer_type = build_pointer_type (type);
   if (!cookie_size && !is_initialized)
-    return build_nop (pointer_type, alloc_call);
+    {
+      rval = build_nop (pointer_type, alloc_call);
+      if (placement != NULL)
+       rval = avoid_placement_new_aliasing (rval, placement_var);
+      return rval;
+    }
 
   /* While we're working, use a pointer to the type we've actually
      allocated. Store the result of the call in a variable so that we
@@ -2052,6 +2122,9 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
   /* A new-expression is never an lvalue.  */
   gcc_assert (!lvalue_p (rval));
 
+  if (placement != NULL)
+    rval = avoid_placement_new_aliasing (rval, placement_var);
+
   return rval;
 }
 
index bd4c62308ee5f0e86108a0a1a45262c4122febd7..c61b871a6792482185b8f032d00ee16aa2a6039b 100644 (file)
@@ -1965,6 +1965,7 @@ This macro returns the attributes on the type @var{type}.
 @tindex TARGET_EXPR
 @tindex AGGR_INIT_EXPR
 @tindex VA_ARG_EXPR
+@tindex CHANGE_DYNAMIC_TYPE_EXPR
 @tindex OMP_PARALLEL
 @tindex OMP_FOR
 @tindex OMP_SECTIONS
@@ -2655,6 +2656,13 @@ mechanism.  It represents expressions like @code{va_arg (ap, type)}.
 Its @code{TREE_TYPE} yields the tree representation for @code{type} and
 its sole argument yields the representation for @code{ap}.
 
+@item CHANGE_DYNAMIC_TYPE_EXPR
+Indicates the special aliasing required by C++ placement new.  It has
+two operands: a type and a location.  It means that the dynamic type
+of the location is changing to be the specified type.  The alias
+analysis code takes this into account when doing type based alias
+analysis.
+
 @item OMP_PARALLEL
 
 Represents @code{#pragma omp parallel [clause1 ... clauseN]}. It
index 19b404f00f98a45d19ba03e843817e60786e6e5a..2a4629a71e03f7431efd71a4147511688f90317a 100644 (file)
@@ -8947,6 +8947,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* Lowered by gimplify.c.  */
       gcc_unreachable ();
 
+    case CHANGE_DYNAMIC_TYPE_EXPR:
+      /* This is ignored at the RTL level.  The tree level set
+        DECL_POINTER_ALIAS_SET of any variable to be 0, which is
+        overkill for the RTL layer but is all that we can
+        represent.  */
+      return const0_rtx;
+
     case EXC_PTR_EXPR:
       return get_exception_pointer (cfun);
 
index 642cd4fdd5c0e92eaf91a100cc376687250e039a..f7888e25482a7e519dbdccbf3aef80ff9756780a 100644 (file)
@@ -242,6 +242,7 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
     case GOTO_EXPR:
     case LABEL_EXPR:
     case SWITCH_EXPR:
+    case CHANGE_DYNAMIC_TYPE_EXPR:
     case OMP_FOR:
     case OMP_SECTIONS:
     case OMP_SECTION:
index e73e00ae9ae959eafd11ee571b0b256600dc83dd..268bef184cfe548406fdefc4a77ad7a9904b5528 100644 (file)
@@ -5791,6 +5791,11 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          ret = GS_ALL_DONE;
          break;
 
+       case CHANGE_DYNAMIC_TYPE_EXPR:
+         ret = gimplify_expr (&CHANGE_DYNAMIC_TYPE_LOCATION (*expr_p),
+                              pre_p, post_p, is_gimple_reg, fb_lvalue);
+         break;
+
        case OBJ_TYPE_REF:
          {
            enum gimplify_status r0, r1;
index 234c860418f90e0d9b0decb711a5f03e062b445e..5b1f3c4c3d8c1c2131a3415d643e51c391fb477e 100644 (file)
@@ -516,6 +516,7 @@ omp_copy_decl_2 (tree var, tree name, tree type, omp_context *ctx)
 
   TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var);
   DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var);
+  DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (var);
   DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var);
   DECL_IGNORED_P (copy) = DECL_IGNORED_P (var);
   TREE_USED (copy) = 1;
index 7eef3a386d2a2fdd0cf3e4ffb9462ac2019cc3d1..7301f47a879be42e42ade606f74436db12f4949c 100644 (file)
@@ -401,7 +401,9 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
          if (DECL_VIRTUAL_P (node))
            fputs (" virtual", file);
          if (DECL_PRESERVE_P (node))
-           fputs (" preserve", file);    
+           fputs (" preserve", file);
+         if (DECL_NO_TBAA_P (node))
+           fputs (" no-tbaa", file);
          if (DECL_LANG_FLAG_0 (node))
            fputs (" decl_0", file);
          if (DECL_LANG_FLAG_1 (node))
index 7aec66339d3e44dd4615dcca1e0852ff8c2ae7f0..dff238910cd918a88e03da3e864498257d70d40f 100644 (file)
@@ -1,3 +1,11 @@
+2007-06-12  Ian Lance Taylor  <iant@google.com>
+
+       PR libstdc++/29286
+       * g++.dg/init/new16.C: New test.
+       * g++.dg/init/new17.C: New test.
+       * g++.dg/init/new18.C: New test.
+       * g++.dg/init/new19.C: New test.
+
 2007-06-12  Olivier Hainque  <hainque@adacore.com>
 
        * gnat.dg/lhs_view_convert.adb: New test.
diff --git a/gcc/testsuite/g++.dg/init/new16.C b/gcc/testsuite/g++.dg/init/new16.C
new file mode 100644 (file)
index 0000000..c49f13f
--- /dev/null
@@ -0,0 +1,38 @@
+// { dg-do run }
+// { dg-options "-O2 -fstrict-aliasing" }
+
+// Test that we don't let TBAA reorder an assignment across a
+// placement new.
+// See PR 29286.
+
+typedef __SIZE_TYPE__ size_t;
+
+inline void* operator new(size_t, void* __p) throw() { return __p; }
+
+void __attribute__((noinline)) bar() {}
+
+long __attribute__((noinline)) foo(double *p, int n)
+{
+  long *f;
+  for (int i=0; i<n; ++i)
+  {
+    int *l = (int *)p;
+    *l = 0;
+    f = new (p) long;
+    *f = -1;
+  }
+  bar ();
+  return *f;
+}
+
+extern "C" void abort(void);
+int main()
+{
+  union {
+    int i;
+    long l;
+  } u;
+  if (foo((double *)&u, 1) != -1)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/init/new17.C b/gcc/testsuite/g++.dg/init/new17.C
new file mode 100644 (file)
index 0000000..58782ff
--- /dev/null
@@ -0,0 +1,37 @@
+// { dg-do compile }
+// { dg-options "-O2 -fstrict-aliasing -fdump-tree-final_cleanup" }
+
+// Test that placement new does not introduce an unnecessary memory
+// barrier.
+// See PR 29286.
+
+typedef __SIZE_TYPE__ size_t;
+
+inline void* operator new(size_t, void* __p) throw() { return __p; }
+
+template <class T, int D>
+class Vector
+{
+public:
+   Vector()
+   {
+     for (int i = 0; i < D; ++i)
+        new (&x_m[i]) T();
+   }
+   T& operator[](int i) { return x_m[i]; }
+
+private:
+   T x_m[D];
+};
+
+void foo(Vector<float, 3> *m)
+{
+  Vector<float, 3> v;
+  v[0] = 1.0;
+  v[1] = 2.0;
+  v[3] = 3.0;
+  *m = v;
+}
+
+// { dg-final { scan-tree-dump-times "= 0\.0" 1 "final_cleanup" } }
+// { dg-final { cleanup-tree-dump "final_cleanup" } }
diff --git a/gcc/testsuite/g++.dg/init/new18.C b/gcc/testsuite/g++.dg/init/new18.C
new file mode 100644 (file)
index 0000000..45f6e7a
--- /dev/null
@@ -0,0 +1,45 @@
+// { dg-do compile }
+// { dg-options "-O2 -fstrict-aliasing" }
+
+// This caused an ICE during placement new.
+
+namespace Pooma {
+   typedef int Context_t;
+   namespace Arch {
+   }
+   inline Context_t context() {
+  }
+   inline int contexts() {
+  }
+ }
+template<class DomT, class T, class NewDom1T> struct DomainTraitsScalar {
+  };
+template<class T> struct DomainTraits : public DomainTraitsScalar<T, T, T> {
+  };
+template<int Dim> class Grid;
+template<class DT> class DomainBase {
+  };
+template<int Dim, class DT> class Domain : public DomainBase<DT> {
+  };
+#include <vector>
+template<> class Grid<1> : public Domain<1, DomainTraits<Grid<1> > > {
+  };
+namespace Pooma {
+ class PatchSizeSyncer {
+    typedef Grid<1> Grid_t;
+    PatchSizeSyncer(int contextKey, Grid_t &localGrid);
+    int myContext_m;
+    int numContexts_m;
+    int localKey_m;
+    Grid_t localGrid_m;
+    typedef std::pair<int,Grid_t *> Elem_t;
+    std::vector<Elem_t> gridList_m;
+  };
+ }
+namespace Pooma {
+ PatchSizeSyncer::PatchSizeSyncer(int contextKey, Grid_t &localGrid)   :
+myContext_m(Pooma::context()),     numContexts_m(Pooma::contexts()),    
+localKey_m(contextKey),     localGrid_m(localGrid) {
+    if (myContext_m == 0) gridList_m.reserve(numContexts_m);
+  }
+ }
diff --git a/gcc/testsuite/g++.dg/init/new19.C b/gcc/testsuite/g++.dg/init/new19.C
new file mode 100644 (file)
index 0000000..a139a35
--- /dev/null
@@ -0,0 +1,73 @@
+// { dg-do compile }
+// { dg-options "-O2 -fstrict-aliasing -fdump-tree-lim-details" }
+
+// Make sure we hoist invariants out of the loop even in the presence
+// of placement new.  This is similar to code in tramp3d.
+
+typedef __SIZE_TYPE__ size_t;
+
+inline void* operator new(size_t, void* __p) throw() { return __p; }
+
+template <class T, int D>
+class Vector
+{
+public:
+   Vector()
+   {
+     for (int i = 0; i < D; ++i)
+        new (&x_m[i]) T();
+   }
+   T& operator[](int i) { return x_m[i]; }
+
+private:
+   T x_m[D];
+};
+
+struct sia
+{
+  int ai[3];
+};
+
+struct s
+{
+  struct si
+  {
+    sia* p;
+  } asi[3];
+  float* pd;
+};
+
+class c
+{
+  int foo(int, int, int);
+  s sm;
+};
+
+
+extern void bar(Vector<float, 3>*, int);
+int c::foo(int f1, int f2, int f3)
+{
+  float sum = 0;
+  for (int i = 0; i < 3; ++i)
+    {
+      for (int j = 0; j < 3; ++j)
+       {
+         Vector<float, 3> v;
+         v[0] = 1.0;
+         v[1] = 2.0;
+         v[2] = 3.0;
+         for (int k = 0; k < 3; ++k)
+           {
+             float f = (f1 * this->sm.asi[0].p->ai[0]
+                        + f2 * this->sm.asi[1].p->ai[0]
+                        + f3 * this->sm.asi[2].p->ai[0]);
+             sum += f * v[k];
+           }
+         *this->sm.pd = sum;
+       }
+    }
+  return sum;
+}
+
+// { dg-final { scan-tree-dump "Moving statement\\n.*->ai\\\[0\\\];\\n.*out of loop" "lim" } }
+// { dg-final { cleanup-tree-dump "lim" } }
index 5530afb231dd3eadceb87f1d664ce10068095b5d..16caf0ad573b024656d1b3c3960aedbece9bbabd 100644 (file)
@@ -1,5 +1,6 @@
 /* Functions to analyze and validate GIMPLE trees.
-   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
    Rewritten by Jason Merrill <jason@redhat.com>
 
@@ -222,6 +223,7 @@ is_gimple_stmt (tree t)
     case TRY_FINALLY_EXPR:
     case EH_FILTER_EXPR:
     case CATCH_EXPR:
+    case CHANGE_DYNAMIC_TYPE_EXPR:
     case ASM_EXPR:
     case RESX_EXPR:
     case PHI_NODE:
index 799b4f3fb6e3abc55bd9defbc8d91e861daa3275..11d400afe61c9470b12354a925c33537d5b63307 100644 (file)
@@ -2030,6 +2030,11 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
       *walk_subtrees = 0;
       return NULL;
 
+      /* CHANGE_DYNAMIC_TYPE_EXPR explicitly expands to nothing.  */
+    case CHANGE_DYNAMIC_TYPE_EXPR:
+      *walk_subtrees = 0;
+      return NULL;
+
     /* Try to estimate the cost of assignments.  We have three cases to
        deal with:
        1) Simple assignments to registers;
@@ -3217,6 +3222,7 @@ copy_decl_to_var (tree decl, copy_body_data *id)
   TREE_READONLY (copy) = TREE_READONLY (decl);
   TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
   DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (decl);
+  DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (decl);
 
   return copy_decl_for_dup_finish (id, decl, copy);
 }
@@ -3243,6 +3249,7 @@ copy_result_decl_to_var (tree decl, copy_body_data *id)
     {
       TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
       DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (decl);
+      DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (decl);
     }
 
   return copy_decl_for_dup_finish (id, decl, copy);
index 7cfd4b51a148bd8a951251c9a7b23ce898abea7e..0c313f20e88bbf3a5dd073cd0d6e95f30c6dd303 100644 (file)
@@ -1496,6 +1496,17 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       is_expr = false;
       break;
 
+    case CHANGE_DYNAMIC_TYPE_EXPR:
+      pp_string (buffer, "<<<change_dynamic_type (");
+      dump_generic_node (buffer, CHANGE_DYNAMIC_TYPE_NEW_TYPE (node), spc + 2,
+                        flags, false);
+      pp_string (buffer, ") ");
+      dump_generic_node (buffer, CHANGE_DYNAMIC_TYPE_LOCATION (node), spc + 2,
+                        flags, false);
+      pp_string (buffer, ")>>>");
+      is_expr = false;
+      break;
+
     case LABEL_EXPR:
       op0 = TREE_OPERAND (node, 0);
       /* If this is for break or continue, don't bother printing it.  */
index 9fa312919c740771589b997df227d049e32661b5..cf5dc2b45e7604a833efd97f6490af49d378c2bb 100644 (file)
@@ -1,5 +1,5 @@
 /* Alias analysis for trees.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
 This file is part of GCC.
@@ -2720,69 +2720,72 @@ may_alias_p (tree ptr, HOST_WIDE_INT mem_alias_set,
 
   gcc_assert (TREE_CODE (mem) == SYMBOL_MEMORY_TAG);
 
-  alias_stats.tbaa_queries++;
-
-  /* If the alias sets don't conflict then MEM cannot alias VAR.  */
-  if (!alias_sets_conflict_p (mem_alias_set, var_alias_set))
+  if (!DECL_NO_TBAA_P (ptr))
     {
-      alias_stats.alias_noalias++;
-      alias_stats.tbaa_resolved++;
-      return false;
-    }
+      alias_stats.tbaa_queries++;
 
-  /* If VAR is a record or union type, PTR cannot point into VAR
-     unless there is some explicit address operation in the
-     program that can reference a field of the type pointed-to by PTR.
-     This also assumes that the types of both VAR and PTR are
-     contained within the compilation unit, and that there is no fancy
-     addressing arithmetic associated with any of the types
-     involved.  */
-  if (mem_alias_set != 0 && var_alias_set != 0)
-    {
-      tree ptr_type = TREE_TYPE (ptr);
-      tree var_type = TREE_TYPE (var);
-      
-      /* The star count is -1 if the type at the end of the pointer_to 
-        chain is not a record or union type. */ 
-      if ((!alias_set_only) && 
-         ipa_type_escape_star_count_of_interesting_type (var_type) >= 0)
+      /* If the alias sets don't conflict then MEM cannot alias VAR.  */
+      if (!alias_sets_conflict_p (mem_alias_set, var_alias_set))
        {
-         int ptr_star_count = 0;
-         
-         /* ipa_type_escape_star_count_of_interesting_type is a
-            little too restrictive for the pointer type, need to
-            allow pointers to primitive types as long as those types
-            cannot be pointers to everything.  */
-         while (POINTER_TYPE_P (ptr_type))
+         alias_stats.alias_noalias++;
+         alias_stats.tbaa_resolved++;
+         return false;
+       }
+
+      /* If VAR is a record or union type, PTR cannot point into VAR
+        unless there is some explicit address operation in the
+        program that can reference a field of the type pointed-to by
+        PTR.  This also assumes that the types of both VAR and PTR
+        are contained within the compilation unit, and that there is
+        no fancy addressing arithmetic associated with any of the
+        types involved.  */
+      if (mem_alias_set != 0 && var_alias_set != 0)
+       {
+         tree ptr_type = TREE_TYPE (ptr);
+         tree var_type = TREE_TYPE (var);
+      
+         /* The star count is -1 if the type at the end of the
+            pointer_to chain is not a record or union type. */ 
+         if ((!alias_set_only) && 
+             ipa_type_escape_star_count_of_interesting_type (var_type) >= 0)
            {
-             /* Strip the *s off.  */ 
-             ptr_type = TREE_TYPE (ptr_type);
-             ptr_star_count++;
-           }
+             int ptr_star_count = 0;
          
-         /* There does not appear to be a better test to see if the 
-            pointer type was one of the pointer to everything 
-            types.  */
-         if (ptr_star_count > 0)
-           {
-             alias_stats.structnoaddress_queries++;
-             if (ipa_type_escape_field_does_not_clobber_p (var_type, 
-                                                           TREE_TYPE (ptr))) 
+             /* ipa_type_escape_star_count_of_interesting_type is a
+                little too restrictive for the pointer type, need to
+                allow pointers to primitive types as long as those
+                types cannot be pointers to everything.  */
+             while (POINTER_TYPE_P (ptr_type))
+               {
+                 /* Strip the *s off.  */ 
+                 ptr_type = TREE_TYPE (ptr_type);
+                 ptr_star_count++;
+               }
+         
+             /* There does not appear to be a better test to see if
+                the pointer type was one of the pointer to everything
+                types.  */
+             if (ptr_star_count > 0)
                {
+                 alias_stats.structnoaddress_queries++;
+                 if (ipa_type_escape_field_does_not_clobber_p (var_type, 
+                                                               TREE_TYPE (ptr)))
+                   {
+                     alias_stats.structnoaddress_resolved++;
+                     alias_stats.alias_noalias++;
+                     return false;
+                   }
+               }
+             else if (ptr_star_count == 0)
+               {
+                 /* If PTR_TYPE was not really a pointer to type, it cannot 
+                    alias.  */ 
+                 alias_stats.structnoaddress_queries++;
                  alias_stats.structnoaddress_resolved++;
                  alias_stats.alias_noalias++;
                  return false;
                }
            }
-         else if (ptr_star_count == 0)
-           {
-             /* If PTR_TYPE was not really a pointer to type, it cannot 
-                alias.  */ 
-             alias_stats.structnoaddress_queries++;
-             alias_stats.structnoaddress_resolved++;
-             alias_stats.alias_noalias++;
-             return false;
-           }
        }
     }
 
index a2f80aa308fcdd1e8030d983766c3625a439275b..d0335a0593f8d0aa189bc999694a53c8a5c442bf 100644 (file)
@@ -1,5 +1,6 @@
 /* Dead code elimination pass for the GNU compiler.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Ben Elliston <bje@redhat.com>
    and Andrew MacLeod <amacleod@redhat.com>
    Adapted to use control dependence by Steven Bosscher, SUSE Labs.
@@ -286,6 +287,7 @@ mark_stmt_if_obviously_necessary (tree stmt, bool aggressive)
     case ASM_EXPR:
     case RESX_EXPR:
     case RETURN_EXPR:
+    case CHANGE_DYNAMIC_TYPE_EXPR:
       mark_stmt_necessary (stmt, true);
       return;
 
index d015a569cd28c46ed75834d8fbda92a0ffbff0b5..edd2b9021883f2027208198ea2ebf75a6cd61826 100644 (file)
@@ -2266,6 +2266,10 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
         return;
       }
 
+    case CHANGE_DYNAMIC_TYPE_EXPR:
+      get_expr_operands (stmt, &CHANGE_DYNAMIC_TYPE_LOCATION (expr), opf_use);
+      return;
+
     case BLOCK:
     case FUNCTION_DECL:
     case EXC_PTR_EXPR:
index d351bf503c24c3245a3196eb781a75641523be4b..c5dbf5c5d7f4fd490dff754abda62a4c14bf9374 100644 (file)
@@ -250,6 +250,10 @@ struct variable_info
   /* True if this is a heap variable.  */
   unsigned int is_heap_var:1;
 
+  /* True if we may not use TBAA to prune references to this
+     variable.  This is used for C++ placement new.  */
+  unsigned int no_tbaa_pruning : 1;
+
   /* Points-to set for this variable.  */
   bitmap solution;
 
@@ -359,6 +363,7 @@ static varinfo_t
 new_var_info (tree t, unsigned int id, const char *name)
 {
   varinfo_t ret = (varinfo_t) pool_alloc (variable_info_pool);
+  tree var;
 
   ret->id = id;
   ret->name = name;
@@ -369,6 +374,12 @@ new_var_info (tree t, unsigned int id, const char *name)
   ret->is_special_var = false;
   ret->is_unknown_size_var = false;
   ret->has_union = false;
+  var = t;
+  if (TREE_CODE (var) == SSA_NAME)
+    var = SSA_NAME_VAR (var);
+  ret->no_tbaa_pruning = (DECL_P (var)
+                         && POINTER_TYPE_P (TREE_TYPE (var))
+                         && DECL_NO_TBAA_P (var));
   ret->solution = BITMAP_ALLOC (&pta_obstack);
   ret->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
   ret->next = NULL;
@@ -1195,6 +1206,9 @@ unify_nodes (constraint_graph_t graph, unsigned int to, unsigned int from,
   merge_graph_nodes (graph, to, from);
   merge_node_constraints (graph, to, from);
 
+  if (get_varinfo (from)->no_tbaa_pruning)
+    get_varinfo (to)->no_tbaa_pruning = true;
+
   if (update_changed && TEST_BIT (changed, from))
     {
       RESET_BIT (changed, from);
@@ -3563,6 +3577,14 @@ find_func_aliases (tree origt)
            }
        }
     }
+  else if (TREE_CODE (t) == CHANGE_DYNAMIC_TYPE_EXPR)
+    {
+      unsigned int j;
+
+      get_constraint_for (CHANGE_DYNAMIC_TYPE_LOCATION (t), &lhsc);
+      for (j = 0; VEC_iterate (ce_s, lhsc, j, c); ++j)
+       get_varinfo (c->var)->no_tbaa_pruning = true;
+    }
 
   /* After promoting variables and computing aliasing we will
      need to re-scan most statements.  FIXME: Try to minimize the
@@ -4130,7 +4152,10 @@ dump_solution_for_var (FILE *file, unsigned int var)
        {
          fprintf (file, "%s ", get_varinfo (i)->name);
        }
-      fprintf (file, "}\n");
+      fprintf (file, "}");
+      if (vi->no_tbaa_pruning)
+       fprintf (file, " no-tbaa-pruning");
+      fprintf (file, "\n");
     }
 }
 
@@ -4292,10 +4317,13 @@ shared_bitmap_add (bitmap pt_vars)
    For variables that are actually dereferenced, we also use type
    based alias analysis to prune the points-to sets.
    IS_DEREFED is true if PTR was directly dereferenced, which we use to
-   help determine whether we are we are allowed to prune using TBAA.  */
+   help determine whether we are we are allowed to prune using TBAA.
+   If NO_TBAA_PRUNING is true, we do not perform any TBAA pruning of
+   the from set.  */
 
 static void
-set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed)
+set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed,
+                  bool no_tbaa_pruning)
 {
   unsigned int i;
   bitmap_iterator bi;
@@ -4331,7 +4359,8 @@ set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed)
              if (sft)
                {
                  var_alias_set = get_alias_set (sft);
-                 if ((!is_derefed && !vi->directly_dereferenced)
+                 if (no_tbaa_pruning
+                     || (!is_derefed && !vi->directly_dereferenced)
                      || alias_sets_conflict_p (ptr_alias_set, var_alias_set))
                    bitmap_set_bit (into, DECL_UID (sft));
                }
@@ -4345,7 +4374,8 @@ set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed)
              else
                {
                  var_alias_set = get_alias_set (vi->decl);
-                 if ((!is_derefed && !vi->directly_dereferenced)
+                 if (no_tbaa_pruning
+                     || (!is_derefed && !vi->directly_dereferenced)
                      || alias_sets_conflict_p (ptr_alias_set, var_alias_set))
                    bitmap_set_bit (into, DECL_UID (vi->decl));
                }
@@ -4558,7 +4588,8 @@ find_what_p_points_to (tree p)
            }
          
          set_uids_in_ptset (vi->decl, finished_solution, vi->solution,
-                            vi->directly_dereferenced);
+                            vi->directly_dereferenced,
+                            vi->no_tbaa_pruning);
          result = shared_bitmap_lookup (finished_solution);
 
          if (!result)
@@ -4784,6 +4815,142 @@ remove_preds_and_fake_succs (constraint_graph_t graph)
   bitmap_obstack_release (&predbitmap_obstack);
 }
 
+/* Compute the set of variables we can't TBAA prune.  */
+
+static void
+compute_tbaa_pruning (void)
+{
+  unsigned int size = VEC_length (varinfo_t, varmap);
+  unsigned int i;
+  bool any;
+
+  changed_count = 0;
+  changed = sbitmap_alloc (size);
+  sbitmap_zero (changed);
+
+  /* Mark all initial no_tbaa_pruning nodes as changed.  */
+  any = false;
+  for (i = 0; i < size; ++i)
+    {
+      varinfo_t ivi = get_varinfo (i);
+
+      if (find (i) == i && ivi->no_tbaa_pruning)
+       {
+         any = true;
+         if ((graph->succs[i] && !bitmap_empty_p (graph->succs[i]))
+             || VEC_length (constraint_t, graph->complex[i]) > 0)
+           {
+             SET_BIT (changed, i);
+             ++changed_count;
+           }
+       }
+    }
+
+  while (changed_count > 0)
+    {
+      struct topo_info *ti = init_topo_info ();
+      ++stats.iterations;
+
+      bitmap_obstack_initialize (&iteration_obstack);
+
+      compute_topo_order (graph, ti);
+
+      while (VEC_length (unsigned, ti->topo_order) != 0)
+       {
+         bitmap_iterator bi;
+
+         i = VEC_pop (unsigned, ti->topo_order);
+
+         /* If this variable is not a representative, skip it.  */
+         if (find (i) != i)
+           continue;
+
+         /* If the node has changed, we need to process the complex
+            constraints and outgoing edges again.  */
+         if (TEST_BIT (changed, i))
+           {
+             unsigned int j;
+             constraint_t c;
+             VEC(constraint_t,heap) *complex = graph->complex[i];
+
+             RESET_BIT (changed, i);
+             --changed_count;
+
+             /* Process the complex copy constraints.  */
+             for (j = 0; VEC_iterate (constraint_t, complex, j, c); ++j)
+               {
+                 if (c->lhs.type == SCALAR && c->rhs.type == SCALAR)
+                   {
+                     varinfo_t lhsvi = get_varinfo (find (c->lhs.var));
+
+                     if (!lhsvi->no_tbaa_pruning)
+                       {
+                         lhsvi->no_tbaa_pruning = true;
+                         if (!TEST_BIT (changed, lhsvi->id))
+                           {
+                             SET_BIT (changed, lhsvi->id);
+                             ++changed_count;
+                           }
+                       }
+                   }
+               }
+
+             /* Propagate to all successors.  */
+             EXECUTE_IF_IN_NONNULL_BITMAP (graph->succs[i], 0, j, bi)
+               {
+                 unsigned int to = find (j);
+                 varinfo_t tovi = get_varinfo (to);
+
+                 /* Don't propagate to ourselves.  */
+                 if (to == i)
+                   continue;
+
+                 if (!tovi->no_tbaa_pruning)
+                   {
+                     tovi->no_tbaa_pruning = true;
+                     if (!TEST_BIT (changed, to))
+                       {
+                         SET_BIT (changed, to);
+                         ++changed_count;
+                       }
+                   }
+               }
+           }
+       }
+
+      free_topo_info (ti);
+      bitmap_obstack_release (&iteration_obstack);
+    }
+
+  sbitmap_free (changed);
+
+  if (any)
+    {
+      for (i = 0; i < size; ++i)
+       {
+         varinfo_t ivi = get_varinfo (i);
+         varinfo_t ivip = get_varinfo (find (i));
+
+         if (ivip->no_tbaa_pruning)
+           {
+             tree var = ivi->decl;
+
+             if (TREE_CODE (var) == SSA_NAME)
+               var = SSA_NAME_VAR (var);
+
+             if (POINTER_TYPE_P (TREE_TYPE (var)))
+               {
+                 DECL_NO_TBAA_P (var) = 1;
+
+                 /* Tell the RTL layer that this pointer can alias
+                    anything.  */
+                 DECL_POINTER_ALIAS_SET (var) = 0;
+               }
+           }
+       }
+    }
+}
+
 /* Create points-to sets for the current function.  See the comments
    at the start of the file for an algorithmic overview.  */
 
@@ -4820,7 +4987,7 @@ compute_points_to_sets (struct alias_info *ai)
            }
        }
 
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
        {
          tree stmt = bsi_stmt (bsi);
 
@@ -4831,6 +4998,13 @@ compute_points_to_sets (struct alias_info *ai)
             This is used when creating name tags and alias
             sets.  */
          update_alias_info (stmt, ai);
+
+         /* The information in CHANGE_DYNAMIC_TYPE_EXPR nodes has now
+            been captured, and we can remove them.  */
+         if (TREE_CODE (stmt) == CHANGE_DYNAMIC_TYPE_EXPR)
+           bsi_remove (&bsi, true);
+         else
+           bsi_next (&bsi);
        }
     }
 
@@ -4862,6 +5036,8 @@ compute_points_to_sets (struct alias_info *ai)
 
   solve_graph (graph);
 
+  compute_tbaa_pruning ();
+
   if (dump_file)
     dump_sa_points_to_info (dump_file);
 
index e1f5fef063e03424d3910cb132dbf94310cd01d0..d4038322bcd812cee8856111e13da180630c769d 100644 (file)
@@ -1,7 +1,7 @@
 /* This file contains the definitions and documentation for the
    tree codes used in GCC.
    Copyright (C) 1987, 1988, 1993, 1995, 1997, 1998, 2000, 2001, 2004, 2005, 
-   2006 Free Software Foundation, Inc.
+   2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -876,6 +876,15 @@ DEFTREECODE (CATCH_EXPR, "catch_expr", tcc_statement, 2)
    expanding.  */
 DEFTREECODE (EH_FILTER_EXPR, "eh_filter_expr", tcc_statement, 2)
 
+/* Indicates a change in the dynamic type of a memory location.  This
+   has no value and generates no executable code.  It is only used for
+   type based alias analysis.  This is generated by C++ placement new.
+   CHANGE_DYNAMIC_TYPE_NEW_TYPE, the first operand, is the new type.
+   CHNAGE_DYNAMIC_TYPE_LOCATION, the second operand, is the location
+   whose type is being changed.  */
+DEFTREECODE (CHANGE_DYNAMIC_TYPE_EXPR, "change_dynamic_type_expr",
+            tcc_statement, 2)
+
 /* Node used for describing a property that is known at compile
    time.  */
 DEFTREECODE (SCEV_KNOWN, "scev_known", tcc_expression, 0)
index 572a1e7c6f9a6cd772ad1bf820847ce1350fe482..aefc00ee33a91dbc026d4f5414cb3268a32cd12e 100644 (file)
@@ -1637,6 +1637,12 @@ struct tree_constructor GTY(())
 #define EH_FILTER_FAILURE(NODE)        TREE_OPERAND (EH_FILTER_EXPR_CHECK (NODE), 1)
 #define EH_FILTER_MUST_NOT_THROW(NODE) TREE_STATIC (EH_FILTER_EXPR_CHECK (NODE))
 
+/* CHANGE_DYNAMIC_TYPE_EXPR accessors.  */
+#define CHANGE_DYNAMIC_TYPE_NEW_TYPE(NODE) \
+  TREE_OPERAND (CHANGE_DYNAMIC_TYPE_EXPR_CHECK (NODE), 0)
+#define CHANGE_DYNAMIC_TYPE_LOCATION(NODE) \
+  TREE_OPERAND (CHANGE_DYNAMIC_TYPE_EXPR_CHECK (NODE), 1)
+
 /* OBJ_TYPE_REF accessors.  */
 #define OBJ_TYPE_REF_EXPR(NODE)          TREE_OPERAND (OBJ_TYPE_REF_CHECK (NODE), 0)
 #define OBJ_TYPE_REF_OBJECT(NODE) TREE_OPERAND (OBJ_TYPE_REF_CHECK (NODE), 1)
@@ -2671,6 +2677,11 @@ struct tree_memory_partition_tag GTY(())
 #define DECL_GIMPLE_REG_P(DECL) \
   DECL_COMMON_CHECK (DECL)->decl_common.gimple_reg_flag
 
+/* For a DECL with pointer type, this is set if Type Based Alias
+   Analysis should not be applied to this DECL.  */
+#define DECL_NO_TBAA_P(DECL) \
+  DECL_COMMON_CHECK (DECL)->decl_common.no_tbaa_flag
+
 struct tree_decl_common GTY(())
 {
   struct tree_decl_minimal common;
@@ -2711,6 +2722,8 @@ struct tree_decl_common GTY(())
   /* Logically, these two would go in a theoretical base shared by var and
      parm decl. */
   unsigned gimple_reg_flag : 1;
+  /* In a DECL with pointer type, set if no TBAA should be done.  */
+  unsigned no_tbaa_flag : 1;
 
   union tree_decl_u1 {
     /* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is