* [PATCH] Re-do call-clobber computation, track non-local pt sets, fix PRs 36400, 36373 and 36344
@ 2008-06-23 14:05 Richard Guenther
2008-06-27 19:05 ` Richard Guenther
0 siblings, 1 reply; 5+ messages in thread
From: Richard Guenther @ 2008-06-23 14:05 UTC (permalink / raw)
To: gcc-patches; +Cc: Daniel Berlin, Diego Novillo
This fixes a bunch of wrong-code bugs with respect to not accounting for
escapes of aggregates for call-clobber computation. It ends up
re-writing call clobber computation in terms of PTA. For this not to
loose too much precision I re-added the ability of PTA to track non-local
points-to sets.
The patch is already quite big, so I left the following for followups:
- remove most of the old call clobber computation code, get rid of
SMTs during this.
- track call-used variables separately (this will fix the XFAIL of
pr24287.c)
- some code movement and proper fixing of the PTA alias-warning code
The code idea of this patch should be applicable to the 4.3 branch as
well, I'll try to prepare a version for the branch at some point.
I tested compile-time performance of this patch on the usual PTA
time-hogs (especially those from 4.2, where we had a similar
mechanism), and compile-time is basically unchanged.
Bootstrapped and tested on x86_64-unknown-linux-gnu - ok for trunk?
Thanks,
Richard.
2008-06-23 Richard Guenther <rguenther@suse.de>
PR tree-optimization/36400
PR tree-optimization/36373
PR tree-optimization/36344
* tree-ssa-structalias.c (var_escaped, escaped_tree, escaped_id,
var_nonlocal, nonlocal_tree, nonlocal_id): New globals
(update_alias_info): Remove call clobbering code.
(make_escape_constraint): New helper function.
(handle_rhs_call): Use it on all pointer containing arguments.
Also mark the static chain escaped.
(handle_lhs_call): Make constraints from NONLOCAL and ESCAPED
instead of ANYTHING.
(make_constraint_from): New helper split out from ...
(make_constraint_from_anything): ... here.
(find_func_aliases): Add constraints for escape sites.
(intra_create_variable_infos): Make constraints from NONLOCAL
for parameters.
(find_what_p_points_to): Interpret NONLOCAL and ESCAPED the same
as ANYTHING.
(clobber_what_p_points_to): Remove.
(clobber_what_escaped): New function.
(init_base_vars): Init NONLOCAL and ESCAPED.
* tree-flow.h (clobber_what_p_points_to): Remove.
(clobber_what_escaped): Declare.
* tree-ssa-alias.c (set_initial_properties): Call it.
Remove code clobbering escaped pointers.
* gcc.dg/torture/pr36373-1.c: New testcase.
* gcc.dg/torture/pr36373-2.c: Likewise.
* gcc.dg/torture/pr36373-3.c: Likewise.
* gcc.dg/torture/pr36373-4.c: Likewise.
* gcc.dg/torture/pr36373-5.c: Likewise.
* gcc.dg/torture/pr36373-6.c: Likewise.
* gcc.dg/torture/pr36373-7.c: Likewise.
* gcc.dg/torture/pr36373-8.c: Likewise.
* gcc.dg/torture/pr36373-9.c: Likewise.
* gcc.dg/torture/pr36373-10.c: Likewise.
* gcc.dg/torture/pr36400.c: Likewise.
* gcc.dg/tree-ssa/loadpre8.c: Remove XFAIL.
* gcc.dg/tree-ssa/pr24287.c: XFAIL.
Index: trunk/gcc/tree-ssa-structalias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-structalias.c 2008-06-12 12:19:41.000000000 +0200
--- trunk/gcc/tree-ssa-structalias.c 2008-06-23 14:16:46.000000000 +0200
*************** get_varinfo_fc (unsigned int n)
*** 294,319 ****
return v;
}
/* Variable that represents the unknown pointer. */
static varinfo_t var_anything;
static tree anything_tree;
- static unsigned int anything_id;
/* Variable that represents the NULL pointer. */
static varinfo_t var_nothing;
static tree nothing_tree;
- static unsigned int nothing_id;
/* Variable that represents read only memory. */
static varinfo_t var_readonly;
static tree readonly_tree;
! static unsigned int readonly_id;
/* Variable that represents integers. This is used for when people do things
like &0->a.b. */
static varinfo_t var_integer;
static tree integer_tree;
- static unsigned int integer_id;
/* Lookup a heap var for FROM, and return it if we find one. */
--- 294,327 ----
return v;
}
+ /* Static IDs for the special variables. */
+ enum { nothing_id = 0, anything_id = 1, readonly_id = 2,
+ escaped_id = 3, nonlocal_id = 4, integer_id = 5 };
+
/* Variable that represents the unknown pointer. */
static varinfo_t var_anything;
static tree anything_tree;
/* Variable that represents the NULL pointer. */
static varinfo_t var_nothing;
static tree nothing_tree;
/* Variable that represents read only memory. */
static varinfo_t var_readonly;
static tree readonly_tree;
!
! /* Variable that represents escaped memory. */
! static varinfo_t var_escaped;
! static tree escaped_tree;
!
! /* Variable that represents nonlocal memory. */
! static varinfo_t var_nonlocal;
! static tree nonlocal_tree;
/* Variable that represents integers. This is used for when people do things
like &0->a.b. */
static varinfo_t var_integer;
static tree integer_tree;
/* Lookup a heap var for FROM, and return it if we find one. */
*************** update_alias_info (tree stmt, struct ali
*** 3271,3294 ****
/* Mark all the variables whose address are taken by the statement. */
addr_taken = addresses_taken (stmt);
if (addr_taken)
! {
! bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken);
!
! /* If STMT is an escape point, all the addresses taken by it are
! call-clobbered. */
! if (stmt_escape_type != NO_ESCAPE)
! {
! bitmap_iterator bi;
! unsigned i;
!
! EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
! {
! tree rvar = referenced_var (i);
! if (!unmodifiable_var_p (rvar))
! mark_call_clobbered (rvar, stmt_escape_type);
! }
! }
! }
/* Process each operand use. For pointers, determine whether they
are dereferenced by the statement, or whether their value
--- 3279,3285 ----
/* Mark all the variables whose address are taken by the statement. */
addr_taken = addresses_taken (stmt);
if (addr_taken)
! bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken);
/* Process each operand use. For pointers, determine whether they
are dereferenced by the statement, or whether their value
*************** handle_ptr_arith (VEC (ce_s, heap) *lhsc
*** 3573,3578 ****
--- 3564,3594 ----
return true;
}
+ /* Make proper constraints of OP escaping. This includes
+ ESCAPED = op, *op = &ESCAPED. */
+
+ static void
+ make_escape_constraint (tree op)
+ {
+ VEC(ce_s, heap) *rhsc = NULL;
+ struct constraint_expr *c;
+ struct constraint_expr includesescaped;
+ struct constraint_expr escapedincludes;
+ unsigned int j;
+
+ includesescaped.var = escaped_id;
+ includesescaped.offset = 0;
+ includesescaped.type = ADDRESSOF;
+ escapedincludes.var = escaped_id;
+ escapedincludes.offset = 0;
+ escapedincludes.type = SCALAR;
+
+ get_constraint_for (op, &rhsc);
+ for (j = 0; VEC_iterate (ce_s, rhsc, j, c); j++)
+ process_constraint_1 (new_constraint (escapedincludes, *c), true);
+ VEC_free (ce_s, heap, rhsc);
+ }
+
/* For non-IPA mode, generate constraints necessary for a call on the
RHS. */
*************** handle_rhs_call (tree rhs)
*** 3581,3615 ****
{
tree arg;
call_expr_arg_iterator iter;
- struct constraint_expr rhsc;
-
- rhsc.var = anything_id;
- rhsc.offset = 0;
- rhsc.type = ADDRESSOF;
FOR_EACH_CALL_EXPR_ARG (arg, iter, rhs)
! {
! VEC(ce_s, heap) *lhsc = NULL;
!
! /* Find those pointers being passed, and make sure they end up
! pointing to anything. */
! if (POINTER_TYPE_P (TREE_TYPE (arg)))
! {
! unsigned int j;
! struct constraint_expr *lhsp;
!
! get_constraint_for (arg, &lhsc);
! do_deref (&lhsc);
! for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
! process_constraint_1 (new_constraint (*lhsp, rhsc), true);
! VEC_free (ce_s, heap, lhsc);
! }
! }
}
/* For non-IPA mode, generate constraints necessary for a call
that returns a pointer and assigns it to LHS. This simply makes
! the LHS point to anything. */
static void
handle_lhs_call (tree lhs)
--- 3597,3617 ----
{
tree arg;
call_expr_arg_iterator iter;
FOR_EACH_CALL_EXPR_ARG (arg, iter, rhs)
! /* Find those pointers being passed, and make sure they end up
! pointing to anything. */
! if (could_have_pointers (arg))
! make_escape_constraint (arg);
!
! /* The static chain escapes as well. */
! if (CALL_EXPR_STATIC_CHAIN (rhs))
! make_escape_constraint (CALL_EXPR_STATIC_CHAIN (rhs));
}
/* For non-IPA mode, generate constraints necessary for a call
that returns a pointer and assigns it to LHS. This simply makes
! the LHS point to global and escaped variables. */
static void
handle_lhs_call (tree lhs)
*************** handle_lhs_call (tree lhs)
*** 3619,3630 ****
unsigned int j;
struct constraint_expr *lhsp;
! rhsc.var = anything_id;
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
get_constraint_for (lhs, &lhsc);
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint_1 (new_constraint (*lhsp, rhsc), true);
VEC_free (ce_s, heap, lhsc);
}
--- 3621,3690 ----
unsigned int j;
struct constraint_expr *lhsp;
! get_constraint_for (lhs, &lhsc);
! rhsc.var = nonlocal_id;
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
+ for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+ process_constraint_1 (new_constraint (*lhsp, rhsc), true);
+ rhsc.var = escaped_id;
+ rhsc.offset = 0;
+ rhsc.type = ADDRESSOF;
+ for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+ process_constraint_1 (new_constraint (*lhsp, rhsc), true);
+ VEC_free (ce_s, heap, lhsc);
+ }
+
+ /* For non-IPA mode, generate constraints necessary for a call of a
+ const function that returns a pointer in the statement STMT. */
+
+ static void
+ handle_const_call (tree stmt)
+ {
+ tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+ tree call = get_call_expr_in (stmt);
+ VEC(ce_s, heap) *lhsc = NULL;
+ struct constraint_expr rhsc;
+ unsigned int j;
+ struct constraint_expr *lhsp;
+ tree arg;
+ call_expr_arg_iterator iter;
+
get_constraint_for (lhs, &lhsc);
+
+ /* If this is a nested function then it can return anything. */
+ if (CALL_EXPR_STATIC_CHAIN (call))
+ {
+ rhsc.var = anything_id;
+ rhsc.offset = 0;
+ rhsc.type = ADDRESSOF;
+ for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+ process_constraint_1 (new_constraint (*lhsp, rhsc), true);
+ VEC_free (ce_s, heap, lhsc);
+ return;
+ }
+
+ /* May return addresses of globals. */
+ rhsc.var = nonlocal_id;
+ rhsc.offset = 0;
+ rhsc.type = ADDRESSOF;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint_1 (new_constraint (*lhsp, rhsc), true);
+
+ /* May return arguments. */
+ FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
+ if (could_have_pointers (arg))
+ {
+ VEC(ce_s, heap) *argc = NULL;
+ struct constraint_expr *argp;
+ int i;
+ get_constraint_for (arg, &argc);
+ for (i = 0; VEC_iterate (ce_s, argc, i, argp); i++)
+ for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+ process_constraint_1 (new_constraint (*lhsp, *argp), true);
+ VEC_free (ce_s, heap, argc);
+ }
+
VEC_free (ce_s, heap, lhsc);
}
*************** handle_lhs_call (tree lhs)
*** 3636,3645 ****
static void
find_func_aliases (tree origt)
{
! tree t = origt;
VEC(ce_s, heap) *lhsc = NULL;
VEC(ce_s, heap) *rhsc = NULL;
struct constraint_expr *c;
if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0))
t = TREE_OPERAND (t, 0);
--- 3696,3707 ----
static void
find_func_aliases (tree origt)
{
! tree call, t = origt;
VEC(ce_s, heap) *lhsc = NULL;
VEC(ce_s, heap) *rhsc = NULL;
struct constraint_expr *c;
+ enum escape_type stmt_escape_type;
+ int flags;
if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0))
t = TREE_OPERAND (t, 0);
*************** find_func_aliases (tree origt)
*** 3688,3704 ****
In non-ipa mode, we need to generate constraints for each
pointer passed by address. */
! else if (((TREE_CODE (t) == GIMPLE_MODIFY_STMT
! && TREE_CODE (GIMPLE_STMT_OPERAND (t, 1)) == CALL_EXPR
! && !(call_expr_flags (GIMPLE_STMT_OPERAND (t, 1))
! & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
! || (TREE_CODE (t) == CALL_EXPR
! && !(call_expr_flags (t)
! & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))))
{
if (!in_ipa_mode)
{
! if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
{
handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1));
if (could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
--- 3750,3775 ----
In non-ipa mode, we need to generate constraints for each
pointer passed by address. */
! else if ((call = get_call_expr_in (t)) != NULL_TREE
! && !((flags = call_expr_flags (call))
! & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
{
if (!in_ipa_mode)
{
! /* Const functions can return their arguments and addresses
! of global memory but not of escaped memory. */
! if (flags & ECF_CONST)
! {
! if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
! && could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
! handle_const_call (t);
! }
! /* Pure functions can return addresses in and of memory
! reachable from their arguments, but they are not an escape
! point for reachable memory of their arguments. But as we
! do not compute call-used memory separately we cannot do
! something special here. */
! else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
{
handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1));
if (could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
*************** find_func_aliases (tree origt)
*** 3893,3898 ****
--- 3964,4020 ----
get_varinfo (c->var)->no_tbaa_pruning = true;
}
+ stmt_escape_type = is_escape_site (t);
+ if (stmt_escape_type == ESCAPE_STORED_IN_GLOBAL)
+ {
+ tree rhs;
+ gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+ rhs = GIMPLE_STMT_OPERAND (t, 1);
+ if (TREE_CODE (rhs) == ADDR_EXPR)
+ {
+ tree base = get_base_address (TREE_OPERAND (rhs, 0));
+ if (base
+ && (!DECL_P (base)
+ || !is_global_var (base)))
+ make_escape_constraint (rhs);
+ }
+ else if (TREE_CODE (rhs) == SSA_NAME
+ && POINTER_TYPE_P (TREE_TYPE (rhs)))
+ make_escape_constraint (rhs);
+ else if (could_have_pointers (rhs))
+ make_escape_constraint (rhs);
+ }
+ else if (stmt_escape_type == ESCAPE_BAD_CAST)
+ {
+ tree rhs;
+ gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+ rhs = GIMPLE_STMT_OPERAND (t, 1);
+ gcc_assert (CONVERT_EXPR_P (rhs)
+ || TREE_CODE (rhs) == VIEW_CONVERT_EXPR);
+ rhs = TREE_OPERAND (rhs, 0);
+ make_escape_constraint (rhs);
+ }
+ else if (stmt_escape_type == ESCAPE_TO_ASM)
+ {
+ tree link;
+ int i;
+ for (i = 0, link = ASM_OUTPUTS (t); link; i++, link = TREE_CHAIN (link))
+ {
+ tree op = TREE_VALUE (link);
+ if (op && could_have_pointers (op))
+ /* Strictly we'd only need the constraints from ESCAPED and
+ NONLOCAL. */
+ make_escape_constraint (op);
+ }
+ for (i = 0, link = ASM_INPUTS (t); link; i++, link = TREE_CHAIN (link))
+ {
+ tree op = TREE_VALUE (link);
+ if (op && could_have_pointers (op))
+ /* Strictly we'd only need the constraint to ESCAPED. */
+ make_escape_constraint (op);
+ }
+ }
+
/* After promoting variables and computing aliasing we will
need to re-scan most statements. FIXME: Try to minimize the
number of statements re-scanned. It's not really necessary to
*************** push_fields_onto_fieldstack (tree type,
*** 4111,4119 ****
return count;
}
! /* Create a constraint from ANYTHING variable to VI. */
static void
! make_constraint_from_anything (varinfo_t vi)
{
struct constraint_expr lhs, rhs;
--- 4233,4241 ----
return count;
}
! /* Create a constraint from ID variable to VI. */
static void
! make_constraint_from (varinfo_t vi, int from)
{
struct constraint_expr lhs, rhs;
*************** make_constraint_from_anything (varinfo_t
*** 4121,4132 ****
lhs.offset = 0;
lhs.type = SCALAR;
! rhs.var = anything_id;
rhs.offset = 0;
rhs.type = ADDRESSOF;
process_constraint (new_constraint (lhs, rhs));
}
/* Count the number of arguments DECL has, and set IS_VARARGS to true
if it is a varargs function. */
--- 4243,4261 ----
lhs.offset = 0;
lhs.type = SCALAR;
! rhs.var = from;
rhs.offset = 0;
rhs.type = ADDRESSOF;
process_constraint (new_constraint (lhs, rhs));
}
+ /* Create a constraint from ANYTHING variable to VI. */
+ static void
+ make_constraint_from_anything (varinfo_t vi)
+ {
+ make_constraint_from (vi, anything_id);
+ }
+
/* Count the number of arguments DECL has, and set IS_VARARGS to true
if it is a varargs function. */
*************** intra_create_variable_infos (void)
*** 4471,4477 ****
struct constraint_expr lhs, rhs;
/* For each incoming pointer argument arg, create the constraint ARG
! = ANYTHING or a dummy variable if flag_argument_noalias is set. */
for (t = DECL_ARGUMENTS (current_function_decl); t; t = TREE_CHAIN (t))
{
varinfo_t p;
--- 4600,4606 ----
struct constraint_expr lhs, rhs;
/* For each incoming pointer argument arg, create the constraint ARG
! = NONLOCAL or a dummy variable if flag_argument_noalias is set. */
for (t = DECL_ARGUMENTS (current_function_decl); t; t = TREE_CHAIN (t))
{
varinfo_t p;
*************** intra_create_variable_infos (void)
*** 4532,4538 ****
varinfo_t arg_vi = get_vi_for_tree (t);
for (p = arg_vi; p; p = p->next)
! make_constraint_from_anything (p);
}
}
}
--- 4661,4667 ----
varinfo_t arg_vi = get_vi_for_tree (t);
for (p = arg_vi; p; p = p->next)
! make_constraint_from (p, nonlocal_id);
}
}
}
*************** find_what_p_points_to (tree p)
*** 4787,4793 ****
aliases. */
if (vi->id == nothing_id)
pi->pt_null = 1;
! else if (vi->id == anything_id)
was_pt_anything = 1;
else if (vi->id == readonly_id)
was_pt_anything = 1;
--- 4916,4924 ----
aliases. */
if (vi->id == nothing_id)
pi->pt_null = 1;
! else if (vi->id == anything_id
! || vi->id == nonlocal_id
! || vi->id == escaped_id)
was_pt_anything = 1;
else if (vi->id == readonly_id)
was_pt_anything = 1;
*************** find_what_p_points_to (tree p)
*** 4836,4877 ****
return false;
}
! /* Mark everything that p points to as call clobbered. Returns true
! if everything is done and false if all addressable variables need to
! be clobbered because p points to anything. */
bool
! clobber_what_p_points_to (tree p)
{
- tree lookup_p = p;
varinfo_t vi;
- struct ptr_info_def *pi;
unsigned int i;
bitmap_iterator bi;
if (!have_alias_info)
return false;
- /* For parameters, get at the points-to set for the actual parm
- decl. */
- if (TREE_CODE (p) == SSA_NAME
- && TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL
- && SSA_NAME_IS_DEFAULT_DEF (p))
- lookup_p = SSA_NAME_VAR (p);
-
- vi = lookup_vi_for_tree (lookup_p);
- if (!vi)
- return false;
-
- /* We are asking for the points-to solution of pointers. */
- gcc_assert (!vi->is_artificial_var
- && vi->size == vi->fullsize);
-
- pi = get_ptr_info (p);
-
/* This variable may have been collapsed, let's get the real
! variable. */
! vi = get_varinfo (find (vi->id));
/* Mark variables in the solution call-clobbered. */
EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
--- 4967,4989 ----
return false;
}
! /* Mark the ESCAPED solution as call clobbered. Returns false if
! pt_anything escaped which needs all locals that have their address
! taken marked call clobbered as well. */
bool
! clobber_what_escaped (void)
{
varinfo_t vi;
unsigned int i;
bitmap_iterator bi;
if (!have_alias_info)
return false;
/* This variable may have been collapsed, let's get the real
! variable for escaped_id. */
! vi = get_varinfo (find (escaped_id));
/* Mark variables in the solution call-clobbered. */
EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
*************** clobber_what_p_points_to (tree p)
*** 4896,4907 ****
|| TREE_CODE (vi->decl) == PARM_DECL
|| TREE_CODE (vi->decl) == RESULT_DECL)
&& !unmodifiable_var_p (vi->decl))
! mark_call_clobbered (vi->decl, pi->escape_mask);
}
return true;
}
/* Dump points-to information to OUTFILE. */
void
--- 5008,5020 ----
|| TREE_CODE (vi->decl) == PARM_DECL
|| TREE_CODE (vi->decl) == RESULT_DECL)
&& !unmodifiable_var_p (vi->decl))
! mark_call_clobbered (vi->decl, ESCAPE_TO_CALL);
}
return true;
}
+
/* Dump points-to information to OUTFILE. */
void
*************** init_base_vars (void)
*** 4952,4971 ****
/* Create the NULL variable, used to represent that a variable points
to NULL. */
nothing_tree = create_tmp_var_raw (void_type_node, "NULL");
! var_nothing = new_var_info (nothing_tree, 0, "NULL");
insert_vi_for_tree (nothing_tree, var_nothing);
var_nothing->is_artificial_var = 1;
var_nothing->offset = 0;
var_nothing->size = ~0;
var_nothing->fullsize = ~0;
var_nothing->is_special_var = 1;
- nothing_id = 0;
VEC_safe_push (varinfo_t, heap, varmap, var_nothing);
/* Create the ANYTHING variable, used to represent that a variable
points to some unknown piece of memory. */
anything_tree = create_tmp_var_raw (void_type_node, "ANYTHING");
! var_anything = new_var_info (anything_tree, 1, "ANYTHING");
insert_vi_for_tree (anything_tree, var_anything);
var_anything->is_artificial_var = 1;
var_anything->size = ~0;
--- 5065,5083 ----
/* Create the NULL variable, used to represent that a variable points
to NULL. */
nothing_tree = create_tmp_var_raw (void_type_node, "NULL");
! var_nothing = new_var_info (nothing_tree, nothing_id, "NULL");
insert_vi_for_tree (nothing_tree, var_nothing);
var_nothing->is_artificial_var = 1;
var_nothing->offset = 0;
var_nothing->size = ~0;
var_nothing->fullsize = ~0;
var_nothing->is_special_var = 1;
VEC_safe_push (varinfo_t, heap, varmap, var_nothing);
/* Create the ANYTHING variable, used to represent that a variable
points to some unknown piece of memory. */
anything_tree = create_tmp_var_raw (void_type_node, "ANYTHING");
! var_anything = new_var_info (anything_tree, anything_id, "ANYTHING");
insert_vi_for_tree (anything_tree, var_anything);
var_anything->is_artificial_var = 1;
var_anything->size = ~0;
*************** init_base_vars (void)
*** 4973,4979 ****
var_anything->next = NULL;
var_anything->fullsize = ~0;
var_anything->is_special_var = 1;
- anything_id = 1;
/* Anything points to anything. This makes deref constraints just
work in the presence of linked list and other p = *p type loops,
--- 5085,5090 ----
*************** init_base_vars (void)
*** 4994,5000 ****
/* Create the READONLY variable, used to represent that a variable
points to readonly memory. */
readonly_tree = create_tmp_var_raw (void_type_node, "READONLY");
! var_readonly = new_var_info (readonly_tree, 2, "READONLY");
var_readonly->is_artificial_var = 1;
var_readonly->offset = 0;
var_readonly->size = ~0;
--- 5105,5111 ----
/* Create the READONLY variable, used to represent that a variable
points to readonly memory. */
readonly_tree = create_tmp_var_raw (void_type_node, "READONLY");
! var_readonly = new_var_info (readonly_tree, readonly_id, "READONLY");
var_readonly->is_artificial_var = 1;
var_readonly->offset = 0;
var_readonly->size = ~0;
*************** init_base_vars (void)
*** 5002,5008 ****
var_readonly->next = NULL;
var_readonly->is_special_var = 1;
insert_vi_for_tree (readonly_tree, var_readonly);
- readonly_id = 2;
VEC_safe_push (varinfo_t, heap, varmap, var_readonly);
/* readonly memory points to anything, in order to make deref
--- 5113,5118 ----
*************** init_base_vars (void)
*** 5013,5027 ****
lhs.var = readonly_id;
lhs.offset = 0;
rhs.type = ADDRESSOF;
! rhs.var = anything_id;
rhs.offset = 0;
-
process_constraint (new_constraint (lhs, rhs));
/* Create the INTEGER variable, used to represent that a variable points
to an INTEGER. */
integer_tree = create_tmp_var_raw (void_type_node, "INTEGER");
! var_integer = new_var_info (integer_tree, 3, "INTEGER");
insert_vi_for_tree (integer_tree, var_integer);
var_integer->is_artificial_var = 1;
var_integer->size = ~0;
--- 5123,5170 ----
lhs.var = readonly_id;
lhs.offset = 0;
rhs.type = ADDRESSOF;
! rhs.var = readonly_id; /* FIXME */
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
+ /* Create the ESCAPED variable, used to represent the set of escaped
+ memory. */
+ escaped_tree = create_tmp_var_raw (void_type_node, "ESCAPED");
+ var_escaped = new_var_info (escaped_tree, escaped_id, "ESCAPED");
+ insert_vi_for_tree (escaped_tree, var_escaped);
+ var_escaped->is_artificial_var = 1;
+ var_escaped->offset = 0;
+ var_escaped->size = ~0;
+ var_escaped->fullsize = ~0;
+ var_escaped->is_special_var = 0;
+ VEC_safe_push (varinfo_t, heap, varmap, var_escaped);
+ gcc_assert (VEC_index (varinfo_t, varmap, 3) == var_escaped);
+
+ /* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc. */
+ lhs.type = SCALAR;
+ lhs.var = escaped_id;
+ lhs.offset = 0;
+ rhs.type = DEREF;
+ rhs.var = escaped_id;
+ rhs.offset = 0;
+ process_constraint_1 (new_constraint (lhs, rhs), true);
+
+ /* Create the NONLOCAL variable, used to represent the set of nonlocal
+ memory. */
+ nonlocal_tree = create_tmp_var_raw (void_type_node, "NONLOCAL");
+ var_nonlocal = new_var_info (nonlocal_tree, nonlocal_id, "NONLOCAL");
+ insert_vi_for_tree (nonlocal_tree, var_nonlocal);
+ var_nonlocal->is_artificial_var = 1;
+ var_nonlocal->offset = 0;
+ var_nonlocal->size = ~0;
+ var_nonlocal->fullsize = ~0;
+ var_nonlocal->is_special_var = 1;
+ VEC_safe_push (varinfo_t, heap, varmap, var_nonlocal);
+
/* Create the INTEGER variable, used to represent that a variable points
to an INTEGER. */
integer_tree = create_tmp_var_raw (void_type_node, "INTEGER");
! var_integer = new_var_info (integer_tree, integer_id, "INTEGER");
insert_vi_for_tree (integer_tree, var_integer);
var_integer->is_artificial_var = 1;
var_integer->size = ~0;
*************** init_base_vars (void)
*** 5029,5035 ****
var_integer->offset = 0;
var_integer->next = NULL;
var_integer->is_special_var = 1;
- integer_id = 3;
VEC_safe_push (varinfo_t, heap, varmap, var_integer);
/* INTEGER = ANYTHING, because we don't know where a dereference of
--- 5172,5177 ----
*************** init_base_vars (void)
*** 5041,5046 ****
--- 5183,5208 ----
rhs.var = anything_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
+
+ /* *ESCAPED = &ESCAPED. This is true because we have to assume
+ everything pointed to by escaped can also point to escaped. */
+ lhs.type = DEREF;
+ lhs.var = escaped_id;
+ lhs.offset = 0;
+ rhs.type = ADDRESSOF;
+ rhs.var = escaped_id;
+ rhs.offset = 0;
+ process_constraint_1 (new_constraint (lhs, rhs), true);
+
+ /* *ESCAPED = &NONLOCAL. This is true because we have to assume
+ everything pointed to by escaped can also point to nonlocal. */
+ lhs.type = DEREF;
+ lhs.var = escaped_id;
+ lhs.offset = 0;
+ rhs.type = ADDRESSOF;
+ rhs.var = nonlocal_id;
+ rhs.offset = 0;
+ process_constraint_1 (new_constraint (lhs, rhs), true);
}
/* Initialize things necessary to perform PTA */
Index: trunk/gcc/tree-flow.h
===================================================================
*** trunk.orig/gcc/tree-flow.h 2008-06-12 12:19:41.000000000 +0200
--- trunk/gcc/tree-flow.h 2008-06-23 14:15:15.000000000 +0200
*************** tree gimple_fold_indirect_ref (tree);
*** 1173,1179 ****
/* In tree-ssa-structalias.c */
bool find_what_p_points_to (tree);
! bool clobber_what_p_points_to (tree);
/* In tree-ssa-live.c */
extern void remove_unused_locals (void);
--- 1173,1179 ----
/* In tree-ssa-structalias.c */
bool find_what_p_points_to (tree);
! bool clobber_what_escaped (void);
/* In tree-ssa-live.c */
extern void remove_unused_locals (void);
Index: trunk/gcc/tree-ssa-alias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-alias.c 2008-06-23 14:13:35.000000000 +0200
--- trunk/gcc/tree-ssa-alias.c 2008-06-23 14:15:15.000000000 +0200
*************** set_initial_properties (struct alias_inf
*** 537,542 ****
--- 537,548 ----
}
}
+ if (!clobber_what_escaped ())
+ {
+ any_pt_anything = true;
+ pt_anything_mask |= ESCAPE_TO_CALL;
+ }
+
for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
{
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
*************** set_initial_properties (struct alias_inf
*** 557,574 ****
if (tag)
mark_call_clobbered (tag, pi->escape_mask);
-
- /* Defer to points-to analysis if possible, otherwise
- clobber all addressable variables. Parameters cannot
- point to local memory though.
- ??? Properly tracking which pointers point to non-local
- memory only would make a big difference here. */
- if (!clobber_what_p_points_to (ptr)
- && !(pi->escape_mask & ESCAPE_IS_PARM))
- {
- any_pt_anything = true;
- pt_anything_mask |= pi->escape_mask;
- }
}
/* If the name tag is call clobbered, so is the symbol tag
--- 563,568 ----
*************** is_escape_site (tree stmt)
*** 2906,2911 ****
--- 2900,2911 ----
if (TREE_CODE (lhs) == SSA_NAME)
return NO_ESCAPE;
+ /* If the LHS is a non-global decl, it isn't a non-local memory store.
+ If the LHS escapes, the RHS escape is dealt with in the PTA solver. */
+ if (DECL_P (lhs)
+ && !is_global_var (lhs))
+ return NO_ESCAPE;
+
/* FIXME: LHS is not an SSA_NAME. Even if it's an assignment to a
local variables we cannot be sure if it will escape, because we
don't have information about objects not in SSA form. Need to
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-1.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-1.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,35 ----
+ /* { dg-do run } */
+ /* { dg-options "-fno-tree-sra" } */
+
+ extern void abort (void);
+ struct Bar {
+ struct Foo {
+ int *p;
+ } x;
+ int *q;
+ };
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo(struct Foo f)
+ {
+ *f.p = 0;
+ }
+ int main()
+ {
+ int a, b;
+ a = 0;
+ b = 1;
+ struct Bar f;
+ f.x = bar (&b);
+ f.q = &a;
+ foo(f.x);
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-2.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-2.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,37 ----
+ /* { dg-do run } */
+ /* { dg-options "-fno-tree-sra" } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ };
+ struct Bar {
+ struct Foo *x;
+ int *q;
+ };
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo(struct Foo f)
+ {
+ *f.p = 0;
+ }
+ int main()
+ {
+ int a, b;
+ a = 0;
+ b = 1;
+ struct Bar f;
+ struct Foo g = bar (&b);
+ f.x = &g;
+ f.q = &a;
+ foo(*f.x);
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-3.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-3.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,36 ----
+ /* { dg-do run } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ };
+ struct Bar {
+ struct Foo *x;
+ int *q;
+ };
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo(struct Foo f)
+ {
+ *f.p = 0;
+ }
+ int main()
+ {
+ int a, b;
+ a = 0;
+ b = 1;
+ struct Bar f;
+ struct Foo g = bar (&b);
+ f.x = &g;
+ f.q = &a;
+ foo(*f.x);
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-4.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-4.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,33 ----
+ /* { dg-do run } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ int *q;
+ };
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo(struct Foo f)
+ {
+ *f.p = 0;
+ }
+ int main()
+ {
+ int a, b;
+ a = 0;
+ b = 1;
+ struct Foo f;
+ f = bar (&b);
+ f.q = &a;
+ foo(f);
+ if (b != 0)
+ abort ();
+ return 0;
+ }
+
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-5.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-5.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,34 ----
+ /* { dg-do run } */
+ /* { dg-options "-fno-tree-sra" } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ int *q;
+ };
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo(struct Foo f)
+ {
+ *f.p = 0;
+ }
+ int main()
+ {
+ int a, b;
+ a = 0;
+ b = 1;
+ struct Foo f;
+ f = bar (&b);
+ f.q = &a;
+ foo(f);
+ if (b != 0)
+ abort ();
+ return 0;
+ }
+
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-6.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-6.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,30 ----
+ /* { dg-do run } */
+ /* { dg-options "-fno-tree-sra" } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ } x;
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo()
+ {
+ *x.p = 0;
+ }
+ int main()
+ {
+ int b;
+ b = 1;
+ struct Foo g = bar (&b);
+ x = g;
+ foo();
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-7.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-7.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,29 ----
+ /* { dg-do run } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ } x;
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo()
+ {
+ *x.p = 0;
+ }
+ int main()
+ {
+ int b;
+ b = 1;
+ struct Foo g = bar (&b);
+ x = g;
+ foo();
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-10.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-10.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,21 ----
+ /* { dg-do run } */
+
+ typedef unsigned long uintptr_t;
+
+ void __attribute__((noinline))
+ foo(uintptr_t l)
+ {
+ int *p = (int *)l;
+ *p = 1;
+ }
+
+ extern void abort (void);
+ int main()
+ {
+ int b = 0;
+ uintptr_t l = (uintptr_t)&b;
+ foo(l);
+ if (b != 1)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-8.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-8.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,24 ----
+ /* { dg-do run } */
+ /* { dg-options "-fno-tree-sra" } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ } x;
+ void __attribute__((noinline))
+ foo()
+ {
+ *x.p = 0;
+ }
+ int main()
+ {
+ int b;
+ struct Foo g;
+ b = 1;
+ g.p = &b;
+ x = g;
+ foo();
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-9.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-9.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,23 ----
+ /* { dg-do run } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ } x;
+ void __attribute__((noinline))
+ foo()
+ {
+ *x.p = 0;
+ }
+ int main()
+ {
+ int b;
+ struct Foo g;
+ b = 1;
+ g.p = &b;
+ x = g;
+ foo();
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36400.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36400.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,16 ----
+ /* { dg-do compile } */
+
+ struct barstruct { char const* some_string; };
+
+ void changethepointer(struct barstruct***);
+
+ void baz()
+ {
+ struct barstruct bar1;
+ struct barstruct* barptr = &bar1;
+ struct barstruct** barptr2 = &barptr;
+ changethepointer(&barptr2);
+ barptr->some_string = "Everything OK";
+ }
+
+ /* { dg-final { scan-assembler "Everything OK" } } */
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c
===================================================================
*** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c 2008-06-10 13:38:41.000000000 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c 2008-06-23 14:15:15.000000000 +0200
*************** rewrite_add_phi_arguments (basic_block b
*** 93,97 ****
get_reaching_def ((get_def_from_ptr (get_phi_result_ptr (phi)))->ssa_name.var);
}
}
! /* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" { xfail *-*-* } } } */
/* { dg-final { cleanup-tree-dump "pre" } } */
--- 93,97 ----
get_reaching_def ((get_def_from_ptr (get_phi_result_ptr (phi)))->ssa_name.var);
}
}
! /* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" } } */
/* { dg-final { cleanup-tree-dump "pre" } } */
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/pr24287-2.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/pr24287-2.c 2008-06-23 14:15:15.000000000 +0200
***************
*** 0 ****
--- 1,25 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -fdump-tree-optimized" } */
+ int g1(int);
+ int h(int *a, int *b)__attribute__((const));
+ void link_error();
+
+ /* The calls to link_error should be eliminated, since nothing escapes to
+ non-const functions. */
+ int g(void)
+ {
+ int t = 0, t1 = 2;
+ int t2 = h(&t, &t1);
+ if (t != 0)
+ link_error ();
+ if (t1 != 2)
+ link_error ();
+ g1(t2);
+ if (t != 0)
+ link_error ();
+ if (t1 != 2)
+ link_error ();
+ return t2 == 2;
+ }
+ /* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */
+ /* { dg-final { cleanup-tree-dump "optimized" } } */
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c
===================================================================
*** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c 2008-06-23 15:43:26.000000000 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c 2008-06-23 15:43:40.000000000 +0200
*************** int g(void)
*** 21,25 ****
link_error ();
return t2 == 2;
}
! /* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
--- 21,25 ----
link_error ();
return t2 == 2;
}
! /* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Re-do call-clobber computation, track non-local pt sets, fix PRs 36400, 36373 and 36344
2008-06-23 14:05 [PATCH] Re-do call-clobber computation, track non-local pt sets, fix PRs 36400, 36373 and 36344 Richard Guenther
@ 2008-06-27 19:05 ` Richard Guenther
2008-06-28 11:08 ` Andreas Schwab
0 siblings, 1 reply; 5+ messages in thread
From: Richard Guenther @ 2008-06-27 19:05 UTC (permalink / raw)
To: gcc-patches; +Cc: Daniel Berlin, Diego Novillo
On Mon, 23 Jun 2008, Richard Guenther wrote:
>
> This fixes a bunch of wrong-code bugs with respect to not accounting for
> escapes of aggregates for call-clobber computation. It ends up
> re-writing call clobber computation in terms of PTA. For this not to
> loose too much precision I re-added the ability of PTA to track non-local
> points-to sets.
>
> The patch is already quite big, so I left the following for followups:
>
> - remove most of the old call clobber computation code, get rid of
> SMTs during this.
> - track call-used variables separately (this will fix the XFAIL of
> pr24287.c)
> - some code movement and proper fixing of the PTA alias-warning code
>
> The code idea of this patch should be applicable to the 4.3 branch as
> well, I'll try to prepare a version for the branch at some point.
>
> I tested compile-time performance of this patch on the usual PTA
> time-hogs (especially those from 4.2, where we had a similar
> mechanism), and compile-time is basically unchanged.
>
> Bootstrapped and tested on x86_64-unknown-linux-gnu - ok for trunk?
Danny approved this on IRC. The following is what I committed after
re-bootstrapping and testing on x86_64 - it contains one fix and
the optimization Danny suggested earlier (tread ESCAPED as placeholder
during propagation).
Richard.
2008-06-23 Richard Guenther <rguenther@suse.de>
PR tree-optimization/36400
PR tree-optimization/36373
PR tree-optimization/36344
* tree-ssa-structalias.c (var_escaped, escaped_tree, escaped_id,
var_nonlocal, nonlocal_tree, nonlocal_id): New globals
(update_alias_info): Remove call clobbering code.
(make_constraint_to): New helper function.
(make_escape_constraint): Likewise.
(handle_rhs_call): Use it on all pointer containing arguments.
Also mark the static chain escaped.
(handle_lhs_call): Make constraints from NONLOCAL and ESCAPED
instead of ANYTHING.
(make_constraint_from): New helper split out from ...
(make_constraint_from_anything): ... here.
(find_func_aliases): Add constraints for escape sites.
(intra_create_variable_infos): Make constraints from NONLOCAL
for parameters.
(find_what_p_points_to): Interpret NONLOCAL and ESCAPED the same
as ANYTHING.
(clobber_what_p_points_to): Remove.
(clobber_what_escaped): New function.
(init_base_vars): Init NONLOCAL and ESCAPED.
(do_sd_constraint): Do not propagate the solution from ESCAPED
but use ESCAPED as a placeholder.
(solve_graph): Likewise.
* tree-flow.h (clobber_what_p_points_to): Remove.
(clobber_what_escaped): Declare.
* tree-ssa-alias.c (set_initial_properties): Call it.
Remove code clobbering escaped pointers.
* gcc.dg/torture/pr36373-1.c: New testcase.
* gcc.dg/torture/pr36373-2.c: Likewise.
* gcc.dg/torture/pr36373-3.c: Likewise.
* gcc.dg/torture/pr36373-4.c: Likewise.
* gcc.dg/torture/pr36373-5.c: Likewise.
* gcc.dg/torture/pr36373-6.c: Likewise.
* gcc.dg/torture/pr36373-7.c: Likewise.
* gcc.dg/torture/pr36373-8.c: Likewise.
* gcc.dg/torture/pr36373-9.c: Likewise.
* gcc.dg/torture/pr36373-10.c: Likewise.
* gcc.dg/torture/pr36400.c: Likewise.
* gcc.c-torture/execute/pta-field-1.c: Likewise.
* gcc.c-torture/execute/pta-field-2.c: Likewise.
* gcc.dg/tree-ssa/loadpre8.c: Remove XFAIL.
* gcc.dg/tree-ssa/pr24287.c: XFAIL.
Index: trunk/gcc/tree-ssa-structalias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-structalias.c 2008-06-25 13:12:30.000000000 +0200
--- trunk/gcc/tree-ssa-structalias.c 2008-06-27 16:58:22.000000000 +0200
*************** get_varinfo_fc (unsigned int n)
*** 294,319 ****
return v;
}
/* Variable that represents the unknown pointer. */
static varinfo_t var_anything;
static tree anything_tree;
- static unsigned int anything_id;
/* Variable that represents the NULL pointer. */
static varinfo_t var_nothing;
static tree nothing_tree;
- static unsigned int nothing_id;
/* Variable that represents read only memory. */
static varinfo_t var_readonly;
static tree readonly_tree;
! static unsigned int readonly_id;
/* Variable that represents integers. This is used for when people do things
like &0->a.b. */
static varinfo_t var_integer;
static tree integer_tree;
- static unsigned int integer_id;
/* Lookup a heap var for FROM, and return it if we find one. */
--- 294,327 ----
return v;
}
+ /* Static IDs for the special variables. */
+ enum { nothing_id = 0, anything_id = 1, readonly_id = 2,
+ escaped_id = 3, nonlocal_id = 4, integer_id = 5 };
+
/* Variable that represents the unknown pointer. */
static varinfo_t var_anything;
static tree anything_tree;
/* Variable that represents the NULL pointer. */
static varinfo_t var_nothing;
static tree nothing_tree;
/* Variable that represents read only memory. */
static varinfo_t var_readonly;
static tree readonly_tree;
!
! /* Variable that represents escaped memory. */
! static varinfo_t var_escaped;
! static tree escaped_tree;
!
! /* Variable that represents nonlocal memory. */
! static varinfo_t var_nonlocal;
! static tree nonlocal_tree;
/* Variable that represents integers. This is used for when people do things
like &0->a.b. */
static varinfo_t var_integer;
static tree integer_tree;
/* Lookup a heap var for FROM, and return it if we find one. */
*************** do_sd_constraint (constraint_graph_t gra
*** 1399,1404 ****
--- 1407,1413 ----
bitmap_set_bit (sol, anything_id);
goto done;
}
+
/* For each variable j in delta (Sol(y)), add
an edge in the graph from j to x, and union Sol(j) into Sol(x). */
EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
*************** do_sd_constraint (constraint_graph_t gra
*** 1417,1424 ****
/* Adding edges from the special vars is pointless.
They don't have sets that can change. */
! if (get_varinfo (t) ->is_special_var)
flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
else if (add_graph_edge (graph, lhs, t))
flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
}
--- 1426,1441 ----
/* Adding edges from the special vars is pointless.
They don't have sets that can change. */
! if (get_varinfo (t)->is_special_var)
flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
+ /* Merging the solution from ESCAPED needlessly increases
+ the set. Use ESCAPED as representative instead. */
+ else if (get_varinfo (t)->id == escaped_id
+ && !bitmap_bit_p (sol, get_varinfo (t)->id))
+ {
+ bitmap_set_bit (sol, escaped_id);
+ flag = true;
+ }
else if (add_graph_edge (graph, lhs, t))
flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
}
*************** solve_graph (constraint_graph_t graph)
*** 2351,2357 ****
solution_empty = bitmap_empty_p (solution);
! if (!solution_empty)
{
bitmap_iterator bi;
--- 2368,2376 ----
solution_empty = bitmap_empty_p (solution);
! if (!solution_empty
! /* Do not propagate the ESCAPED solution. */
! && i != escaped_id)
{
bitmap_iterator bi;
*************** update_alias_info (tree stmt, struct ali
*** 3271,3294 ****
/* Mark all the variables whose address are taken by the statement. */
addr_taken = addresses_taken (stmt);
if (addr_taken)
! {
! bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken);
!
! /* If STMT is an escape point, all the addresses taken by it are
! call-clobbered. */
! if (stmt_escape_type != NO_ESCAPE)
! {
! bitmap_iterator bi;
! unsigned i;
!
! EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
! {
! tree rvar = referenced_var (i);
! if (!unmodifiable_var_p (rvar))
! mark_call_clobbered (rvar, stmt_escape_type);
! }
! }
! }
/* Process each operand use. For pointers, determine whether they
are dereferenced by the statement, or whether their value
--- 3290,3296 ----
/* Mark all the variables whose address are taken by the statement. */
addr_taken = addresses_taken (stmt);
if (addr_taken)
! bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken);
/* Process each operand use. For pointers, determine whether they
are dereferenced by the statement, or whether their value
*************** handle_ptr_arith (VEC (ce_s, heap) *lhsc
*** 3573,3578 ****
--- 3575,3608 ----
return true;
}
+ /* Create a constraint ID = OP. */
+
+ static void
+ make_constraint_to (unsigned id, tree op)
+ {
+ VEC(ce_s, heap) *rhsc = NULL;
+ struct constraint_expr *c;
+ struct constraint_expr includes;
+ unsigned int j;
+
+ includes.var = id;
+ includes.offset = 0;
+ includes.type = SCALAR;
+
+ get_constraint_for (op, &rhsc);
+ for (j = 0; VEC_iterate (ce_s, rhsc, j, c); j++)
+ process_constraint_1 (new_constraint (includes, *c), true);
+ VEC_free (ce_s, heap, rhsc);
+ }
+
+ /* Make constraints necessary to make OP escape. */
+
+ static void
+ make_escape_constraint (tree op)
+ {
+ make_constraint_to (escaped_id, op);
+ }
+
/* For non-IPA mode, generate constraints necessary for a call on the
RHS. */
*************** handle_rhs_call (tree rhs)
*** 3581,3615 ****
{
tree arg;
call_expr_arg_iterator iter;
- struct constraint_expr rhsc;
-
- rhsc.var = anything_id;
- rhsc.offset = 0;
- rhsc.type = ADDRESSOF;
FOR_EACH_CALL_EXPR_ARG (arg, iter, rhs)
! {
! VEC(ce_s, heap) *lhsc = NULL;
!
! /* Find those pointers being passed, and make sure they end up
! pointing to anything. */
! if (POINTER_TYPE_P (TREE_TYPE (arg)))
! {
! unsigned int j;
! struct constraint_expr *lhsp;
!
! get_constraint_for (arg, &lhsc);
! do_deref (&lhsc);
! for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
! process_constraint_1 (new_constraint (*lhsp, rhsc), true);
! VEC_free (ce_s, heap, lhsc);
! }
! }
}
/* For non-IPA mode, generate constraints necessary for a call
that returns a pointer and assigns it to LHS. This simply makes
! the LHS point to anything. */
static void
handle_lhs_call (tree lhs)
--- 3611,3631 ----
{
tree arg;
call_expr_arg_iterator iter;
FOR_EACH_CALL_EXPR_ARG (arg, iter, rhs)
! /* Find those pointers being passed, and make sure they end up
! pointing to anything. */
! if (could_have_pointers (arg))
! make_escape_constraint (arg);
!
! /* The static chain escapes as well. */
! if (CALL_EXPR_STATIC_CHAIN (rhs))
! make_escape_constraint (CALL_EXPR_STATIC_CHAIN (rhs));
}
/* For non-IPA mode, generate constraints necessary for a call
that returns a pointer and assigns it to LHS. This simply makes
! the LHS point to global and escaped variables. */
static void
handle_lhs_call (tree lhs)
*************** handle_lhs_call (tree lhs)
*** 3619,3630 ****
unsigned int j;
struct constraint_expr *lhsp;
! rhsc.var = anything_id;
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
get_constraint_for (lhs, &lhsc);
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint_1 (new_constraint (*lhsp, rhsc), true);
VEC_free (ce_s, heap, lhsc);
}
--- 3635,3704 ----
unsigned int j;
struct constraint_expr *lhsp;
! get_constraint_for (lhs, &lhsc);
! rhsc.var = nonlocal_id;
! rhsc.offset = 0;
! rhsc.type = ADDRESSOF;
! for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
! process_constraint_1 (new_constraint (*lhsp, rhsc), true);
! rhsc.var = escaped_id;
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
+ for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+ process_constraint_1 (new_constraint (*lhsp, rhsc), true);
+ VEC_free (ce_s, heap, lhsc);
+ }
+
+ /* For non-IPA mode, generate constraints necessary for a call of a
+ const function that returns a pointer in the statement STMT. */
+
+ static void
+ handle_const_call (tree stmt)
+ {
+ tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+ tree call = get_call_expr_in (stmt);
+ VEC(ce_s, heap) *lhsc = NULL;
+ struct constraint_expr rhsc;
+ unsigned int j;
+ struct constraint_expr *lhsp;
+ tree arg;
+ call_expr_arg_iterator iter;
+
get_constraint_for (lhs, &lhsc);
+
+ /* If this is a nested function then it can return anything. */
+ if (CALL_EXPR_STATIC_CHAIN (call))
+ {
+ rhsc.var = anything_id;
+ rhsc.offset = 0;
+ rhsc.type = ADDRESSOF;
+ for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+ process_constraint_1 (new_constraint (*lhsp, rhsc), true);
+ VEC_free (ce_s, heap, lhsc);
+ return;
+ }
+
+ /* May return addresses of globals. */
+ rhsc.var = nonlocal_id;
+ rhsc.offset = 0;
+ rhsc.type = ADDRESSOF;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint_1 (new_constraint (*lhsp, rhsc), true);
+
+ /* May return arguments. */
+ FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
+ if (could_have_pointers (arg))
+ {
+ VEC(ce_s, heap) *argc = NULL;
+ struct constraint_expr *argp;
+ int i;
+ get_constraint_for (arg, &argc);
+ for (i = 0; VEC_iterate (ce_s, argc, i, argp); i++)
+ for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+ process_constraint_1 (new_constraint (*lhsp, *argp), true);
+ VEC_free (ce_s, heap, argc);
+ }
+
VEC_free (ce_s, heap, lhsc);
}
*************** handle_lhs_call (tree lhs)
*** 3636,3645 ****
static void
find_func_aliases (tree origt)
{
! tree t = origt;
VEC(ce_s, heap) *lhsc = NULL;
VEC(ce_s, heap) *rhsc = NULL;
struct constraint_expr *c;
if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0))
t = TREE_OPERAND (t, 0);
--- 3710,3721 ----
static void
find_func_aliases (tree origt)
{
! tree call, t = origt;
VEC(ce_s, heap) *lhsc = NULL;
VEC(ce_s, heap) *rhsc = NULL;
struct constraint_expr *c;
+ enum escape_type stmt_escape_type;
+ int flags;
if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0))
t = TREE_OPERAND (t, 0);
*************** find_func_aliases (tree origt)
*** 3688,3704 ****
In non-ipa mode, we need to generate constraints for each
pointer passed by address. */
! else if (((TREE_CODE (t) == GIMPLE_MODIFY_STMT
! && TREE_CODE (GIMPLE_STMT_OPERAND (t, 1)) == CALL_EXPR
! && !(call_expr_flags (GIMPLE_STMT_OPERAND (t, 1))
! & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
! || (TREE_CODE (t) == CALL_EXPR
! && !(call_expr_flags (t)
! & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))))
{
if (!in_ipa_mode)
{
! if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
{
handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1));
if (could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
--- 3764,3789 ----
In non-ipa mode, we need to generate constraints for each
pointer passed by address. */
! else if ((call = get_call_expr_in (t)) != NULL_TREE
! && !((flags = call_expr_flags (call))
! & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
{
if (!in_ipa_mode)
{
! /* Const functions can return their arguments and addresses
! of global memory but not of escaped memory. */
! if (flags & ECF_CONST)
! {
! if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
! && could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
! handle_const_call (t);
! }
! /* Pure functions can return addresses in and of memory
! reachable from their arguments, but they are not an escape
! point for reachable memory of their arguments. But as we
! do not compute call-used memory separately we cannot do
! something special here. */
! else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
{
handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1));
if (could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
*************** find_func_aliases (tree origt)
*** 3893,3898 ****
--- 3978,4034 ----
get_varinfo (c->var)->no_tbaa_pruning = true;
}
+ stmt_escape_type = is_escape_site (t);
+ if (stmt_escape_type == ESCAPE_STORED_IN_GLOBAL)
+ {
+ tree rhs;
+ gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+ rhs = GIMPLE_STMT_OPERAND (t, 1);
+ if (TREE_CODE (rhs) == ADDR_EXPR)
+ {
+ tree base = get_base_address (TREE_OPERAND (rhs, 0));
+ if (base
+ && (!DECL_P (base)
+ || !is_global_var (base)))
+ make_escape_constraint (rhs);
+ }
+ else if (TREE_CODE (rhs) == SSA_NAME
+ && POINTER_TYPE_P (TREE_TYPE (rhs)))
+ make_escape_constraint (rhs);
+ else if (could_have_pointers (rhs))
+ make_escape_constraint (rhs);
+ }
+ else if (stmt_escape_type == ESCAPE_BAD_CAST)
+ {
+ tree rhs;
+ gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+ rhs = GIMPLE_STMT_OPERAND (t, 1);
+ gcc_assert (CONVERT_EXPR_P (rhs)
+ || TREE_CODE (rhs) == VIEW_CONVERT_EXPR);
+ rhs = TREE_OPERAND (rhs, 0);
+ make_escape_constraint (rhs);
+ }
+ else if (stmt_escape_type == ESCAPE_TO_ASM)
+ {
+ tree link;
+ int i;
+ for (i = 0, link = ASM_OUTPUTS (t); link; i++, link = TREE_CHAIN (link))
+ {
+ tree op = TREE_VALUE (link);
+ if (op && could_have_pointers (op))
+ /* Strictly we'd only need the constraints from ESCAPED and
+ NONLOCAL. */
+ make_escape_constraint (op);
+ }
+ for (i = 0, link = ASM_INPUTS (t); link; i++, link = TREE_CHAIN (link))
+ {
+ tree op = TREE_VALUE (link);
+ if (op && could_have_pointers (op))
+ /* Strictly we'd only need the constraint to ESCAPED. */
+ make_escape_constraint (op);
+ }
+ }
+
/* After promoting variables and computing aliasing we will
need to re-scan most statements. FIXME: Try to minimize the
number of statements re-scanned. It's not really necessary to
*************** push_fields_onto_fieldstack (tree type,
*** 4117,4125 ****
return count;
}
! /* Create a constraint from ANYTHING variable to VI. */
static void
! make_constraint_from_anything (varinfo_t vi)
{
struct constraint_expr lhs, rhs;
--- 4253,4262 ----
return count;
}
! /* Create a constraint ID = &FROM. */
!
static void
! make_constraint_from (varinfo_t vi, int from)
{
struct constraint_expr lhs, rhs;
*************** make_constraint_from_anything (varinfo_t
*** 4127,4138 ****
lhs.offset = 0;
lhs.type = SCALAR;
! rhs.var = anything_id;
rhs.offset = 0;
rhs.type = ADDRESSOF;
process_constraint (new_constraint (lhs, rhs));
}
/* Count the number of arguments DECL has, and set IS_VARARGS to true
if it is a varargs function. */
--- 4264,4282 ----
lhs.offset = 0;
lhs.type = SCALAR;
! rhs.var = from;
rhs.offset = 0;
rhs.type = ADDRESSOF;
process_constraint (new_constraint (lhs, rhs));
}
+ /* Create a constraint from ANYTHING variable to VI. */
+ static void
+ make_constraint_from_anything (varinfo_t vi)
+ {
+ make_constraint_from (vi, anything_id);
+ }
+
/* Count the number of arguments DECL has, and set IS_VARARGS to true
if it is a varargs function. */
*************** intra_create_variable_infos (void)
*** 4477,4483 ****
struct constraint_expr lhs, rhs;
/* For each incoming pointer argument arg, create the constraint ARG
! = ANYTHING or a dummy variable if flag_argument_noalias is set. */
for (t = DECL_ARGUMENTS (current_function_decl); t; t = TREE_CHAIN (t))
{
varinfo_t p;
--- 4621,4627 ----
struct constraint_expr lhs, rhs;
/* For each incoming pointer argument arg, create the constraint ARG
! = NONLOCAL or a dummy variable if flag_argument_noalias is set. */
for (t = DECL_ARGUMENTS (current_function_decl); t; t = TREE_CHAIN (t))
{
varinfo_t p;
*************** intra_create_variable_infos (void)
*** 4538,4544 ****
varinfo_t arg_vi = get_vi_for_tree (t);
for (p = arg_vi; p; p = p->next)
! make_constraint_from_anything (p);
}
}
}
--- 4682,4688 ----
varinfo_t arg_vi = get_vi_for_tree (t);
for (p = arg_vi; p; p = p->next)
! make_constraint_from (p, nonlocal_id);
}
}
}
*************** find_what_p_points_to (tree p)
*** 4793,4799 ****
aliases. */
if (vi->id == nothing_id)
pi->pt_null = 1;
! else if (vi->id == anything_id)
was_pt_anything = 1;
else if (vi->id == readonly_id)
was_pt_anything = 1;
--- 4937,4945 ----
aliases. */
if (vi->id == nothing_id)
pi->pt_null = 1;
! else if (vi->id == anything_id
! || vi->id == nonlocal_id
! || vi->id == escaped_id)
was_pt_anything = 1;
else if (vi->id == readonly_id)
was_pt_anything = 1;
*************** find_what_p_points_to (tree p)
*** 4842,4883 ****
return false;
}
! /* Mark everything that p points to as call clobbered. Returns true
! if everything is done and false if all addressable variables need to
! be clobbered because p points to anything. */
bool
! clobber_what_p_points_to (tree p)
{
- tree lookup_p = p;
varinfo_t vi;
- struct ptr_info_def *pi;
unsigned int i;
bitmap_iterator bi;
if (!have_alias_info)
return false;
- /* For parameters, get at the points-to set for the actual parm
- decl. */
- if (TREE_CODE (p) == SSA_NAME
- && TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL
- && SSA_NAME_IS_DEFAULT_DEF (p))
- lookup_p = SSA_NAME_VAR (p);
-
- vi = lookup_vi_for_tree (lookup_p);
- if (!vi)
- return false;
-
- /* We are asking for the points-to solution of pointers. */
- gcc_assert (!vi->is_artificial_var
- && vi->size == vi->fullsize);
-
- pi = get_ptr_info (p);
-
/* This variable may have been collapsed, let's get the real
! variable. */
! vi = get_varinfo (find (vi->id));
/* Mark variables in the solution call-clobbered. */
EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
--- 4988,5010 ----
return false;
}
! /* Mark the ESCAPED solution as call clobbered. Returns false if
! pt_anything escaped which needs all locals that have their address
! taken marked call clobbered as well. */
bool
! clobber_what_escaped (void)
{
varinfo_t vi;
unsigned int i;
bitmap_iterator bi;
if (!have_alias_info)
return false;
/* This variable may have been collapsed, let's get the real
! variable for escaped_id. */
! vi = get_varinfo (find (escaped_id));
/* Mark variables in the solution call-clobbered. */
EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
*************** clobber_what_p_points_to (tree p)
*** 4902,4913 ****
|| TREE_CODE (vi->decl) == PARM_DECL
|| TREE_CODE (vi->decl) == RESULT_DECL)
&& !unmodifiable_var_p (vi->decl))
! mark_call_clobbered (vi->decl, pi->escape_mask);
}
return true;
}
/* Dump points-to information to OUTFILE. */
void
--- 5029,5041 ----
|| TREE_CODE (vi->decl) == PARM_DECL
|| TREE_CODE (vi->decl) == RESULT_DECL)
&& !unmodifiable_var_p (vi->decl))
! mark_call_clobbered (vi->decl, ESCAPE_TO_CALL);
}
return true;
}
+
/* Dump points-to information to OUTFILE. */
void
*************** init_base_vars (void)
*** 4958,4977 ****
/* Create the NULL variable, used to represent that a variable points
to NULL. */
nothing_tree = create_tmp_var_raw (void_type_node, "NULL");
! var_nothing = new_var_info (nothing_tree, 0, "NULL");
insert_vi_for_tree (nothing_tree, var_nothing);
var_nothing->is_artificial_var = 1;
var_nothing->offset = 0;
var_nothing->size = ~0;
var_nothing->fullsize = ~0;
var_nothing->is_special_var = 1;
- nothing_id = 0;
VEC_safe_push (varinfo_t, heap, varmap, var_nothing);
/* Create the ANYTHING variable, used to represent that a variable
points to some unknown piece of memory. */
anything_tree = create_tmp_var_raw (void_type_node, "ANYTHING");
! var_anything = new_var_info (anything_tree, 1, "ANYTHING");
insert_vi_for_tree (anything_tree, var_anything);
var_anything->is_artificial_var = 1;
var_anything->size = ~0;
--- 5086,5104 ----
/* Create the NULL variable, used to represent that a variable points
to NULL. */
nothing_tree = create_tmp_var_raw (void_type_node, "NULL");
! var_nothing = new_var_info (nothing_tree, nothing_id, "NULL");
insert_vi_for_tree (nothing_tree, var_nothing);
var_nothing->is_artificial_var = 1;
var_nothing->offset = 0;
var_nothing->size = ~0;
var_nothing->fullsize = ~0;
var_nothing->is_special_var = 1;
VEC_safe_push (varinfo_t, heap, varmap, var_nothing);
/* Create the ANYTHING variable, used to represent that a variable
points to some unknown piece of memory. */
anything_tree = create_tmp_var_raw (void_type_node, "ANYTHING");
! var_anything = new_var_info (anything_tree, anything_id, "ANYTHING");
insert_vi_for_tree (anything_tree, var_anything);
var_anything->is_artificial_var = 1;
var_anything->size = ~0;
*************** init_base_vars (void)
*** 4979,4985 ****
var_anything->next = NULL;
var_anything->fullsize = ~0;
var_anything->is_special_var = 1;
- anything_id = 1;
/* Anything points to anything. This makes deref constraints just
work in the presence of linked list and other p = *p type loops,
--- 5106,5111 ----
*************** init_base_vars (void)
*** 5000,5006 ****
/* Create the READONLY variable, used to represent that a variable
points to readonly memory. */
readonly_tree = create_tmp_var_raw (void_type_node, "READONLY");
! var_readonly = new_var_info (readonly_tree, 2, "READONLY");
var_readonly->is_artificial_var = 1;
var_readonly->offset = 0;
var_readonly->size = ~0;
--- 5126,5132 ----
/* Create the READONLY variable, used to represent that a variable
points to readonly memory. */
readonly_tree = create_tmp_var_raw (void_type_node, "READONLY");
! var_readonly = new_var_info (readonly_tree, readonly_id, "READONLY");
var_readonly->is_artificial_var = 1;
var_readonly->offset = 0;
var_readonly->size = ~0;
*************** init_base_vars (void)
*** 5008,5014 ****
var_readonly->next = NULL;
var_readonly->is_special_var = 1;
insert_vi_for_tree (readonly_tree, var_readonly);
- readonly_id = 2;
VEC_safe_push (varinfo_t, heap, varmap, var_readonly);
/* readonly memory points to anything, in order to make deref
--- 5134,5139 ----
*************** init_base_vars (void)
*** 5019,5033 ****
lhs.var = readonly_id;
lhs.offset = 0;
rhs.type = ADDRESSOF;
! rhs.var = anything_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
/* Create the INTEGER variable, used to represent that a variable points
to an INTEGER. */
integer_tree = create_tmp_var_raw (void_type_node, "INTEGER");
! var_integer = new_var_info (integer_tree, 3, "INTEGER");
insert_vi_for_tree (integer_tree, var_integer);
var_integer->is_artificial_var = 1;
var_integer->size = ~0;
--- 5144,5201 ----
lhs.var = readonly_id;
lhs.offset = 0;
rhs.type = ADDRESSOF;
! rhs.var = readonly_id; /* FIXME */
! rhs.offset = 0;
! process_constraint (new_constraint (lhs, rhs));
!
! /* Create the ESCAPED variable, used to represent the set of escaped
! memory. */
! escaped_tree = create_tmp_var_raw (void_type_node, "ESCAPED");
! var_escaped = new_var_info (escaped_tree, escaped_id, "ESCAPED");
! insert_vi_for_tree (escaped_tree, var_escaped);
! var_escaped->is_artificial_var = 1;
! var_escaped->offset = 0;
! var_escaped->size = ~0;
! var_escaped->fullsize = ~0;
! var_escaped->is_special_var = 0;
! VEC_safe_push (varinfo_t, heap, varmap, var_escaped);
! gcc_assert (VEC_index (varinfo_t, varmap, 3) == var_escaped);
!
! /* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc. */
! lhs.type = SCALAR;
! lhs.var = escaped_id;
! lhs.offset = 0;
! rhs.type = DEREF;
! rhs.var = escaped_id;
rhs.offset = 0;
+ process_constraint_1 (new_constraint (lhs, rhs), true);
+
+ /* Create the NONLOCAL variable, used to represent the set of nonlocal
+ memory. */
+ nonlocal_tree = create_tmp_var_raw (void_type_node, "NONLOCAL");
+ var_nonlocal = new_var_info (nonlocal_tree, nonlocal_id, "NONLOCAL");
+ insert_vi_for_tree (nonlocal_tree, var_nonlocal);
+ var_nonlocal->is_artificial_var = 1;
+ var_nonlocal->offset = 0;
+ var_nonlocal->size = ~0;
+ var_nonlocal->fullsize = ~0;
+ var_nonlocal->is_special_var = 1;
+ VEC_safe_push (varinfo_t, heap, varmap, var_nonlocal);
+ /* Nonlocal memory points to escaped (which includes nonlocal),
+ in order to make deref easier. */
+ lhs.type = SCALAR;
+ lhs.var = nonlocal_id;
+ lhs.offset = 0;
+ rhs.type = ADDRESSOF;
+ rhs.var = escaped_id;
+ rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
/* Create the INTEGER variable, used to represent that a variable points
to an INTEGER. */
integer_tree = create_tmp_var_raw (void_type_node, "INTEGER");
! var_integer = new_var_info (integer_tree, integer_id, "INTEGER");
insert_vi_for_tree (integer_tree, var_integer);
var_integer->is_artificial_var = 1;
var_integer->size = ~0;
*************** init_base_vars (void)
*** 5035,5041 ****
var_integer->offset = 0;
var_integer->next = NULL;
var_integer->is_special_var = 1;
- integer_id = 3;
VEC_safe_push (varinfo_t, heap, varmap, var_integer);
/* INTEGER = ANYTHING, because we don't know where a dereference of
--- 5203,5208 ----
*************** init_base_vars (void)
*** 5047,5052 ****
--- 5214,5239 ----
rhs.var = anything_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
+
+ /* *ESCAPED = &ESCAPED. This is true because we have to assume
+ everything pointed to by escaped can also point to escaped. */
+ lhs.type = DEREF;
+ lhs.var = escaped_id;
+ lhs.offset = 0;
+ rhs.type = ADDRESSOF;
+ rhs.var = escaped_id;
+ rhs.offset = 0;
+ process_constraint_1 (new_constraint (lhs, rhs), true);
+
+ /* *ESCAPED = &NONLOCAL. This is true because we have to assume
+ everything pointed to by escaped can also point to nonlocal. */
+ lhs.type = DEREF;
+ lhs.var = escaped_id;
+ lhs.offset = 0;
+ rhs.type = ADDRESSOF;
+ rhs.var = nonlocal_id;
+ rhs.offset = 0;
+ process_constraint_1 (new_constraint (lhs, rhs), true);
}
/* Initialize things necessary to perform PTA */
Index: trunk/gcc/tree-flow.h
===================================================================
*** trunk.orig/gcc/tree-flow.h 2008-06-23 15:52:50.000000000 +0200
--- trunk/gcc/tree-flow.h 2008-06-27 12:07:55.000000000 +0200
*************** tree gimple_fold_indirect_ref (tree);
*** 1173,1179 ****
/* In tree-ssa-structalias.c */
bool find_what_p_points_to (tree);
! bool clobber_what_p_points_to (tree);
/* In tree-ssa-live.c */
extern void remove_unused_locals (void);
--- 1173,1179 ----
/* In tree-ssa-structalias.c */
bool find_what_p_points_to (tree);
! bool clobber_what_escaped (void);
/* In tree-ssa-live.c */
extern void remove_unused_locals (void);
Index: trunk/gcc/tree-ssa-alias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-alias.c 2008-06-23 15:52:50.000000000 +0200
--- trunk/gcc/tree-ssa-alias.c 2008-06-27 12:07:55.000000000 +0200
*************** set_initial_properties (struct alias_inf
*** 537,542 ****
--- 537,548 ----
}
}
+ if (!clobber_what_escaped ())
+ {
+ any_pt_anything = true;
+ pt_anything_mask |= ESCAPE_TO_CALL;
+ }
+
for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
{
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
*************** set_initial_properties (struct alias_inf
*** 557,574 ****
if (tag)
mark_call_clobbered (tag, pi->escape_mask);
-
- /* Defer to points-to analysis if possible, otherwise
- clobber all addressable variables. Parameters cannot
- point to local memory though.
- ??? Properly tracking which pointers point to non-local
- memory only would make a big difference here. */
- if (!clobber_what_p_points_to (ptr)
- && !(pi->escape_mask & ESCAPE_IS_PARM))
- {
- any_pt_anything = true;
- pt_anything_mask |= pi->escape_mask;
- }
}
/* If the name tag is call clobbered, so is the symbol tag
--- 563,568 ----
*************** is_escape_site (tree stmt)
*** 2906,2911 ****
--- 2900,2911 ----
if (TREE_CODE (lhs) == SSA_NAME)
return NO_ESCAPE;
+ /* If the LHS is a non-global decl, it isn't a non-local memory store.
+ If the LHS escapes, the RHS escape is dealt with in the PTA solver. */
+ if (DECL_P (lhs)
+ && !is_global_var (lhs))
+ return NO_ESCAPE;
+
/* FIXME: LHS is not an SSA_NAME. Even if it's an assignment to a
local variables we cannot be sure if it will escape, because we
don't have information about objects not in SSA form. Need to
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-1.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-1.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,35 ----
+ /* { dg-do run } */
+ /* { dg-options "-fno-tree-sra" } */
+
+ extern void abort (void);
+ struct Bar {
+ struct Foo {
+ int *p;
+ } x;
+ int *q;
+ };
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo(struct Foo f)
+ {
+ *f.p = 0;
+ }
+ int main()
+ {
+ int a, b;
+ a = 0;
+ b = 1;
+ struct Bar f;
+ f.x = bar (&b);
+ f.q = &a;
+ foo(f.x);
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-2.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-2.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,37 ----
+ /* { dg-do run } */
+ /* { dg-options "-fno-tree-sra" } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ };
+ struct Bar {
+ struct Foo *x;
+ int *q;
+ };
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo(struct Foo f)
+ {
+ *f.p = 0;
+ }
+ int main()
+ {
+ int a, b;
+ a = 0;
+ b = 1;
+ struct Bar f;
+ struct Foo g = bar (&b);
+ f.x = &g;
+ f.q = &a;
+ foo(*f.x);
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-3.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-3.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,36 ----
+ /* { dg-do run } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ };
+ struct Bar {
+ struct Foo *x;
+ int *q;
+ };
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo(struct Foo f)
+ {
+ *f.p = 0;
+ }
+ int main()
+ {
+ int a, b;
+ a = 0;
+ b = 1;
+ struct Bar f;
+ struct Foo g = bar (&b);
+ f.x = &g;
+ f.q = &a;
+ foo(*f.x);
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-4.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-4.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,33 ----
+ /* { dg-do run } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ int *q;
+ };
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo(struct Foo f)
+ {
+ *f.p = 0;
+ }
+ int main()
+ {
+ int a, b;
+ a = 0;
+ b = 1;
+ struct Foo f;
+ f = bar (&b);
+ f.q = &a;
+ foo(f);
+ if (b != 0)
+ abort ();
+ return 0;
+ }
+
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-5.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-5.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,34 ----
+ /* { dg-do run } */
+ /* { dg-options "-fno-tree-sra" } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ int *q;
+ };
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo(struct Foo f)
+ {
+ *f.p = 0;
+ }
+ int main()
+ {
+ int a, b;
+ a = 0;
+ b = 1;
+ struct Foo f;
+ f = bar (&b);
+ f.q = &a;
+ foo(f);
+ if (b != 0)
+ abort ();
+ return 0;
+ }
+
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-6.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-6.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,30 ----
+ /* { dg-do run } */
+ /* { dg-options "-fno-tree-sra" } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ } x;
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo()
+ {
+ *x.p = 0;
+ }
+ int main()
+ {
+ int b;
+ b = 1;
+ struct Foo g = bar (&b);
+ x = g;
+ foo();
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-7.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-7.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,29 ----
+ /* { dg-do run } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ } x;
+ struct Foo __attribute__((noinline))
+ bar(int *p)
+ {
+ struct Foo f;
+ f.p = p;
+ return f;
+ }
+ void __attribute__((noinline))
+ foo()
+ {
+ *x.p = 0;
+ }
+ int main()
+ {
+ int b;
+ b = 1;
+ struct Foo g = bar (&b);
+ x = g;
+ foo();
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-10.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-10.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,21 ----
+ /* { dg-do run } */
+
+ typedef unsigned long uintptr_t;
+
+ void __attribute__((noinline))
+ foo(uintptr_t l)
+ {
+ int *p = (int *)l;
+ *p = 1;
+ }
+
+ extern void abort (void);
+ int main()
+ {
+ int b = 0;
+ uintptr_t l = (uintptr_t)&b;
+ foo(l);
+ if (b != 1)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-8.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-8.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,24 ----
+ /* { dg-do run } */
+ /* { dg-options "-fno-tree-sra" } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ } x;
+ void __attribute__((noinline))
+ foo()
+ {
+ *x.p = 0;
+ }
+ int main()
+ {
+ int b;
+ struct Foo g;
+ b = 1;
+ g.p = &b;
+ x = g;
+ foo();
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36373-9.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36373-9.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,23 ----
+ /* { dg-do run } */
+
+ extern void abort (void);
+ struct Foo {
+ int *p;
+ } x;
+ void __attribute__((noinline))
+ foo()
+ {
+ *x.p = 0;
+ }
+ int main()
+ {
+ int b;
+ struct Foo g;
+ b = 1;
+ g.p = &b;
+ x = g;
+ foo();
+ if (b != 0)
+ abort ();
+ return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/torture/pr36400.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pr36400.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,16 ----
+ /* { dg-do compile } */
+
+ struct barstruct { char const* some_string; };
+
+ void changethepointer(struct barstruct***);
+
+ void baz()
+ {
+ struct barstruct bar1;
+ struct barstruct* barptr = &bar1;
+ struct barstruct** barptr2 = &barptr;
+ changethepointer(&barptr2);
+ barptr->some_string = "Everything OK";
+ }
+
+ /* { dg-final { scan-assembler "Everything OK" } } */
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c
===================================================================
*** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c 2008-06-23 15:52:50.000000000 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c 2008-06-26 14:16:04.000000000 +0200
*************** rewrite_add_phi_arguments (basic_block b
*** 93,97 ****
get_reaching_def ((get_def_from_ptr (get_phi_result_ptr (phi)))->ssa_name.var);
}
}
! /* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" { xfail *-*-* } } } */
/* { dg-final { cleanup-tree-dump "pre" } } */
--- 93,97 ----
get_reaching_def ((get_def_from_ptr (get_phi_result_ptr (phi)))->ssa_name.var);
}
}
! /* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" } } */
/* { dg-final { cleanup-tree-dump "pre" } } */
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/pr24287-2.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/pr24287-2.c 2008-06-26 14:16:04.000000000 +0200
***************
*** 0 ****
--- 1,25 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -fdump-tree-optimized" } */
+ int g1(int);
+ int h(int *a, int *b)__attribute__((const));
+ void link_error();
+
+ /* The calls to link_error should be eliminated, since nothing escapes to
+ non-const functions. */
+ int g(void)
+ {
+ int t = 0, t1 = 2;
+ int t2 = h(&t, &t1);
+ if (t != 0)
+ link_error ();
+ if (t1 != 2)
+ link_error ();
+ g1(t2);
+ if (t != 0)
+ link_error ();
+ if (t1 != 2)
+ link_error ();
+ return t2 == 2;
+ }
+ /* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */
+ /* { dg-final { cleanup-tree-dump "optimized" } } */
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c
===================================================================
*** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c 2008-06-23 15:52:50.000000000 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c 2008-06-27 12:07:55.000000000 +0200
*************** int g(void)
*** 21,25 ****
link_error ();
return t2 == 2;
}
! /* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
--- 21,25 ----
link_error ();
return t2 == 2;
}
! /* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: trunk/gcc/testsuite/gcc.c-torture/execute/pta-field-1.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.c-torture/execute/pta-field-1.c 2008-06-27 12:08:35.000000000 +0200
***************
*** 0 ****
--- 1,28 ----
+ struct Foo {
+ int *p;
+ int *q;
+ };
+
+ void __attribute__((noinline))
+ bar (int **x)
+ {
+ struct Foo *f = (struct Foo *)x;
+ *(f->q) = 0;
+ }
+
+ int foo(void)
+ {
+ struct Foo f;
+ int i = 1, j = 2;
+ f.p = &i;
+ f.q = &j;
+ bar(&f.p);
+ return j;
+ }
+
+ extern void abort (void);
+ int main()
+ {
+ if (foo () != 0)
+ abort ();
+ }
Index: trunk/gcc/testsuite/gcc.c-torture/execute/pta-field-2.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.c-torture/execute/pta-field-2.c 2008-06-27 12:08:35.000000000 +0200
***************
*** 0 ****
--- 1,28 ----
+ struct Foo {
+ int *p;
+ int *q;
+ };
+
+ void __attribute__((noinline))
+ bar (int **x)
+ {
+ struct Foo *f = (struct Foo *)(x - 1);
+ *(f->p) = 0;
+ }
+
+ int foo(void)
+ {
+ struct Foo f;
+ int i = 1, j = 2;
+ f.p = &i;
+ f.q = &j;
+ bar(&f.q);
+ return i;
+ }
+
+ extern void abort (void);
+ int main()
+ {
+ if (foo () != 0)
+ abort ();
+ }
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Re-do call-clobber computation, track non-local pt sets, fix PRs 36400, 36373 and 36344
2008-06-27 19:05 ` Richard Guenther
@ 2008-06-28 11:08 ` Andreas Schwab
2008-06-28 11:11 ` Richard Guenther
0 siblings, 1 reply; 5+ messages in thread
From: Andreas Schwab @ 2008-06-28 11:08 UTC (permalink / raw)
To: Richard Guenther; +Cc: gcc-patches, Daniel Berlin, Diego Novillo
Richard Guenther <rguenther@suse.de> writes:
> 2008-06-23 Richard Guenther <rguenther@suse.de>
>
> PR tree-optimization/36400
> PR tree-optimization/36373
> PR tree-optimization/36344
> * tree-ssa-structalias.c (var_escaped, escaped_tree, escaped_id,
> [...]
That breaks Ada:
/tmp/cvs/gcc-20080628/Build/./gcc/xgcc -B/tmp/cvs/gcc-20080628/Build/./gcc/ -B/tmp/cvs/gcc-20080628/Build/root/ia64-suse-linux/bin/ -B/tmp/cvs/gcc-20080628/Build/root/ia64-suse-linux/lib/ -isystem /tmp/cvs/gcc-20080628/Build/root/ia64-suse-linux/include -isystem /tmp/cvs/gcc-20080628/Build/root/ia64-suse-linux/sys-include -c -g -O2 -W -Wall -gnatpg -g -O1 -fno-inline \
-fno-toplevel-reorder a-except.adb -o a-except.o
+===========================GNAT BUG DETECTED==============================+
| 4.4.0 20080628 (experimental) [trunk revision 137214] (ia64-suse-linux-gnu) GCC error:|
| in process_constraint_1, at tree-ssa-structalias.c:2568 |
| Error detected around a-exexpr.adb:128 |
Andreas.
--
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, MaxfeldstraÃe 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Re-do call-clobber computation, track non-local pt sets, fix PRs 36400, 36373 and 36344
2008-06-28 11:08 ` Andreas Schwab
@ 2008-06-28 11:11 ` Richard Guenther
2008-06-29 13:56 ` Richard Guenther
0 siblings, 1 reply; 5+ messages in thread
From: Richard Guenther @ 2008-06-28 11:11 UTC (permalink / raw)
To: Andreas Schwab; +Cc: gcc-patches, Daniel Berlin, Diego Novillo
On Sat, 28 Jun 2008, Andreas Schwab wrote:
> Richard Guenther <rguenther@suse.de> writes:
>
>> 2008-06-23 Richard Guenther <rguenther@suse.de>
>>
>> PR tree-optimization/36400
>> PR tree-optimization/36373
>> PR tree-optimization/36344
>> * tree-ssa-structalias.c (var_escaped, escaped_tree, escaped_id,
>> [...]
>
> That breaks Ada:
>
> /tmp/cvs/gcc-20080628/Build/./gcc/xgcc -B/tmp/cvs/gcc-20080628/Build/./gcc/ -B/tmp/cvs/gcc-20080628/Build/root/ia64-suse-linux/bin/ -B/tmp/cvs/gcc-20080628/Build/root/ia64-suse-linux/lib/ -isystem /tmp/cvs/gcc-20080628/Build/root/ia64-suse-linux/include -isystem /tmp/cvs/gcc-20080628/Build/root/ia64-suse-linux/sys-include -c -g -O2 -W -Wall -gnatpg -g -O1 -fno-inline \
> -fno-toplevel-reorder a-except.adb -o a-except.o
> +===========================GNAT BUG DETECTED==============================+
> | 4.4.0 20080628 (experimental) [trunk revision 137214] (ia64-suse-linux-gnu) GCC error:|
> | in process_constraint_1, at tree-ssa-structalias.c:2568 |
> | Error detected around a-exexpr.adb:128 |
I didn't see this on x86_64. I'll have a look.
Richard.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Re-do call-clobber computation, track non-local pt sets, fix PRs 36400, 36373 and 36344
2008-06-28 11:11 ` Richard Guenther
@ 2008-06-29 13:56 ` Richard Guenther
0 siblings, 0 replies; 5+ messages in thread
From: Richard Guenther @ 2008-06-29 13:56 UTC (permalink / raw)
To: Andreas Schwab; +Cc: gcc-patches, Daniel Berlin, Diego Novillo
On Sat, 28 Jun 2008, Richard Guenther wrote:
>> | 4.4.0 20080628 (experimental) [trunk revision 137214]
>> (ia64-suse-linux-gnu) GCC error:|
>> | in process_constraint_1, at tree-ssa-structalias.c:2568
>> |
>> | Error detected around a-exexpr.adb:128
>> |
>
> I didn't see this on x86_64. I'll have a look.
PR36666.
Richard.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-06-29 13:36 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-06-23 14:05 [PATCH] Re-do call-clobber computation, track non-local pt sets, fix PRs 36400, 36373 and 36344 Richard Guenther
2008-06-27 19:05 ` Richard Guenther
2008-06-28 11:08 ` Andreas Schwab
2008-06-28 11:11 ` Richard Guenther
2008-06-29 13:56 ` Richard Guenther
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).