+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
+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.
/* 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.
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
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;
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))
{
/* 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
/* 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;
}
@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
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
/* 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);
case GOTO_EXPR:
case LABEL_EXPR:
case SWITCH_EXPR:
+ case CHANGE_DYNAMIC_TYPE_EXPR:
case OMP_FOR:
case OMP_SECTIONS:
case OMP_SECTION:
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;
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;
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))
+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.
--- /dev/null
+// { 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;
+}
--- /dev/null
+// { 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" } }
--- /dev/null
+// { 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);
+ }
+ }
--- /dev/null
+// { 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" } }
/* 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>
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:
*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;
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);
}
{
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);
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. */
/* 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.
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;
- }
}
}
/* 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.
case ASM_EXPR:
case RESX_EXPR:
case RETURN_EXPR:
+ case CHANGE_DYNAMIC_TYPE_EXPR:
mark_stmt_necessary (stmt, true);
return;
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:
/* 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;
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;
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;
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);
}
}
}
+ 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
{
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");
}
}
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;
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));
}
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));
}
}
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)
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. */
}
}
- 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);
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);
}
}
solve_graph (graph);
+ compute_tbaa_pruning ();
+
if (dump_file)
dump_sa_points_to_info (dump_file);
/* 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.
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)
#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)
#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;
/* 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