Commit 0f8d6231 by Richard Guenther Committed by Richard Biener

re PR tree-optimization/45967 (gcc-4.5.x optimizes code with side-effects away)

2010-10-18  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/45967
	* tree-ssa-structalias.c (type_could_have_pointers): Remove.
	(could_have_pointers): Likewise.
	(handle_rhs_call, handle_const_call, handle_pure_call,
	find_func_aliases, intra_create_variable_infos): Remove calls to them.
	(struct fieldoff): Add must_have_pointers field.
	(type_must_have_pointers): New function.
	(field_must_have_pointers): Likewise.
	(push_fields_onto_fieldstack): Remove must_have_pointers_p argument.
	Adjust field merging.
	(create_function_info_for): May-have-pointers of varinfo is
	almost always true.
	(create_variable_info_for_1): Likewise.

	* gcc.dg/torture/pr45967.c: New testcase.
	* gcc.dg/ipa/ipa-pta-10.c: Adjust.
	* gcc.dg/ipa/ipa-pta-13.c: Likewise
	* gcc.dg/torture/pr39074-2.c: Likewise
	* gcc.dg/torture/pta-escape-1.c: Likewise
	* gcc.dg/torture/pta-ptrarith-1.c: Likewise
	* gcc.dg/tree-ssa/pta-callused.c: Likewise
	* gcc.dg/tree-ssa/pta-escape-1.c: Likewise
	* gcc.dg/tree-ssa/pta-escape-2.c: Likewise
	* gcc.dg/tree-ssa/pta-escape-3.c: Likewise
	* gcc.dg/tree-ssa/ssa-pre-21.c: Likewise

From-SVN: r165641
parent 1915c739
2010-10-18 Richard Guenther <rguenther@suse.de>
PR tree-optimization/45967
* tree-ssa-structalias.c (type_could_have_pointers): Remove.
(could_have_pointers): Likewise.
(handle_rhs_call, handle_const_call, handle_pure_call,
find_func_aliases, intra_create_variable_infos): Remove calls to them.
(struct fieldoff): Add must_have_pointers field.
(type_must_have_pointers): New function.
(field_must_have_pointers): Likewise.
(push_fields_onto_fieldstack): Remove must_have_pointers_p argument.
Adjust field merging.
(create_function_info_for): May-have-pointers of varinfo is
almost always true.
(create_variable_info_for_1): Likewise.
2010-10-18 Tejas Belagod <tejas.belagod@arm.com> 2010-10-18 Tejas Belagod <tejas.belagod@arm.com>
* config/arm/neon.md (neon_move_hi_quad_<mode>): Fix the order * config/arm/neon.md (neon_move_hi_quad_<mode>): Fix the order
2010-10-18 Richard Guenther <rguenther@suse.de>
PR tree-optimization/45967
* gcc.dg/torture/pr45967.c: New testcase.
* gcc.dg/ipa/ipa-pta-10.c: Adjust.
* gcc.dg/ipa/ipa-pta-13.c: Likewise
* gcc.dg/torture/pr39074-2.c: Likewise
* gcc.dg/torture/pta-escape-1.c: Likewise
* gcc.dg/torture/pta-ptrarith-1.c: Likewise
* gcc.dg/tree-ssa/pta-callused.c: Likewise
* gcc.dg/tree-ssa/pta-escape-1.c: Likewise
* gcc.dg/tree-ssa/pta-escape-2.c: Likewise
* gcc.dg/tree-ssa/pta-escape-3.c: Likewise
* gcc.dg/tree-ssa/ssa-pre-21.c: Likewise
2010-10-18 Kai Tietz <kai.tietz@onevision.com> 2010-10-18 Kai Tietz <kai.tietz@onevision.com>
* gfortran.dg/bessel_7.f90: Set xfail for mingw targets. * gfortran.dg/bessel_7.f90: Set xfail for mingw targets.
......
...@@ -26,5 +26,5 @@ int main() ...@@ -26,5 +26,5 @@ int main()
/* Verify we properly handle variadic arguments and do not let escape /* Verify we properly handle variadic arguments and do not let escape
stuff through it. */ stuff through it. */
/* { dg-final { scan-ipa-dump "ESCAPED = { }" "pta" } } */ /* { dg-final { scan-ipa-dump "ESCAPED = { ESCAPED NONLOCAL }" "pta" } } */
/* { dg-final { cleanup-ipa-dump "pta" } } */ /* { dg-final { cleanup-ipa-dump "pta" } } */
...@@ -15,6 +15,8 @@ local_address_taken (int *p) ...@@ -15,6 +15,8 @@ local_address_taken (int *p)
*p = 1; *p = 1;
} }
void *anyfn_global;
/* Even though not referenced in this TU we should have added constraints /* Even though not referenced in this TU we should have added constraints
for the initializer. */ for the initializer. */
/* { dg-final { scan-ipa-dump "ex = &local_address_taken" "pta" } } */ /* { dg-final { scan-ipa-dump "ex = &local_address_taken" "pta" } } */
...@@ -24,7 +26,7 @@ extern void link_error (void); ...@@ -24,7 +26,7 @@ extern void link_error (void);
int main() int main()
{ {
void (*anyfn)(int *) = (void (*)(int *))(__SIZE_TYPE__)x; void (*anyfn)(int *) = (void (*)(int *))(__SIZE_TYPE__)anyfn_global;
/* The following should cause local_address_taken to get &x /* The following should cause local_address_taken to get &x
as argument, but not local. We shouldn't get &x added to as argument, but not local. We shouldn't get &x added to
arbitrary special sub-vars of local_address_taken though, arbitrary special sub-vars of local_address_taken though,
...@@ -34,9 +36,13 @@ int main() ...@@ -34,9 +36,13 @@ int main()
We shouldn't get the functions sub-vars in the ESCAPED solution We shouldn't get the functions sub-vars in the ESCAPED solution
though, another missed-optimization. This also causes the functions though, another missed-optimization. This also causes the functions
uses to be messed up even further. */ uses to be messed up even further. */
/* { dg-final { scan-ipa-dump "local_address_taken.arg0 = { ESCAPED NONLOCAL y x }" "pta" } } */ /* ??? As we don't expand the ESCAPED solution we either get x printed here
/* { dg-final { scan-ipa-dump "local_address_taken.clobber = { ESCAPED NONLOCAL y x }" "pta" } } */ or not based on the phase of the moon. */
/* { dg-final { scan-ipa-dump "local_address_taken.arg0 = { ESCAPED NONLOCAL y x }" "pta" { xfail *-*-* } } } */
/* { dg-final { scan-ipa-dump "local_address_taken.clobber = { ESCAPED NONLOCAL y x }" "pta" { xfail *-*-* } } } */
/* { dg-final { scan-ipa-dump "local_address_taken.use = { }" "pta" { xfail *-*-* } } } */ /* { dg-final { scan-ipa-dump "local_address_taken.use = { }" "pta" { xfail *-*-* } } } */
/* ??? But make sure x really escaped. */
/* { dg-final { scan-ipa-dump "ESCAPED = {\[^\n\}\]* x \[^\n\}\]*}" "pta" } } */
(*anyfn) (&x); (*anyfn) (&x);
x = 0; x = 0;
local (&y); local (&y);
......
...@@ -30,5 +30,5 @@ int main() ...@@ -30,5 +30,5 @@ int main()
return 0; return 0;
} }
/* { dg-final { scan-tree-dump "y.._., points-to non-local, points-to escaped, points-to vars: { i }" "alias" } } */ /* { dg-final { scan-tree-dump "y.._., points-to vars: { i }" "alias" } } */
/* { dg-final { cleanup-tree-dump "alias" } } */ /* { dg-final { cleanup-tree-dump "alias" } } */
/* { dg-do run } */
extern void abort (void);
void __attribute__((noinline,noclone))
foo (void *p_)
{
int *p;
int i;
for (i = 0; i < sizeof(int *); ++i)
((char *)&p)[i] = ((char *)p_)[i];
*p = 1;
}
int main()
{
int i = 0;
int *p = &i;
foo (&p);
if (i != 1)
abort ();
return 0;
}
...@@ -30,5 +30,5 @@ main() ...@@ -30,5 +30,5 @@ main()
return 0; return 0;
} }
/* { dg-final { scan-tree-dump "ESCAPED = { ESCAPED NONLOCAL i }" "alias" } } */ /* { dg-final { scan-tree-dump "ESCAPED = {\[^\n\}\]* i \[^\n\}\]*}" "alias" } } */
/* { dg-final { cleanup-tree-dump "alias" } } */ /* { dg-final { cleanup-tree-dump "alias" } } */
...@@ -29,5 +29,5 @@ int main() ...@@ -29,5 +29,5 @@ int main()
return 0; return 0;
} }
/* { dg-final { scan-tree-dump "ESCAPED = { ESCAPED NONLOCAL f .* i }" "alias" } } */ /* { dg-final { scan-tree-dump "ESCAPED = {\[^\n\}\]* i f \[^\n\}\]*}" "alias" } } */
/* { dg-final { cleanup-tree-dump "alias" } } */ /* { dg-final { cleanup-tree-dump "alias" } } */
...@@ -22,6 +22,6 @@ int bar (int b) ...@@ -22,6 +22,6 @@ int bar (int b)
return *foo (&q); return *foo (&q);
} }
/* { dg-final { scan-tree-dump "CALLUSED = { f.* i q }" "alias" } } */ /* { dg-final { scan-tree-dump "CALLUSED = { ESCAPED NONLOCAL f.* i q }" "alias" } } */
/* { dg-final { cleanup-tree-dump "alias" } } */ /* { dg-final { cleanup-tree-dump "alias" } } */
...@@ -33,5 +33,5 @@ int main() ...@@ -33,5 +33,5 @@ int main()
return 0; return 0;
} }
/* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to vars: { x }" "alias" } } */ /* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to NULL, points-to vars: { x }" "alias" } } */
/* { dg-final { cleanup-tree-dump "alias" } } */ /* { dg-final { cleanup-tree-dump "alias" } } */
...@@ -34,5 +34,5 @@ int main() ...@@ -34,5 +34,5 @@ int main()
return 0; return 0;
} }
/* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to vars: { x }" "alias" } } */ /* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to NULL, points-to vars: { x }" "alias" } } */
/* { dg-final { cleanup-tree-dump "alias" } } */ /* { dg-final { cleanup-tree-dump "alias" } } */
...@@ -38,5 +38,5 @@ int main() ...@@ -38,5 +38,5 @@ int main()
return 0; return 0;
} }
/* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to vars: { x }" "alias" } } */ /* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to NULL, points-to vars: { x }" "alias" } } */
/* { dg-final { cleanup-tree-dump "alias" } } */ /* { dg-final { cleanup-tree-dump "alias" } } */
...@@ -11,5 +11,5 @@ NumSift (long *array, unsigned long k) ...@@ -11,5 +11,5 @@ NumSift (long *array, unsigned long k)
/* There should be only two loads left. */ /* There should be only two loads left. */
/* { dg-final { scan-tree-dump-times "= \\\*D" 2 "pre" } } */ /* { dg-final { scan-tree-dump-times "= \\\*D\[^\n;\]*;" 2 "pre" } } */
/* { dg-final { cleanup-tree-dump "pre" } } */ /* { dg-final { cleanup-tree-dump "pre" } } */
...@@ -2931,38 +2931,6 @@ process_constraint (constraint_t t) ...@@ -2931,38 +2931,6 @@ process_constraint (constraint_t t)
} }
} }
/* Return true if T is a type that could contain pointers. */
static bool
type_could_have_pointers (tree type)
{
if (POINTER_TYPE_P (type))
return true;
if (TREE_CODE (type) == ARRAY_TYPE)
return type_could_have_pointers (TREE_TYPE (type));
/* A function or method can consume pointers.
??? We could be more precise here. */
if (TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE)
return true;
return AGGREGATE_TYPE_P (type);
}
/* Return true if T is a variable of a type that could contain
pointers. */
static bool
could_have_pointers (tree t)
{
return (((TREE_CODE (t) == VAR_DECL
|| TREE_CODE (t) == PARM_DECL
|| TREE_CODE (t) == RESULT_DECL)
&& (TREE_PUBLIC (t) || DECL_EXTERNAL (t) || TREE_ADDRESSABLE (t)))
|| type_could_have_pointers (TREE_TYPE (t)));
}
/* Return the position, in bits, of FIELD_DECL from the beginning of its /* Return the position, in bits, of FIELD_DECL from the beginning of its
structure. */ structure. */
...@@ -3786,10 +3754,8 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results) ...@@ -3786,10 +3754,8 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results)
tree arg = gimple_call_arg (stmt, i); tree arg = gimple_call_arg (stmt, i);
int flags = gimple_call_arg_flags (stmt, i); int flags = gimple_call_arg_flags (stmt, i);
/* If the argument is not used or it does not contain pointers /* If the argument is not used we can ignore it. */
we can ignore it. */ if (flags & EAF_UNUSED)
if ((flags & EAF_UNUSED)
|| !could_have_pointers (arg))
continue; continue;
/* As we compute ESCAPED context-insensitive we do not gain /* As we compute ESCAPED context-insensitive we do not gain
...@@ -3952,17 +3918,13 @@ handle_const_call (gimple stmt, VEC(ce_s, heap) **results) ...@@ -3952,17 +3918,13 @@ handle_const_call (gimple stmt, VEC(ce_s, heap) **results)
for (k = 0; k < gimple_call_num_args (stmt); ++k) for (k = 0; k < gimple_call_num_args (stmt); ++k)
{ {
tree arg = gimple_call_arg (stmt, k); tree arg = gimple_call_arg (stmt, k);
VEC(ce_s, heap) *argc = NULL;
if (could_have_pointers (arg)) unsigned i;
{ struct constraint_expr *argp;
VEC(ce_s, heap) *argc = NULL; get_constraint_for_rhs (arg, &argc);
unsigned i; FOR_EACH_VEC_ELT (ce_s, argc, i, argp)
struct constraint_expr *argp; VEC_safe_push (ce_s, heap, *results, argp);
get_constraint_for_rhs (arg, &argc); VEC_free(ce_s, heap, argc);
FOR_EACH_VEC_ELT (ce_s, argc, i, argp)
VEC_safe_push (ce_s, heap, *results, argp);
VEC_free(ce_s, heap, argc);
}
} }
/* May return addresses of globals. */ /* May return addresses of globals. */
...@@ -3986,16 +3948,12 @@ handle_pure_call (gimple stmt, VEC(ce_s, heap) **results) ...@@ -3986,16 +3948,12 @@ handle_pure_call (gimple stmt, VEC(ce_s, heap) **results)
for (i = 0; i < gimple_call_num_args (stmt); ++i) for (i = 0; i < gimple_call_num_args (stmt); ++i)
{ {
tree arg = gimple_call_arg (stmt, i); tree arg = gimple_call_arg (stmt, i);
if (!uses)
if (could_have_pointers (arg))
{ {
if (!uses) uses = get_call_use_vi (stmt);
{ make_transitive_closure_constraints (uses);
uses = get_call_use_vi (stmt);
make_transitive_closure_constraints (uses);
}
make_constraint_to (uses->id, arg);
} }
make_constraint_to (uses->id, arg);
} }
/* The static chain is used as well. */ /* The static chain is used as well. */
...@@ -4075,34 +4033,27 @@ find_func_aliases (gimple origt) ...@@ -4075,34 +4033,27 @@ find_func_aliases (gimple origt)
/* Now build constraints expressions. */ /* Now build constraints expressions. */
if (gimple_code (t) == GIMPLE_PHI) if (gimple_code (t) == GIMPLE_PHI)
{ {
gcc_assert (!AGGREGATE_TYPE_P (TREE_TYPE (gimple_phi_result (t)))); size_t i;
unsigned int j;
/* Only care about pointers and structures containing /* For a phi node, assign all the arguments to
pointers. */ the result. */
if (could_have_pointers (gimple_phi_result (t))) get_constraint_for (gimple_phi_result (t), &lhsc);
for (i = 0; i < gimple_phi_num_args (t); i++)
{ {
size_t i; tree strippedrhs = PHI_ARG_DEF (t, i);
unsigned int j;
/* For a phi node, assign all the arguments to
the result. */
get_constraint_for (gimple_phi_result (t), &lhsc);
for (i = 0; i < gimple_phi_num_args (t); i++)
{
tree strippedrhs = PHI_ARG_DEF (t, i);
STRIP_NOPS (strippedrhs); STRIP_NOPS (strippedrhs);
get_constraint_for_rhs (gimple_phi_arg_def (t, i), &rhsc); get_constraint_for_rhs (gimple_phi_arg_def (t, i), &rhsc);
FOR_EACH_VEC_ELT (ce_s, lhsc, j, c) FOR_EACH_VEC_ELT (ce_s, lhsc, j, c)
{
struct constraint_expr *c2;
while (VEC_length (ce_s, rhsc) > 0)
{ {
struct constraint_expr *c2; c2 = VEC_last (ce_s, rhsc);
while (VEC_length (ce_s, rhsc) > 0) process_constraint (new_constraint (*c, *c2));
{ VEC_pop (ce_s, rhsc);
c2 = VEC_last (ce_s, rhsc);
process_constraint (new_constraint (*c, *c2));
VEC_pop (ce_s, rhsc);
}
} }
} }
} }
...@@ -4353,16 +4304,7 @@ find_func_aliases (gimple origt) ...@@ -4353,16 +4304,7 @@ find_func_aliases (gimple origt)
else else
handle_rhs_call (t, &rhsc); handle_rhs_call (t, &rhsc);
if (gimple_call_lhs (t)) if (gimple_call_lhs (t))
{ handle_lhs_call (t, gimple_call_lhs (t), flags, rhsc, fndecl);
if (could_have_pointers (gimple_call_lhs (t)))
handle_lhs_call (t, gimple_call_lhs (t), flags, rhsc, fndecl);
/* Similar to conversions a result that is not a pointer
is an escape point for any pointer the function might
return. */
else if (flags & (ECF_CONST|ECF_PURE
|ECF_NOVOPS|ECF_LOOPING_CONST_OR_PURE))
make_constraints_to (escaped_id, rhsc);
}
VEC_free (ce_s, heap, rhsc); VEC_free (ce_s, heap, rhsc);
} }
else else
...@@ -4380,9 +4322,6 @@ find_func_aliases (gimple origt) ...@@ -4380,9 +4322,6 @@ find_func_aliases (gimple origt)
struct constraint_expr *rhsp; struct constraint_expr *rhsp;
tree arg = gimple_call_arg (t, j); tree arg = gimple_call_arg (t, j);
if (!could_have_pointers (arg))
continue;
get_constraint_for_rhs (arg, &rhsc); get_constraint_for_rhs (arg, &rhsc);
lhs = get_function_part_constraint (fi, fi_parm_base + j); lhs = get_function_part_constraint (fi, fi_parm_base + j);
while (VEC_length (ce_s, rhsc) != 0) while (VEC_length (ce_s, rhsc) != 0)
...@@ -4395,8 +4334,7 @@ find_func_aliases (gimple origt) ...@@ -4395,8 +4334,7 @@ find_func_aliases (gimple origt)
/* If we are returning a value, assign it to the result. */ /* If we are returning a value, assign it to the result. */
lhsop = gimple_call_lhs (t); lhsop = gimple_call_lhs (t);
if (lhsop if (lhsop)
&& type_could_have_pointers (TREE_TYPE (lhsop)))
{ {
struct constraint_expr rhs; struct constraint_expr rhs;
struct constraint_expr *lhsp; struct constraint_expr *lhsp;
...@@ -4449,8 +4387,7 @@ find_func_aliases (gimple origt) ...@@ -4449,8 +4387,7 @@ find_func_aliases (gimple origt)
/* Otherwise, just a regular assignment statement. Only care about /* Otherwise, just a regular assignment statement. Only care about
operations with pointer result, others are dealt with as escape operations with pointer result, others are dealt with as escape
points if they have pointer operands. */ points if they have pointer operands. */
else if (is_gimple_assign (t) else if (is_gimple_assign (t))
&& type_could_have_pointers (TREE_TYPE (gimple_assign_lhs (t))))
{ {
/* Otherwise, just a regular assignment statement. */ /* Otherwise, just a regular assignment statement. */
tree lhsop = gimple_assign_lhs (t); tree lhsop = gimple_assign_lhs (t);
...@@ -4460,7 +4397,6 @@ find_func_aliases (gimple origt) ...@@ -4460,7 +4397,6 @@ find_func_aliases (gimple origt)
do_structure_copy (lhsop, rhsop); do_structure_copy (lhsop, rhsop);
else else
{ {
struct constraint_expr temp;
get_constraint_for (lhsop, &lhsc); get_constraint_for (lhsop, &lhsc);
if (gimple_assign_rhs_code (t) == POINTER_PLUS_EXPR) if (gimple_assign_rhs_code (t) == POINTER_PLUS_EXPR)
...@@ -4481,10 +4417,19 @@ find_func_aliases (gimple origt) ...@@ -4481,10 +4417,19 @@ find_func_aliases (gimple origt)
get_constraint_for_rhs (rhsop, &rhsc); get_constraint_for_rhs (rhsop, &rhsc);
else else
{ {
temp.type = ADDRESSOF; /* All other operations are merges. */
temp.var = anything_id; VEC (ce_s, heap) *tmp = NULL;
temp.offset = 0; struct constraint_expr *rhsp;
VEC_safe_push (ce_s, heap, rhsc, &temp); unsigned i, j;
get_constraint_for_rhs (gimple_assign_rhs1 (t), &rhsc);
for (i = 2; i < gimple_num_ops (t); ++i)
{
get_constraint_for_rhs (gimple_op (t, i), &tmp);
FOR_EACH_VEC_ELT (ce_s, tmp, j, rhsp)
VEC_safe_push (ce_s, heap, rhsc, rhsp);
VEC_truncate (ce_s, tmp, 0);
}
VEC_free (ce_s, heap, tmp);
} }
process_all_all_constraints (lhsc, rhsc); process_all_all_constraints (lhsc, rhsc);
} }
...@@ -4505,17 +4450,9 @@ find_func_aliases (gimple origt) ...@@ -4505,17 +4450,9 @@ find_func_aliases (gimple origt)
make_constraint_from_restrict (get_vi_for_tree (lhsop), make_constraint_from_restrict (get_vi_for_tree (lhsop),
"CAST_RESTRICT"); "CAST_RESTRICT");
} }
/* For conversions of pointers to non-pointers the pointer escapes. */
else if (gimple_assign_cast_p (t)
&& POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (t)))
&& !POINTER_TYPE_P (TREE_TYPE (gimple_assign_lhs (t))))
{
make_escape_constraint (gimple_assign_rhs1 (t));
}
/* Handle escapes through return. */ /* Handle escapes through return. */
else if (gimple_code (t) == GIMPLE_RETURN else if (gimple_code (t) == GIMPLE_RETURN
&& gimple_return_retval (t) != NULL_TREE && gimple_return_retval (t) != NULL_TREE)
&& could_have_pointers (gimple_return_retval (t)))
{ {
fi = NULL; fi = NULL;
if (!in_ipa_mode if (!in_ipa_mode
...@@ -4561,7 +4498,7 @@ find_func_aliases (gimple origt) ...@@ -4561,7 +4498,7 @@ find_func_aliases (gimple origt)
/* The asm may read global memory, so outputs may point to /* The asm may read global memory, so outputs may point to
any global memory. */ any global memory. */
if (op && could_have_pointers (op)) if (op)
{ {
VEC(ce_s, heap) *lhsc = NULL; VEC(ce_s, heap) *lhsc = NULL;
struct constraint_expr rhsc, *lhsp; struct constraint_expr rhsc, *lhsp;
...@@ -4591,7 +4528,7 @@ find_func_aliases (gimple origt) ...@@ -4591,7 +4528,7 @@ find_func_aliases (gimple origt)
/* Strictly we'd only need the constraint to ESCAPED if /* Strictly we'd only need the constraint to ESCAPED if
the asm clobbers memory, otherwise using something the asm clobbers memory, otherwise using something
along the lines of per-call clobbers/uses would be enough. */ along the lines of per-call clobbers/uses would be enough. */
else if (op && could_have_pointers (op)) else if (op)
make_escape_constraint (op); make_escape_constraint (op);
} }
} }
...@@ -4960,6 +4897,8 @@ struct fieldoff ...@@ -4960,6 +4897,8 @@ struct fieldoff
unsigned has_unknown_size : 1; unsigned has_unknown_size : 1;
unsigned must_have_pointers : 1;
unsigned may_have_pointers : 1; unsigned may_have_pointers : 1;
unsigned only_restrict_pointers : 1; unsigned only_restrict_pointers : 1;
...@@ -5021,6 +4960,32 @@ var_can_have_subvars (const_tree v) ...@@ -5021,6 +4960,32 @@ var_can_have_subvars (const_tree v)
return false; return false;
} }
/* Return true if T is a type that does contain pointers. */
static bool
type_must_have_pointers (tree type)
{
if (POINTER_TYPE_P (type))
return true;
if (TREE_CODE (type) == ARRAY_TYPE)
return type_must_have_pointers (TREE_TYPE (type));
/* A function or method can have pointers as arguments, so track
those separately. */
if (TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE)
return true;
return false;
}
static bool
field_must_have_pointers (tree t)
{
return type_must_have_pointers (TREE_TYPE (t));
}
/* Given a TYPE, and a vector of field offsets FIELDSTACK, push all /* Given a TYPE, and a vector of field offsets FIELDSTACK, push all
the fields of TYPE onto fieldstack, recording their offsets along the fields of TYPE onto fieldstack, recording their offsets along
the way. the way.
...@@ -5032,7 +4997,7 @@ var_can_have_subvars (const_tree v) ...@@ -5032,7 +4997,7 @@ var_can_have_subvars (const_tree v)
static bool static bool
push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack, push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
HOST_WIDE_INT offset, bool must_have_pointers_p) HOST_WIDE_INT offset)
{ {
tree field; tree field;
bool empty_p = true; bool empty_p = true;
...@@ -5057,8 +5022,7 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack, ...@@ -5057,8 +5022,7 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
|| TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
push = true; push = true;
else if (!push_fields_onto_fieldstack else if (!push_fields_onto_fieldstack
(TREE_TYPE (field), fieldstack, offset + foff, (TREE_TYPE (field), fieldstack, offset + foff)
must_have_pointers_p)
&& (DECL_SIZE (field) && (DECL_SIZE (field)
&& !integer_zerop (DECL_SIZE (field)))) && !integer_zerop (DECL_SIZE (field))))
/* Empty structures may have actual size, like in C++. So /* Empty structures may have actual size, like in C++. So
...@@ -5070,6 +5034,7 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack, ...@@ -5070,6 +5034,7 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
{ {
fieldoff_s *pair = NULL; fieldoff_s *pair = NULL;
bool has_unknown_size = false; bool has_unknown_size = false;
bool must_have_pointers_p;
if (!VEC_empty (fieldoff_s, *fieldstack)) if (!VEC_empty (fieldoff_s, *fieldstack))
pair = VEC_last (fieldoff_s, *fieldstack); pair = VEC_last (fieldoff_s, *fieldstack);
...@@ -5079,13 +5044,13 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack, ...@@ -5079,13 +5044,13 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
has_unknown_size = true; has_unknown_size = true;
/* If adjacent fields do not contain pointers merge them. */ /* If adjacent fields do not contain pointers merge them. */
must_have_pointers_p = field_must_have_pointers (field);
if (pair if (pair
&& !pair->may_have_pointers
&& !pair->has_unknown_size
&& !has_unknown_size && !has_unknown_size
&& pair->offset + (HOST_WIDE_INT)pair->size == offset + foff
&& !must_have_pointers_p && !must_have_pointers_p
&& !could_have_pointers (field)) && !pair->must_have_pointers
&& !pair->has_unknown_size
&& pair->offset + (HOST_WIDE_INT)pair->size == offset + foff)
{ {
pair->size += TREE_INT_CST_LOW (DECL_SIZE (field)); pair->size += TREE_INT_CST_LOW (DECL_SIZE (field));
} }
...@@ -5098,8 +5063,8 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack, ...@@ -5098,8 +5063,8 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
pair->size = TREE_INT_CST_LOW (DECL_SIZE (field)); pair->size = TREE_INT_CST_LOW (DECL_SIZE (field));
else else
pair->size = -1; pair->size = -1;
pair->may_have_pointers pair->must_have_pointers = must_have_pointers_p;
= must_have_pointers_p || could_have_pointers (field); pair->may_have_pointers = true;
pair->only_restrict_pointers pair->only_restrict_pointers
= (!has_unknown_size = (!has_unknown_size
&& POINTER_TYPE_P (TREE_TYPE (field)) && POINTER_TYPE_P (TREE_TYPE (field))
...@@ -5245,7 +5210,7 @@ create_function_info_for (tree decl, const char *name) ...@@ -5245,7 +5210,7 @@ create_function_info_for (tree decl, const char *name)
resultvi->fullsize = vi->fullsize; resultvi->fullsize = vi->fullsize;
resultvi->is_full_var = true; resultvi->is_full_var = true;
if (DECL_RESULT (decl)) if (DECL_RESULT (decl))
resultvi->may_have_pointers = could_have_pointers (DECL_RESULT (decl)); resultvi->may_have_pointers = true;
gcc_assert (prev_vi->offset < resultvi->offset); gcc_assert (prev_vi->offset < resultvi->offset);
prev_vi->next = resultvi; prev_vi->next = resultvi;
prev_vi = resultvi; prev_vi = resultvi;
...@@ -5275,7 +5240,7 @@ create_function_info_for (tree decl, const char *name) ...@@ -5275,7 +5240,7 @@ create_function_info_for (tree decl, const char *name)
argvi->is_full_var = true; argvi->is_full_var = true;
argvi->fullsize = vi->fullsize; argvi->fullsize = vi->fullsize;
if (arg) if (arg)
argvi->may_have_pointers = could_have_pointers (arg); argvi->may_have_pointers = true;
gcc_assert (prev_vi->offset < argvi->offset); gcc_assert (prev_vi->offset < argvi->offset);
prev_vi->next = argvi; prev_vi->next = argvi;
prev_vi = argvi; prev_vi = argvi;
...@@ -5359,7 +5324,7 @@ create_variable_info_for_1 (tree decl, const char *name) ...@@ -5359,7 +5324,7 @@ create_variable_info_for_1 (tree decl, const char *name)
vi->fullsize = ~0; vi->fullsize = ~0;
vi->is_unknown_size_var = true; vi->is_unknown_size_var = true;
vi->is_full_var = true; vi->is_full_var = true;
vi->may_have_pointers = could_have_pointers (decl); vi->may_have_pointers = true;
return vi; return vi;
} }
...@@ -5376,10 +5341,7 @@ create_variable_info_for_1 (tree decl, const char *name) ...@@ -5376,10 +5341,7 @@ create_variable_info_for_1 (tree decl, const char *name)
bool notokay = false; bool notokay = false;
unsigned int i; unsigned int i;
push_fields_onto_fieldstack (decl_type, &fieldstack, 0, push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
TREE_PUBLIC (decl)
|| DECL_EXTERNAL (decl)
|| TREE_ADDRESSABLE (decl));
for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++) for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
if (fo->has_unknown_size if (fo->has_unknown_size
...@@ -5414,7 +5376,7 @@ create_variable_info_for_1 (tree decl, const char *name) ...@@ -5414,7 +5376,7 @@ create_variable_info_for_1 (tree decl, const char *name)
{ {
vi = new_var_info (decl, name); vi = new_var_info (decl, name);
vi->offset = 0; vi->offset = 0;
vi->may_have_pointers = could_have_pointers (decl); vi->may_have_pointers = true;
vi->fullsize = TREE_INT_CST_LOW (declsize); vi->fullsize = TREE_INT_CST_LOW (declsize);
vi->size = vi->fullsize; vi->size = vi->fullsize;
vi->is_full_var = true; vi->is_full_var = true;
...@@ -5558,9 +5520,6 @@ intra_create_variable_infos (void) ...@@ -5558,9 +5520,6 @@ intra_create_variable_infos (void)
{ {
varinfo_t p; varinfo_t p;
if (!could_have_pointers (t))
continue;
/* For restrict qualified pointers to objects passed by /* For restrict qualified pointers to objects passed by
reference build a real representative for the pointed-to object. */ reference build a real representative for the pointed-to object. */
if (DECL_BY_REFERENCE (t) if (DECL_BY_REFERENCE (t)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment