[PATCH] Fix points-to / call-clobber solution in the face of pointer-arithmetic

Richard Guenther rguenther@suse.de
Fri Jul 4 14:16:00 GMT 2008


This (again) fixes how we handle pointer-arithmetic in 
(field-sensitive) PTA.

First, as shown in the single testcase included, we have to be able
to compute the reachability set of a pointer that points after
an object - which we cannot do right now because the points-to set
we create at the moment is empty in that case.

Second, repeated increments smaller than a sub-field size do not
cause the solution to change, so the solution for p + 2 + 2 may
be different of that for p + 4.  This problem is a real problem
if we have a sub-field which includes multiple "real" fields
(which happens for structs with variable sized fields, or of course
with the patch globbing non-pointer fields).

The solution to the above problems is for 1) use the last sub-field
as the solution for off-variable pointers, 2) include the next
sub-field in the solution iff the sub-field doesn't start at the
offset.

An alternative solution to 1) is to drop to anything.

We still only handle positive offsets in arithmetic (we can handle
them if we drop to anything in case 1), or if we have an explicit
sub-field for one-after-the-object pointers, in which case we
would have to drop to anything if we go off that one).

Bootstrapped and tested on x86_64-unknown-linux-gnu, ok for trunk?

Thanks,
Richard.

2008-07-04  Richard Guenther  <rguenther@suse.de>

 	* tree-ssa-structalias.c (solution_set_add): Correctly handle
 	pointers outside a var and inside a field.
 	(process_constraint): Remove zeroing offset for !use_field_sensitive.
 	(get_constraint_for_ptr_offset): New function.
 	(get_constraint_for_component_ref): For addresses at least include
 	the last field of the variable.
 	(get_constraint_for_1): Factor common code, handle POINTER_PLUS_EXPR.
 	(handle_ptr_arith): Remove.
 	(find_func_aliases): Simplify assignment handling.
 	(init_alias_vars): Initialize use_field_sensitive from
 	max-fields-for-field-sensitive parameter.

 	* gcc.dg/torture/pta-ptrarith-1.c: New testcase.

Index: trunk/gcc/tree-ssa-structalias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-structalias.c	2008-07-04 11:36:20.000000000 +0200
--- trunk/gcc/tree-ssa-structalias.c	2008-07-04 13:52:19.000000000 +0200
*************** solution_set_add (bitmap set, unsigned H
*** 756,778 ****

     EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
       {
!       /* If this is a properly sized variable, only add offset if it's
! 	 less than end.  Otherwise, it is globbed to a single
! 	 variable.  */
! 
!       if ((get_varinfo (i)->offset + offset) < get_varinfo (i)->fullsize)
   	{
   	  unsigned HOST_WIDE_INT fieldoffset = get_varinfo (i)->offset + offset;
   	  varinfo_t v = first_vi_for_offset (get_varinfo (i), fieldoffset);
   	  if (!v)
! 	    continue;
   	  bitmap_set_bit (result, v->id);
! 	}
!       else if (get_varinfo (i)->is_artificial_var
! 	       || get_varinfo (i)->has_union
! 	       || get_varinfo (i)->is_unknown_size_var)
! 	{
! 	  bitmap_set_bit (result, i);
   	}
       }

--- 756,784 ----

     EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
       {
!       /* Artificial and unknown-size variables are not split.  */
!       if (get_varinfo (i)->is_artificial_var
! 	  || get_varinfo (i)->has_union
! 	  || get_varinfo (i)->is_unknown_size_var)
! 	bitmap_set_bit (result, i);
!       else
   	{
   	  unsigned HOST_WIDE_INT fieldoffset = get_varinfo (i)->offset + offset;
   	  varinfo_t v = first_vi_for_offset (get_varinfo (i), fieldoffset);
+ 	  /* If the result is outside of the variable use the last field.  */
   	  if (!v)
! 	    {
! 	      v = get_varinfo (i);
! 	      while (v->next != NULL)
! 	        v = v->next;
! 	    }
   	  bitmap_set_bit (result, v->id);
! 	  /* If the result is not exactly at fieldoffset include the next
! 	     field as well.  See get_constraint_for_ptr_offset for more
! 	     rationale.  */
! 	  if (v->offset != fieldoffset
! 	      && v->next != NULL)
! 	    bitmap_set_bit (result, v->next->id);
   	}
       }

*************** process_constraint (constraint_t t)
*** 2602,2613 ****
     gcc_assert (rhs.var < VEC_length (varinfo_t, varmap));
     gcc_assert (lhs.var < VEC_length (varinfo_t, varmap));

-   if (!use_field_sensitive)
-     {
-       t->rhs.offset = 0;
-       t->lhs.offset = 0;
-     }
-
     /* ANYTHING == ANYTHING is pointless.  */
     if (lhs.var == anything_id && rhs.var == anything_id)
       return;
--- 2608,2613 ----
*************** bitpos_of_field (const tree fdecl)
*** 2683,2688 ****
--- 2683,2809 ----
   }


+ /* Handle pointer arithmetic EXPR when creating aliasing constraints.
+    Expressions of the type PTR + CST can be handled in two ways:
+ 
+    1- If the constraint for PTR is ADDRESSOF for a non-structure
+       variable, then we can use it directly because adding or
+       subtracting a constant may not alter the original ADDRESSOF
+       constraint (i.e., pointer arithmetic may not legally go outside
+       an object's boundaries).
+ 
+    2- If the constraint for PTR is ADDRESSOF for a structure variable,
+       then if CST is a compile-time constant that can be used as an
+       offset, we can determine which sub-variable will be pointed-to
+       by the expression.
+ 
+    Return true if the expression is handled.  For any other kind of
+    expression, return false so that each operand can be added as a
+    separate constraint by the caller.  */
+ 
+ static void
+ get_constraint_for_ptr_offset (tree ptr, tree offset,
+ 			       VEC (ce_s, heap) **results)
+ {
+   struct constraint_expr *c;
+   unsigned int j, n;
+   unsigned HOST_WIDE_INT rhsunitoffset, rhsoffset;
+ 
+   /* If we do not do field-sensitive PTA adding offsets to pointers
+      does not change the points-to solution.  */
+   if (!use_field_sensitive)
+     {
+       get_constraint_for (ptr, results);
+       return;
+     }
+ 
+   /* If the offset is not a non-negative integer constant that fits
+      in a HOST_WIDE_INT, we have to fall back to a conservative
+      solution which includes all sub-fields of all pointed-to
+      variables of ptr.
+      ???  As we do not have the ability to express this, fall back
+      to anything.  */
+   if (!host_integerp (offset, 1))
+     {
+       struct constraint_expr temp;
+       temp.var = anything_id;
+       temp.type = SCALAR;
+       temp.offset = 0;
+       VEC_safe_push (ce_s, heap, *results, &temp);
+       return;
+     }
+ 
+   /* Make sure the bit-offset also fits.  */
+   rhsunitoffset = TREE_INT_CST_LOW (offset);
+   rhsoffset = rhsunitoffset * BITS_PER_UNIT;
+   if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
+     {
+       struct constraint_expr temp;
+       temp.var = anything_id;
+       temp.type = SCALAR;
+       temp.offset = 0;
+       VEC_safe_push (ce_s, heap, *results, &temp);
+       return;
+     }
+ 
+   get_constraint_for (ptr, results);
+   if (rhsoffset == 0)
+     return;
+ 
+   /* As we are eventually appending to the solution do not use
+      VEC_iterate here.  */
+   n = VEC_length (ce_s, *results);
+   for (j = 0; j < n; j++)
+     {
+       c = VEC_index (ce_s, *results, j);
+ 
+       if (c->type == ADDRESSOF)
+ 	{
+ 	  varinfo_t temp, curr = get_varinfo (c->var);
+ 
+ 	  /* Search the sub-field which overlaps with the
+ 	     pointed-to offset.  As we deal with positive offsets
+ 	     only, we can start the search from the current variable.  */
+ 	  temp = first_vi_for_offset (curr, curr->offset + rhsoffset);
+ 
+ 	  /* If the result is outside of the variable we have to provide
+ 	     a conservative result, as the variable is still reachable
+ 	     from the resulting pointer (even though it technically
+ 	     cannot point to anything).  The last sub-field is such
+ 	     a conservative result.
+ 	     ???  If we always had a sub-field for &object + 1 then
+ 	     we could represent this in a more precise way.  */
+ 	  if (temp == NULL)
+ 	    {
+ 	      temp = curr;
+ 	      while (temp->next != NULL)
+ 		temp = temp->next;
+ 	      continue;
+ 	    }
+ 
+ 	  /* If the found variable is not exactly at the pointed to
+ 	     result, we have to include the next variable in the
+ 	     solution as well.  Otherwise two increments by offset / 2
+ 	     do not result in the same or a conservative superset
+ 	     solution.  */
+ 	  if (temp->offset != curr->offset + rhsoffset
+ 	      && temp->next != NULL)
+ 	    {
+ 	      struct constraint_expr c2;
+ 	      c2.var = temp->next->id;
+ 	      c2.type = ADDRESSOF;
+ 	      c2.offset = 0;
+ 	      VEC_safe_push (ce_s, heap, *results, &c2);
+ 	    }
+ 	  c->var = temp->id;
+ 	  c->offset = 0;
+ 	}
+       else
+ 	c->offset = rhsoffset;
+     }
+ }
+ 
+
   /* Given a COMPONENT_REF T, return the constraint_expr vector for it.
      If address_p is true the result will be taken its address of.  */

*************** get_constraint_for_component_ref (tree t
*** 2719,2727 ****
     /* Pretend to take the address of the base, we'll take care of
        adding the required subset of sub-fields below.  */
     get_constraint_for_1 (t, results, true);
-   result = VEC_last (ce_s, *results);
-
     gcc_assert (VEC_length (ce_s, *results) == 1);

     /* This can also happen due to weird offsetof type macros.  */
     if (TREE_CODE (t) != ADDR_EXPR && result->type == ADDRESSOF)
--- 2840,2847 ----
     /* Pretend to take the address of the base, we'll take care of
        adding the required subset of sub-fields below.  */
     get_constraint_for_1 (t, results, true);
     gcc_assert (VEC_length (ce_s, *results) == 1);
+   result = VEC_last (ce_s, *results);

     /* This can also happen due to weird offsetof type macros.  */
     if (TREE_CODE (t) != ADDR_EXPR && result->type == ADDRESSOF)
*************** get_constraint_for_component_ref (tree t
*** 2756,2767 ****
   		    break;
   		}
   	    }
! 	  /* assert that we found *some* field there. The user couldn't be
! 	     accessing *only* padding.  */
! 	  /* Still the user could access one past the end of an array
! 	     embedded in a struct resulting in accessing *only* padding.  */
! 	  gcc_assert (VEC_length (ce_s, *results) >= 1
! 		      || ref_contains_array_ref (orig_t));
   	}
         else if (bitmaxsize == 0)
   	{
--- 2876,2900 ----
   		    break;
   		}
   	    }
! 	  /* If we are going to take the address of this field then
! 	     to be able to compute reachability correctly add at least
! 	     the last field of the variable.  */
! 	  if (address_p
! 	      && VEC_length (ce_s, *results) == 0)
! 	    {
! 	      curr = get_varinfo (cexpr.var);
! 	      while (curr->next != NULL)
! 		curr = curr->next;
! 	      cexpr.var = curr->id;
! 	      VEC_safe_push (ce_s, heap, *results, &cexpr);
! 	    }
! 	  else
! 	    /* Assert that we found *some* field there. The user couldn't be
! 	       accessing *only* padding.  */
! 	    /* Still the user could access one past the end of an array
! 	       embedded in a struct resulting in accessing *only* padding.  */
! 	    gcc_assert (VEC_length (ce_s, *results) >= 1
! 			|| ref_contains_array_ref (orig_t));
   	}
         else if (bitmaxsize == 0)
   	{
*************** get_constraint_for_1 (tree t, VEC (ce_s,
*** 2905,2928 ****
   		VEC_safe_push (ce_s, heap, *results, &temp);
   		return;
   	      }
- 	    else
- 	      {
- 		temp.var = anything_id;
- 		temp.type = SCALAR;
- 		temp.offset = 0;
- 		VEC_safe_push (ce_s, heap, *results, &temp);
- 		return;
- 	      }
   	    break;
! 	  default:
! 	    {
! 	      temp.type = ADDRESSOF;
! 	      temp.var = anything_id;
! 	      temp.offset = 0;
! 	      VEC_safe_push (ce_s, heap, *results, &temp);
! 	      return;
! 	    }
   	  }
         }
       case tcc_reference:
         {
--- 3038,3047 ----
   		VEC_safe_push (ce_s, heap, *results, &temp);
   		return;
   	      }
   	    break;
! 	  default:;
   	  }
+ 	break;
         }
       case tcc_reference:
         {
*************** get_constraint_for_1 (tree t, VEC (ce_s,
*** 2939,2953 ****
   	  case COMPONENT_REF:
   	    get_constraint_for_component_ref (t, results, address_p);
   	    return;
! 	  default:
! 	    {
! 	      temp.type = ADDRESSOF;
! 	      temp.var = anything_id;
! 	      temp.offset = 0;
! 	      VEC_safe_push (ce_s, heap, *results, &temp);
! 	      return;
! 	    }
   	  }
         }
       case tcc_unary:
         {
--- 3058,3066 ----
   	  case COMPONENT_REF:
   	    get_constraint_for_component_ref (t, results, address_p);
   	    return;
! 	  default:;
   	  }
+ 	break;
         }
       case tcc_unary:
         {
*************** get_constraint_for_1 (tree t, VEC (ce_s,
*** 2968,2982 ****

   	      /* FALLTHRU  */
   	    }
! 	  default:
! 	    {
! 	      temp.type = ADDRESSOF;
! 	      temp.var = anything_id;
! 	      temp.offset = 0;
! 	      VEC_safe_push (ce_s, heap, *results, &temp);
! 	      return;
! 	    }
   	  }
         }
       case tcc_exceptional:
         {
--- 3081,3099 ----

   	      /* FALLTHRU  */
   	    }
! 	  default:;
   	  }
+ 	break;
+       }
+     case tcc_binary:
+       {
+ 	if (TREE_CODE (t) == POINTER_PLUS_EXPR)
+ 	  {
+ 	    get_constraint_for_ptr_offset (TREE_OPERAND (t, 0),
+ 					   TREE_OPERAND (t, 1), results);
+ 	    return;
+ 	  }
+ 	break;
         }
       case tcc_exceptional:
         {
*************** get_constraint_for_1 (tree t, VEC (ce_s,
*** 2987,3023 ****
   	      get_constraint_for_1 (PHI_RESULT (t), results, address_p);
   	      return;
   	    }
- 	    break;
   	  case SSA_NAME:
   	    {
   	      get_constraint_for_ssa_var (t, results, address_p);
   	      return;
   	    }
! 	    break;
! 	  default:
! 	    {
! 	      temp.type = ADDRESSOF;
! 	      temp.var = anything_id;
! 	      temp.offset = 0;
! 	      VEC_safe_push (ce_s, heap, *results, &temp);
! 	      return;
! 	    }
   	  }
         }
       case tcc_declaration:
         {
   	get_constraint_for_ssa_var (t, results, address_p);
   	return;
         }
!     default:
!       {
! 	temp.type = ADDRESSOF;
! 	temp.var = anything_id;
! 	temp.offset = 0;
! 	VEC_safe_push (ce_s, heap, *results, &temp);
! 	return;
!       }
       }
   }

   /* Given a gimple tree T, return the constraint expression vector for it.  */
--- 3104,3131 ----
   	      get_constraint_for_1 (PHI_RESULT (t), results, address_p);
   	      return;
   	    }
   	  case SSA_NAME:
   	    {
   	      get_constraint_for_ssa_var (t, results, address_p);
   	      return;
   	    }
! 	  default:;
   	  }
+ 	break;
         }
       case tcc_declaration:
         {
   	get_constraint_for_ssa_var (t, results, address_p);
   	return;
         }
!     default:;
       }
+ 
+   /* The default fallback is a constraint from anything.  */
+   temp.type = ADDRESSOF;
+   temp.var = anything_id;
+   temp.offset = 0;
+   VEC_safe_push (ce_s, heap, *results, &temp);
   }

   /* Given a gimple tree T, return the constraint expression vector for it.  */
*************** do_structure_copy (tree lhsop, tree rhso
*** 3303,3382 ****
       }
   }

- 
- /* Handle pointer arithmetic EXPR when creating aliasing constraints.
-    Expressions of the type PTR + CST can be handled in two ways:
- 
-    1- If the constraint for PTR is ADDRESSOF for a non-structure
-       variable, then we can use it directly because adding or
-       subtracting a constant may not alter the original ADDRESSOF
-       constraint (i.e., pointer arithmetic may not legally go outside
-       an object's boundaries).
- 
-    2- If the constraint for PTR is ADDRESSOF for a structure variable,
-       then if CST is a compile-time constant that can be used as an
-       offset, we can determine which sub-variable will be pointed-to
-       by the expression.
- 
-    Return true if the expression is handled.  For any other kind of
-    expression, return false so that each operand can be added as a
-    separate constraint by the caller.  */
- 
- static bool
- handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr)
- {
-   tree op0, op1;
-   struct constraint_expr *c, *c2;
-   unsigned int i = 0;
-   unsigned int j = 0;
-   VEC (ce_s, heap) *temp = NULL;
-   unsigned HOST_WIDE_INT rhsunitoffset, rhsoffset;
- 
-   if (TREE_CODE (expr) != POINTER_PLUS_EXPR)
-     return false;
- 
-   op0 = TREE_OPERAND (expr, 0);
-   op1 = TREE_OPERAND (expr, 1);
-   gcc_assert (POINTER_TYPE_P (TREE_TYPE (op0)));
- 
-   /* If the offset is not a non-negative integer constant that fits
-      in a HOST_WIDE_INT, we cannot handle it here.  */
-   if (!host_integerp (op1, 1))
-     return false;
- 
-   /* Make sure the bit-offset also fits.  */
-   rhsunitoffset = TREE_INT_CST_LOW (op1);
-   rhsoffset = rhsunitoffset * BITS_PER_UNIT;
-   if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
-     return false;
- 
-   get_constraint_for (op0, &temp);
- 
-   for (i = 0; VEC_iterate (ce_s, lhsc, i, c); i++)
-     for (j = 0; VEC_iterate (ce_s, temp, j, c2); j++)
-       {
- 	if (c2->type == ADDRESSOF && rhsoffset != 0)
- 	  {
- 	    varinfo_t temp = get_varinfo (c2->var);
- 
- 	    /* An access one after the end of an array is valid,
- 	       so simply punt on accesses we cannot resolve.  */
- 	    temp = first_vi_for_offset (temp, rhsoffset);
- 	    if (temp == NULL)
- 	      continue;
- 	    c2->var = temp->id;
- 	    c2->offset = 0;
- 	  }
- 	else
- 	  c2->offset = rhsoffset;
- 	process_constraint (new_constraint (*c, *c2));
-       }
- 
-   VEC_free (ce_s, heap, temp);
- 
-   return true;
- }
-
   /* Create a constraint ID = OP.  */

   static void
--- 3411,3416 ----
*************** find_func_aliases (tree origt)
*** 3776,3864 ****
   	    }
   	}
       }
!   /* Otherwise, just a regular assignment statement.  */
!   else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
       {
         tree lhsop = GIMPLE_STMT_OPERAND (t, 0);
         tree rhsop = GIMPLE_STMT_OPERAND (t, 1);
-       int i;

!       if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
! 	  && AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
! 	{
! 	  do_structure_copy (lhsop, rhsop);
! 	}
         else
   	{
! 	  /* Only care about operations with pointers, structures
! 	     containing pointers, dereferences, and call expressions.  */
! 	  if (could_have_pointers (lhsop)
! 	      || TREE_CODE (rhsop) == CALL_EXPR)
   	    {
! 	      get_constraint_for (lhsop, &lhsc);
! 	      switch (TREE_CODE_CLASS (TREE_CODE (rhsop)))
! 		{
! 		  /* RHS that consist of unary operations,
! 		     exceptional types, or bare decls/constants, get
! 		     handled directly by get_constraint_for.  */
! 		  case tcc_reference:
! 		  case tcc_declaration:
! 		  case tcc_constant:
! 		  case tcc_exceptional:
! 		  case tcc_expression:
! 		  case tcc_vl_exp:
! 		  case tcc_unary:
! 		      {
! 			unsigned int j;
! 
! 			get_constraint_for (rhsop, &rhsc);
! 			for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
! 			  {
! 			    struct constraint_expr *c2;
! 			    unsigned int k;
! 
! 			    for (k = 0; VEC_iterate (ce_s, rhsc, k, c2); k++)
! 			      process_constraint (new_constraint (*c, *c2));
! 			  }
! 
! 		      }
! 		    break;

! 		  case tcc_binary:
! 		      {
! 			/* For pointer arithmetic of the form
! 			   PTR + CST, we can simply use PTR's
! 			   constraint because pointer arithmetic is
! 			   not allowed to go out of bounds.  */
! 			if (handle_ptr_arith (lhsc, rhsop))
! 			  break;
! 		      }
! 		    /* FALLTHRU  */
! 
! 		  /* Otherwise, walk each operand.  Notice that we
! 		     can't use the operand interface because we need
! 		     to process expressions other than simple operands
! 		     (e.g. INDIRECT_REF, ADDR_EXPR, CALL_EXPR).  */
! 		  default:
! 		    for (i = 0; i < TREE_OPERAND_LENGTH (rhsop); i++)
! 		      {
! 			tree op = TREE_OPERAND (rhsop, i);
! 			unsigned int j;
! 
! 			gcc_assert (VEC_length (ce_s, rhsc) == 0);
! 			get_constraint_for (op, &rhsc);
! 			for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
! 			  {
! 			    struct constraint_expr *c2;
! 			    while (VEC_length (ce_s, rhsc) > 0)
! 			      {
! 				c2 = VEC_last (ce_s, rhsc);
! 				process_constraint (new_constraint (*c, *c2));
! 				VEC_pop (ce_s, rhsc);
! 			      }
! 			  }
! 		      }
! 		}
   	    }
   	}
       }
--- 3810,3838 ----
   	    }
   	}
       }
!   /* Otherwise, just a regular assignment statement.  Only care about
!      operations with pointer result, others are dealt with as escape
!      points if they have pointer operands.  */
!   else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
! 	   && could_have_pointers (GIMPLE_STMT_OPERAND (t, 0)))
       {
         tree lhsop = GIMPLE_STMT_OPERAND (t, 0);
         tree rhsop = GIMPLE_STMT_OPERAND (t, 1);

!       if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop)))
! 	do_structure_copy (lhsop, rhsop);
         else
   	{
! 	  unsigned int j;
! 	  get_constraint_for (lhsop, &lhsc);
! 	  get_constraint_for (rhsop, &rhsc);
! 	  for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
   	    {
! 	      struct constraint_expr *c2;
! 	      unsigned int k;

! 	      for (k = 0; VEC_iterate (ce_s, rhsc, k, c2); k++)
! 		process_constraint (new_constraint (*c, *c2));
   	    }
   	}
       }
*************** init_base_vars (void)
*** 5209,5214 ****
--- 5183,5190 ----
   static void
   init_alias_vars (void)
   {
+   use_field_sensitive = (MAX_FIELDS_FOR_FIELD_SENSITIVE > 1);
+
     bitmap_obstack_initialize (&pta_obstack);
     bitmap_obstack_initialize (&oldpta_obstack);
     bitmap_obstack_initialize (&predbitmap_obstack);
Index: trunk/gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c	2008-07-04 14:43:54.000000000 +0200
***************
*** 0 ****
--- 1,33 ----
+ /* { dg-do run } */
+ /* { dg-options "-fdump-tree-alias" } */
+ /* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+ 
+ struct Foo {
+   int *p;
+ };
+ 
+ void __attribute__((noinline))
+ foo (void *p)
+ {
+   struct Foo *f = (struct Foo *)p - 1;
+   *f->p = 0;
+ }
+ 
+ int bar (void)
+ {
+   struct Foo f;
+   int i = 1;
+   f.p = &i;
+   foo (&f + 1);
+   return i;
+ }
+ extern void abort (void);
+ int main()
+ {
+   if (bar () != 0)
+     abort ();
+   return 0;
+ }
+ 
+ /* { dg-final { scan-tree-dump "ESCAPED = { ESCAPED NONLOCAL f i }" "alias" } } */
+ /* { dg-final { cleanup-tree-dump "alias" } } */



More information about the Gcc-patches mailing list