gcc: backport upstream fix for issue with C++'s placement new
Fixes GCC libstdc++/29286 Obtained from: gcc 4.3 (rev. 125603, 125653; GPLv2) MFC after: 2 weeks
This commit is contained in:
parent
0a036e525d
commit
915b4b42ae
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=259619
@ -65,6 +65,48 @@
|
||||
fvisibility-ms-compat.
|
||||
* c.opt (fvisibility-ms-compat): New.
|
||||
|
||||
2007-06-12 Ian Lance Taylor <iant@google.com> (r125653)
|
||||
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-09 Daniel Berlin <dberlin@dberlin.org> (r125603)
|
||||
|
||||
* tree-ssa-structalias.c (set_uids_in_ptset): Add is_deref'd
|
||||
parameter, use it.
|
||||
(find_what_p_points_to): Pass new parameter to set_uids_in_ptset.
|
||||
|
||||
2007-06-05 Joerg Wunsch <j.gnu@uriah.heep.sax.de> (r125346)
|
||||
|
||||
PR preprocessor/23479
|
||||
|
@ -25,6 +25,12 @@
|
||||
* decl2.c (determine_visibility): Remove duplicate code for
|
||||
handling type info.
|
||||
|
||||
2007-06-12 Ian Lance Taylor <iant@google.com> (r125653)
|
||||
|
||||
PR libstdc++/29286
|
||||
* init.c (avoid_placement_new_aliasing): New static function.
|
||||
(build_new_1): Call it.
|
||||
|
||||
2007-05-31 Daniel Berlin <dberlin@dberlin.org> (r125239)
|
||||
|
||||
* typeck.c (build_binary_op): Include types in error.
|
||||
|
@ -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
|
||||
@ -2051,6 +2121,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;
|
||||
}
|
||||
|
||||
|
@ -1916,6 +1916,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
|
||||
@ -2572,6 +2573,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
|
||||
|
@ -8718,6 +8718,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);
|
||||
|
||||
|
@ -243,6 +243,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:
|
||||
|
@ -5748,6 +5748,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;
|
||||
|
@ -518,6 +518,7 @@ omp_copy_decl_2 (tree var, tree name, tree type, omp_context *ctx)
|
||||
|
||||
TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var);
|
||||
DECL_COMPLEX_GIMPLE_REG_P (copy) = DECL_COMPLEX_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;
|
||||
|
@ -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))
|
||||
|
@ -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>
|
||||
|
||||
@ -215,6 +216,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:
|
||||
|
@ -1649,6 +1649,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;
|
||||
@ -2635,6 +2640,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_COMPLEX_GIMPLE_REG_P (copy) = DECL_COMPLEX_GIMPLE_REG_P (decl);
|
||||
DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (decl);
|
||||
|
||||
return copy_decl_for_dup_finish (id, decl, copy);
|
||||
}
|
||||
@ -2661,6 +2667,7 @@ copy_result_decl_to_var (tree decl, copy_body_data *id)
|
||||
{
|
||||
TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
|
||||
DECL_COMPLEX_GIMPLE_REG_P (copy) = DECL_COMPLEX_GIMPLE_REG_P (decl);
|
||||
DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (decl);
|
||||
}
|
||||
|
||||
return copy_decl_for_dup_finish (id, decl, copy);
|
||||
|
@ -1443,6 +1443,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. */
|
||||
|
@ -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.
|
||||
@ -1961,28 +1961,29 @@ 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 operation explicit address operation in the
|
||||
program that can reference a field of the ptr's dereferenced
|
||||
type. 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 the alias sets don't conflict then MEM cannot alias VAR. */
|
||||
if (!alias_sets_conflict_p (mem_alias_set, var_alias_set))
|
||||
{
|
||||
alias_stats.alias_noalias++;
|
||||
alias_stats.tbaa_resolved++;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((mem_alias_set != 0) && (var_alias_set != 0))
|
||||
{
|
||||
tree ptr_type = TREE_TYPE (ptr);
|
||||
tree var_type = TREE_TYPE (var);
|
||||
/* 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. */
|
||||
@ -1991,41 +1992,41 @@ may_alias_p (tree ptr, HOST_WIDE_INT mem_alias_set,
|
||||
{
|
||||
int ptr_star_count = 0;
|
||||
|
||||
/* Ipa_type_escape_star_count_of_interesting_type is a little to
|
||||
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)))
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
@ -307,6 +308,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;
|
||||
|
||||
|
@ -2057,6 +2057,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_none);
|
||||
return;
|
||||
|
||||
case BLOCK:
|
||||
case FUNCTION_DECL:
|
||||
case EXC_PTR_EXPR:
|
||||
|
@ -251,6 +251,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;
|
||||
|
||||
@ -368,6 +372,7 @@ static varinfo_t
|
||||
new_var_info (tree t, unsigned int id, const char *name)
|
||||
{
|
||||
varinfo_t ret = pool_alloc (variable_info_pool);
|
||||
tree var;
|
||||
|
||||
ret->id = id;
|
||||
ret->name = name;
|
||||
@ -378,6 +383,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;
|
||||
@ -1221,6 +1232,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);
|
||||
@ -3564,6 +3578,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
|
||||
@ -4250,7 +4272,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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -4422,10 +4447,15 @@ shared_bitmap_add (bitmap pt_vars)
|
||||
/* Set bits in INTO corresponding to the variable uids in solution set
|
||||
FROM, which came from variable PTR.
|
||||
For variables that are actually dereferenced, we also use type
|
||||
based alias analysis to prune the points-to sets. */
|
||||
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.
|
||||
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)
|
||||
set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed,
|
||||
bool no_tbaa_pruning)
|
||||
{
|
||||
unsigned int i;
|
||||
bitmap_iterator bi;
|
||||
@ -4462,7 +4492,8 @@ set_uids_in_ptset (tree ptr, bitmap into, bitmap from)
|
||||
if (sft)
|
||||
{
|
||||
var_alias_set = get_alias_set (sft);
|
||||
if (!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));
|
||||
}
|
||||
@ -4476,7 +4507,8 @@ set_uids_in_ptset (tree ptr, bitmap into, bitmap from)
|
||||
else
|
||||
{
|
||||
var_alias_set = get_alias_set (vi->decl);
|
||||
if (!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));
|
||||
}
|
||||
@ -4564,7 +4596,9 @@ find_what_p_points_to (tree p)
|
||||
return false;
|
||||
|
||||
finished_solution = BITMAP_GGC_ALLOC ();
|
||||
set_uids_in_ptset (vi->decl, finished_solution, vi->solution);
|
||||
set_uids_in_ptset (vi->decl, finished_solution, vi->solution,
|
||||
vi->directly_dereferenced,
|
||||
vi->no_tbaa_pruning);
|
||||
result = shared_bitmap_lookup (finished_solution);
|
||||
|
||||
if (!result)
|
||||
@ -4913,6 +4947,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. */
|
||||
|
||||
@ -4948,7 +5118,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);
|
||||
|
||||
@ -4959,6 +5129,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4991,6 +5168,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);
|
||||
have_alias_info = true;
|
||||
|
@ -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.
|
||||
|
||||
@ -880,6 +880,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)
|
||||
|
@ -1548,6 +1548,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)
|
||||
@ -2538,6 +2544,11 @@ struct tree_struct_field_tag GTY(())
|
||||
#define DECL_CALL_CLOBBERED(DECL) \
|
||||
DECL_COMMON_CHECK (DECL)->decl_common.call_clobbered_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;
|
||||
@ -2579,6 +2590,8 @@ struct tree_decl_common GTY(())
|
||||
parm decl. */
|
||||
unsigned gimple_reg_flag : 1;
|
||||
unsigned call_clobbered_flag : 1;
|
||||
/* In a DECL with pointer type, set if no TBAA should be done. */
|
||||
unsigned no_tbaa_flag : 1;
|
||||
|
||||
unsigned int align : 24;
|
||||
/* DECL_OFFSET_ALIGN, used only for FIELD_DECLs. */
|
||||
|
Loading…
Reference in New Issue
Block a user