This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Fix call-clobbering (PRs 36373 and 36387)
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Diego Novillo <dnovillo at google dot com>, Daniel Berlin <dberlin at dberlin dot org>
- Date: Sat, 31 May 2008 13:41:36 +0200 (CEST)
- Subject: Re: [PATCH] Fix call-clobbering (PRs 36373 and 36387)
- References: <Pine.LNX.4.64.0805310004080.26762@zhemvz.fhfr.qr>
So, over the discussion about the points-to fix and the call clobbering
the following parts of the patch fix one serious problem,
struct_with_pointers = foo ();
didn't get a struct_with_pointers = &ANYTHING constraint, fixed with
*************** find_func_aliases (tree origt)
*** 3726,3732 ****
if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
{
handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1));
! if (POINTER_TYPE_P (TREE_TYPE (GIMPLE_STMT_OPERAND (t, 1))))
handle_lhs_call (GIMPLE_STMT_OPERAND (t, 0));
}
else
--- 3494,3502 ----
if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
{
handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1));
! /* If the result containts pointers, we need to generate
! constraints from anything for the lhs. */
! if (could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
handle_lhs_call (GIMPLE_STMT_OPERAND (t, 0));
}
else
the rest of the patch below is cleanup and optimization. First
a const/pure call cannot write to its arguments:
*************** handle_rhs_call (tree rhs)
*** 3608,3625 ****
call_expr_arg_iterator iter;
struct constraint_expr rhsc;
+ /* A pure/const function is neither an escape and nor a clobber site.
*/
+ if (call_expr_flags (rhs) & (ECF_CONST | ECF_PURE))
+ return;
+
rhsc.var = anything_id;
Second, the non-exact could_have_pointers causes a bunch of extra
X = &ANYTHING constraints, in particular from struct arguments
(I had a testcase failing because of this, I guess it will fail with
the points-to fix as well then).
*************** process_constraint (constraint_t t)
*** 2596,2611 ****
/* Return true if T is a variable of a type that could contain
pointers. */
! static bool
could_have_pointers (tree t)
{
tree type = TREE_TYPE (t);
! if (POINTER_TYPE_P (type)
! || AGGREGATE_TYPE_P (type)
! || TREE_CODE (type) == COMPLEX_TYPE)
return true;
return false;
}
--- 2596,2624 ----
/* Return true if T is a variable of a type that could contain
pointers. */
! bool
could_have_pointers (tree t)
{
tree type = TREE_TYPE (t);
! if (POINTER_TYPE_P (type))
return true;
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && could_have_pointers (type))
+ return true;
+
+ if (TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == UNION_TYPE
+ || TREE_CODE (type) == QUAL_UNION_TYPE)
+ {
+ tree field;
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN
(field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && could_have_pointers (field))
+ return true;
+ }
+
return false;
}
I can add a cache if you think this may cause compile-time problems.
(I was thinking on two bitmaps indexed by the type UID, one to note
if we have seen this type and one to note its state. We can keep this
over the whole compilation as type UIDs are unique in the whole
program. I'd use it only for structs where the walking is expensive.).
For reference, full patch including cleanup parts below.
Are those ok with you?
Thanks,
Richard.
2008-05-30 Richard Guenther <rguenther@suse.de>
PR tree-optimization/36373
PR tree-optimization/36387
* tree-ssa-structalias.c (could_have_pointers): Export.
COMPLEX_TYPEs cannot contain pointers. Recurse for arrays and
structures.
(handle_rhs_call): Don't do anything for const/pure calls.
(find_func_aliases): Generate constraints for the LHS of calls
if the LHS may contain pointers. Process a structure copy
if it is a structure copy.
Index: trunk/gcc/tree-ssa-structalias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-structalias.c 2008-05-30 21:56:26.000000000 +0200
--- trunk/gcc/tree-ssa-structalias.c 2008-05-30 22:19:06.000000000 +0200
*************** process_constraint (constraint_t t)
*** 2596,2611 ****
/* Return true if T is a variable of a type that could contain
pointers. */
! static bool
could_have_pointers (tree t)
{
tree type = TREE_TYPE (t);
! if (POINTER_TYPE_P (type)
! || AGGREGATE_TYPE_P (type)
! || TREE_CODE (type) == COMPLEX_TYPE)
return true;
return false;
}
--- 2596,2624 ----
/* Return true if T is a variable of a type that could contain
pointers. */
! bool
could_have_pointers (tree t)
{
tree type = TREE_TYPE (t);
! if (POINTER_TYPE_P (type))
return true;
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && could_have_pointers (type))
+ return true;
+
+ if (TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == UNION_TYPE
+ || TREE_CODE (type) == QUAL_UNION_TYPE)
+ {
+ tree field;
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && could_have_pointers (field))
+ return true;
+ }
+
return false;
}
*************** do_structure_copy (tree lhsop, tree rhso
*** 3146,3157 ****
gcc_assert (VEC_length (ce_s, rhsc) == 1);
lhs = *(VEC_last (ce_s, lhsc));
rhs = *(VEC_last (ce_s, rhsc));
-
VEC_free (ce_s, heap, lhsc);
VEC_free (ce_s, heap, rhsc);
/* If we have special var = x, swap it around. */
! if (lhs.var <= integer_id && !(get_varinfo (rhs.var)->is_special_var))
{
tmp = lhs;
lhs = rhs;
--- 3159,3170 ----
gcc_assert (VEC_length (ce_s, rhsc) == 1);
lhs = *(VEC_last (ce_s, lhsc));
rhs = *(VEC_last (ce_s, rhsc));
VEC_free (ce_s, heap, lhsc);
VEC_free (ce_s, heap, rhsc);
/* If we have special var = x, swap it around. */
! if (get_varinfo (lhs.var)->is_special_var
! && !(get_varinfo (rhs.var)->is_special_var))
{
tmp = lhs;
lhs = rhs;
*************** handle_rhs_call (tree rhs)
*** 3608,3625 ****
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;
--- 3371,3393 ----
call_expr_arg_iterator iter;
struct constraint_expr rhsc;
+ /* A pure/const function is neither an escape and nor a clobber site. */
+ if (call_expr_flags (rhs) & (ECF_CONST | ECF_PURE))
+ return;
+
rhsc.var = anything_id;
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
FOR_EACH_CALL_EXPR_ARG (arg, iter, rhs)
{
! /* Find those pointers being passed, and make sure their pointed
! to memory ends up pointing to anything.
! ??? This is a insufficient hack. See PR36387. */
! if (POINTER_TYPE_P (TREE_TYPE (arg))
! && could_have_pointers (TREE_TYPE (arg)))
{
+ VEC(ce_s, heap) *lhsc = NULL;
unsigned int j;
struct constraint_expr *lhsp;
*************** find_func_aliases (tree origt)
*** 3726,3732 ****
if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
{
handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1));
! if (POINTER_TYPE_P (TREE_TYPE (GIMPLE_STMT_OPERAND (t, 1))))
handle_lhs_call (GIMPLE_STMT_OPERAND (t, 0));
}
else
--- 3494,3502 ----
if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
{
handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1));
! /* If the result containts pointers, we need to generate
! constraints from anything for the lhs. */
! if (could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
handle_lhs_call (GIMPLE_STMT_OPERAND (t, 0));
}
else
*************** find_func_aliases (tree origt)
*** 3828,3840 ****
tree rhsop = GIMPLE_STMT_OPERAND (t, 1);
int i;
! if ((AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
! || TREE_CODE (TREE_TYPE (lhsop)) == COMPLEX_TYPE)
! && (AGGREGATE_TYPE_P (TREE_TYPE (rhsop))
! || TREE_CODE (TREE_TYPE (lhsop)) == COMPLEX_TYPE))
! {
! do_structure_copy (lhsop, rhsop);
! }
else
{
/* Only care about operations with pointers, structures
--- 3598,3606 ----
tree rhsop = GIMPLE_STMT_OPERAND (t, 1);
int i;
! if (!is_gimple_reg (lhsop)
! && !is_gimple_reg (rhsop) && !is_gimple_min_invariant (rhsop))
! do_structure_copy (lhsop, rhsop);
else
{
/* Only care about operations with pointers, structures