[PATCH] Fix call-clobbering (PRs 36373 and 36387)

Richard Guenther rguenther@suse.de
Mon Jun 9 11:21:00 GMT 2008


On Fri, 6 Jun 2008, Daniel Berlin wrote:

> On Fri, Jun 6, 2008 at 10:14 AM, Richard Guenther <rguenther@suse.de> wrote:
> > On Fri, 6 Jun 2008, Richard Guenther wrote:
> >
> >> On Thu, 5 Jun 2008, Daniel Berlin wrote:
> >>
> >> > On Thu, Jun 5, 2008 at 9:07 AM, Richard Guenther <rguenther@suse.de> wrote:
> >> > > On Fri, 30 May 2008, Daniel Berlin wrote:
> >> > >
> >> > >> Something like the attached should fix the points-to results (I may
> >> > >> have missed some is_special_var cases to remove, etc)
> >> > >
> >> > > I played a little with the patch and tried to simplify and extend it
> >> > > somewhat (I'm still trying to improve the accuracy of call clobbers,
> >> > > because thats the only thing the alias-oracle really has to punt on
> >> > > while walking the statements).
> >> > >
> >> > > First I didn't like re-using ANYTHING for aggregating the reachable
> >> > > escaped memory, so I created a new var ESCAPED for that (and simply
> >> > > make it not a special_var, so the solver part of the patch seems
> >> > > unneeded).  In interpreting the PTA results, ESCAPED needs to
> >> > > be treated the same as anything in this state.  Note in particular
> >> > > that for fixing the aggregate escape bugs I created proper
> >> > > constraints for escape sites.
> >> > >
> >> > > The thing we can improve with call-clobbers is to track NONLOCAL
> >> > > again, noting that at calls the reachable memory can point to
> >> > > NONLOCAL and ESCAPED.  Likewise call results point to NONLOCAL
> >> > > and ESCAPED and obviously incoming function arguments point to NONLOCAL.
> >> > > But for that to really work I need to track escapes to global vars
> >> > > and read from global vars properly - in the end ESCAPED would then
> >> > > (apart from global vars) include the full call-clobber solution, no
> >> > > need for a separate transitive closure there.
> >> > >
> >> > > This still won't handle pure/const functions in an optimal manner
> >> > > because we would have to track call-used memory for those.  Both
> >> > > are not escape sites but const functions may return pointers to
> >> > > global memory and its function arguments.  pure functions may return
> >> > > pointers to any reachable memory by its function arguments in addition.
> >> > > Proper VUSEs need to be added for them.  [with the patch below
> >> > > gcc.dg/tree-ssa/pr24287.c fails to optimize because of this]
> >> > >
> >> > > I verified that with the re-invention of NONLOCAL and ESCAPED we
> >> > > don't get PR30052 back, but I still have to do some compile-time
> >> > > analyses.  With making can_have_pointers more precise we can possibly
> >> > > avoid creating some constraints and increase the precision as well.
> >> > >
> >> > > Bootstrapped / tested on x86_64-unknown-linux-gnu.
> >> > >
> >> > > While the patch is getting somewhat big I'm going to try to track
> >> > > call-used memory separately and clean up the memory-tag clobbering
> >> > > code.  Still, does this look like a reasonable change?
> >> > >
> >> >
> >> > It looks reasonable to me. If you have ESCAPE compute transitive
> >> > closure from points-to, you are going to want to make a fake set until
> >> > the end.
> >> >
> >> > Otherwise, you will have this:
> >> >
> >> > ESCAPED = <6000 variables>
> >> > foo (which escapes) = ESCAPED
> >> > bar (which escapes) = ESCAPED
> >> > etc
> >> > Offline var substitution will not always collapse these, and you will
> >> > end up allocating 6000 bit bitmaps for a lot of variables and then
> >> > propagating them around.
> >> >
> >> > This is easily taken care of with a fake variable though, like
> >> > ESCAPED_SET, which you fill in at *_what_p_points_to time with the
> >> > result of ESCAPED.
> >>
> >> Yes, I'm seeing for example
> >>
> >> ESCAPED = *ESCAPED
> >> ESCAPED = &ESCAPED
> >> derefaddrtmp.30 = &ESCAPED
> >> *ESCAPED = derefaddrtmp.30
> >> derefaddrtmp.31 = &NONLOCAL
> >> *ESCAPED = derefaddrtmp.31
> >> a = &i
> >> b = &i
> >> ESCAPED = &a
> >> ESCAPED = &b
> >> D.1567_1 = a
> >> D.1570_4 = b
> >>
> >> ->
> >>
> >> ESCAPED = { ESCAPED NONLOCAL a i b }
> >> NONLOCAL = { }
> >> a = same as D.1567_1
> >> i = { ESCAPED NONLOCAL }
> >> b = same as D.1570_4
> >> D.1567_1 = { ESCAPED NONLOCAL i }
> >> D.1570_4 = { ESCAPED NONLOCAL i }
> >>
> >> where for example the i = { ESCAPED NONLOCAL } is not needed (i is not
> >> a pointer) and D.1567_1 and D.1570_4 could have been unified.
> >>
> >> but I don't understand what you are suggesting ;)
> >>
> >> are you suggesting not to add ESCAPED to the points-to solution until
> >> after the solver finished and get the information from the ESCAPED
> >> set itself at *_what_p_points_to time?  That is, omit
> >>
> >> derefaddrtmp.30 = &ESCAPED
> >> *ESCAPED = derefaddrtmp.30
> >> derefaddrtmp.31 = &NONLOCAL
> >> *ESCAPED = derefaddrtmp.31
> >>
> >> from the static constraints so we end up with
> >>
> >> ESCAPED = { ESCAPED a i b }
> >> NONLOCAL = { }
> >> a = same as D.1567_1
> >> i = { }
> >> b = same as D.1570_4
> >> D.1567_1 = { i }
> >> D.1570_4 = { i }
> >>
> >> ?
> >>
> >> btw - can ESCAPED ever be unioned with some other variable?  (it's
> >> only an is_artificial_var, not is_special_var)
> >
> > Btw - this doesn't work correctly.  Suppose you have
> >
> > p = &i
> > ESCAPED = &p
> > x_4 = p
> > x_1 = x_4
> > x_1 = &NULL
> >
> > then you end up with
> >
> > ESCAPED = { p i }
> > p = { ESCAPED NONLOCAL i }
> > p = same as x_4
> > i = { }
> > x_4 = { ESCAPED NONLOCAL i }
> > x_1 = { NULL i }
> >
> 
> ???
> From your constraints, x_1 = x_4, so if x_4 contains { ESCAPED
> NONLOCAL }, so should x_1 at the end of solving.
> My guess is that  it is one of the special casings in the solver that
> is making this not work (or you didn't actually try the above :P)

Yes, I did ;)  x_1 is the result of a PHI node (I just wanted to avoid
x_1 is being unified with p, in which case it obviously works).

But the above is without the

  *ESCAPED = &ESCAPED

constraint (but only the ESCAPED = *ESCAPED one).  x_4 works because
it is unified with p.  So the point was that I need the
*ESCAPED = &ESCAPED constraint to do the transitive clobbering, thus
your suggestion to use ESCAPED and ESCAPED_PLACEHOLDER won't work.

> No, i'm suggesting that you have  both "ESCAPED" and
> "ESCAPED_PLACEHOLDER". ESCAPED should be computed as it is now.
> Things you are trying to set *from* ESCAPED (IE a = ESCAPED) should be
> set to ESCAPED_PLACEHOLDER instead.
>
> At the end, anything pointing to ESCAPED_PLACEHOLDER gets ESCAPED's
> points-to vars added to it's set.

Computing ESCAPED requires a transitive closure, thus

  ESCAPED = *ESCAPED
  ESCAPED = p
  ...

and the clobbering (that is, the set that needs its points-to set
adjusted by ESCAPED) as well, thus

  ESCAPED_PLACEHOLDER = *ESCAPED_PLACEHOLDER
  *p = &ESCAPED_PLACEHOLDER

but that means I gain nothing from using ESCAPED_PLACEHOLDER?
(and I guess the above wouldn't set ***p = &ESCAPED_PLACEHOLDER
either - which is the situation above where I said "it doens't work").

So, basically I'm back to doing

  ESCAPED = *ESCAPED
  *ESCAPED = &ESCAPED

and for every escaped pointer

  ESCAPED = p

which will end up with

  p = { ... ESCAPED }


The following is the current patch, see

  /* We wouldn't need the two constraints below if we propagated them
     manually after solving.  See distribute_escape_set ().  */

for what (wrong) parts I had to disable again to get it working again.

Richard.

2008-06-05  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.

Index: trunk/gcc/tree-ssa-structalias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-structalias.c	2008-06-06 12:08:19.000000000 +0200
--- trunk/gcc/tree-ssa-structalias.c	2008-06-06 16:27:24.000000000 +0200
*************** get_varinfo_fc (unsigned int n)
*** 299,324 ****
    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.  */
  
--- 299,332 ----
    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
*** 3285,3308 ****
    /* 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
--- 3293,3299 ----
    /* 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
*** 3578,3583 ****
--- 3569,3599 ----
    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)
*** 3586,3620 ****
  {
    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)
--- 3602,3622 ----
  {
    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)
*** 3624,3635 ****
    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);
  }
  
--- 3626,3695 ----
    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)
*** 3641,3650 ****
  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);
--- 3701,3712 ----
  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)
*** 3693,3709 ****
  
       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)))
--- 3755,3780 ----
  
       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)
*** 3898,3903 ****
--- 3969,4025 ----
  	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, 
*** 4116,4124 ****
    return count;
  }
  
! /* Create a constraint from ANYTHING variable to VI.  */
  static void
! make_constraint_from_anything (varinfo_t vi)
  {
    struct constraint_expr lhs, rhs;
  
--- 4238,4246 ----
    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
*** 4126,4137 ****
    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.  */
  
--- 4248,4266 ----
    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)
*** 4476,4482 ****
    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;
--- 4605,4611 ----
    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)
*** 4537,4543 ****
  	  varinfo_t arg_vi = get_vi_for_tree (t);
  
  	  for (p = arg_vi; p; p = p->next)
! 	    make_constraint_from_anything (p);
  	}
      }
  }
--- 4666,4672 ----
  	  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)
*** 4791,4797 ****
  		     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;
--- 4920,4928 ----
  		     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)
*** 4840,4881 ****
    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)
--- 4971,4993 ----
    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)
*** 4900,4911 ****
  	   || 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
--- 5012,5024 ----
  	   || 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)
*** 4956,4975 ****
    /* 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;
--- 5069,5087 ----
    /* 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)
*** 4977,4983 ****
    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,
--- 5089,5094 ----
*************** init_base_vars (void)
*** 4998,5004 ****
    /* 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;
--- 5109,5115 ----
    /* 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)
*** 5006,5012 ****
    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
--- 5117,5122 ----
*************** init_base_vars (void)
*** 5017,5031 ****
    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;
--- 5127,5174 ----
    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)
*** 5033,5039 ****
    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
--- 5176,5181 ----
*************** init_base_vars (void)
*** 5045,5050 ****
--- 5187,5215 ----
    rhs.var = anything_id;
    rhs.offset = 0;
    process_constraint (new_constraint (lhs, rhs));
+ 
+   /* We wouldn't need the two constraints below if we propagated them
+      manually after solving.  See distribute_escape_set ().  */
+ 
+   /* *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 */
*************** compute_tbaa_pruning (void)
*** 5239,5244 ****
--- 5404,5429 ----
      }
  }
  
+ /* Distributes escaped_id and nonlocal_id to the solutions of escaped vars.  */
+ 
+ static void ATTRIBUTE_UNUSED
+ distribute_escape_set (void)
+ {
+   varinfo_t escaped = get_varinfo (find (escaped_id));
+   bitmap_iterator bi;
+   unsigned i;
+ 
+   EXECUTE_IF_SET_IN_BITMAP (escaped->solution, 0, i, bi)
+     {
+       varinfo_t vi = get_varinfo (find (i));
+       if (could_have_pointers (vi->decl))
+ 	{
+ 	  bitmap_set_bit (vi->solution, escaped_id);
+ 	  bitmap_set_bit (vi->solution, nonlocal_id);
+ 	}
+     }
+ }
+ 
  /* Create points-to sets for the current function.  See the comments
     at the start of the file for an algorithmic overview.  */
  
*************** compute_points_to_sets (struct alias_inf
*** 5348,5353 ****
--- 5533,5542 ----
  
    compute_tbaa_pruning ();
  
+   /* This implementation doesn't work.  We need to fully propagate
+      ESCAPED and NONLOCAL from the ESCAPED set.  */
+   /* distribute_escape_set (); */
+ 
    if (dump_file)
      dump_sa_points_to_info (dump_file);
  
Index: trunk/gcc/tree-flow.h
===================================================================
*** trunk.orig/gcc/tree-flow.h	2008-06-06 12:04:35.000000000 +0200
--- trunk/gcc/tree-flow.h	2008-06-06 12:23:36.000000000 +0200
*************** tree gimple_fold_indirect_ref (tree);
*** 1167,1173 ****
  
  /* 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);
--- 1167,1173 ----
  
  /* 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-06 12:04:35.000000000 +0200
--- trunk/gcc/tree-ssa-alias.c	2008-06-06 13:44:48.000000000 +0200
*************** set_initial_properties (struct alias_inf
*** 538,543 ****
--- 538,549 ----
  	}
      }
  
+   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
*** 558,575 ****
  
  	  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
--- 564,569 ----
*************** is_escape_site (tree stmt)
*** 2889,2894 ****
--- 2883,2894 ----
        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-06 12:23:36.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-06 12:23:36.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-06 12:23:36.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-06 12:23:36.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-06 12:23:36.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-06 12:23:36.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-06 12:23:36.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-06 12:23:36.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-06 12:23:36.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-06 12:23:36.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-06 12:23:36.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-06 12:04:35.000000000 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c	2008-06-06 12:23:36.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-06 15:51:10.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" } } */



More information about the Gcc-patches mailing list