This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


The current call-clobbering code as far as it deals with using
the PTA results is missing quite a few cases.  First escaped
aggregates (as opposed to pointers) are not tracked at all.
Second, we miss to compute the reachability set of the
escaped pointers and only clobber the directly pointed-to
memory.

Thus, the following patch re-writes the call-clobbering and escape
code to run after the PTA solver and to properly track all escapes.
It computes the reachability set by doing a transitive closure
on the escaped variables with respect to their points-to set and
marks the result call clobbered.

This fixes quite a bunch of testcases and should get the
clobbering correct now.

A followup patch needs to deal with the wrong final points-to sets
(see comment #2 of PR36387) by fixing them by using the
call-clobber solution.  A followup also may need to deal with the
memory tag clobbering code - but I have to think about how to
correctly deal with that.

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

Thanks,
Richard.

2008-05-30  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/36373
	PR tree-optimization/36387
	* tree-ssa-structalias.h (struct alias_info): Move ...
	* tree-ssa-alias.c (struct alias_info): ... here.  Add
	escape_solution member.
	* tree-ssa-structalias.c (update_alias_info): Move ...
	* tree-ssa-alias.c (update_alias_info): ... here.  Initialize the
	escape_solution from the escaped variables points-to solution.
	(process_escape): New helper function.
	(set_initial_properties): Compute the call clobbered variables by
	computing the reachable memory from the escaped pointers and the
	escape_solution.
	(compute_escape_set): New function.
	(compute_may_aliases): Call it.
	(init_alias_info): Allocate escape_solution.
	* 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.
	Mention this is a hack.
	(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.
	(clobber_what_p_points_to): Remove.
	(union_what_p_points_to): New function.
	(union_what_p_points_to_indirect): Likewise.
	(compute_reachability_set): Likewise.
	(clobber_set): Likewise.
	(compute_points_to_sets): Do not call update_alias_info here.
	* tree-flow.h (clobber_what_p_points_to): Remove.
	(union_what_p_points_to): Declare.
	(union_what_p_points_to_indirect): Likewise.
	(compute_reachability_set): Likewise.
	(clobber_set): Likewise.
	* tree-ssa-structalias.h (could_have_pointers): Export.
	(compute_points_to_sets): Adjust prototype.

	* 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.

Index: trunk/gcc/tree-ssa-alias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-alias.c	2008-05-30 21:56:26.000000000 +0200
--- trunk/gcc/tree-ssa-alias.c	2008-05-30 22:49:53.000000000 +0200
*************** along with GCC; see the file COPYING3.  
*** 166,171 ****
--- 166,208 ----
     Lastly, we delete partitions with no symbols, and clean up after
     ourselves.  */
  
+ 
+ /* Alias information used by compute_may_aliases and its helpers.  */
+ struct alias_info
+ {
+   /* SSA names visited while collecting points-to information.  If bit I
+      is set, it means that SSA variable with version I has already been
+      visited.  */
+   sbitmap ssa_names_visited;
+ 
+   /* Array of SSA_NAME pointers processed by the points-to collector.  */
+   VEC(tree,heap) *processed_ptrs;
+ 
+   /* ADDRESSABLE_VARS contains all the global variables and locals that
+      have had their address taken.  */
+   struct alias_map_d **addressable_vars;
+   size_t num_addressable_vars;
+ 
+   /* POINTERS contains all the _DECL pointers with unique memory tags
+      that have been referenced in the program.  */
+   struct alias_map_d **pointers;
+   size_t num_pointers;
+ 
+   /* Variables that have been written to directly (i.e., not through a
+      pointer dereference).  */
+   struct pointer_set_t *written_vars;
+ 
+   /* Pointers that have been used in an indirect store operation.  */
+   struct pointer_set_t *dereferenced_ptrs_store;
+ 
+   /* Pointers that have been used in an indirect load operation.  */
+   struct pointer_set_t *dereferenced_ptrs_load;
+ 
+   /* Points-to solution for the variables that escaped.  */
+   bitmap escape_solution;
+ };
+ 
+ 
  /* Structure to map a variable to its alias set.  */
  struct alias_map_d
  {
*************** set_initial_properties (struct alias_inf
*** 523,529 ****
    tree ptr;
    bool any_pt_anything = false;
    enum escape_type pt_anything_mask = 0;
- 
    FOR_EACH_REFERENCED_VAR (var, rvi)
      {
        if (is_global_var (var))
--- 560,565 ----
*************** set_initial_properties (struct alias_inf
*** 541,546 ****
--- 577,608 ----
  	}
      }
  
+   /* Add escaped pointers to the escape solution.  */
+   for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
+     {
+       struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+ 
+       /* A pointer that only escapes via a function return does not
+          add to the call clobber or call used solution.
+ 	 To exclude ESCAPE_TO_PURE_CONST we would need to track
+ 	 call used variables separately or compute those properly
+ 	 in the operand scanner.  */
+       if (pi->value_escapes_p
+ 	  && pi->escape_mask & ~(ESCAPE_TO_RETURN|ESCAPE_IS_PARM))
+ 	if (union_what_p_points_to (ai->escape_solution, ptr))
+ 	  break;
+     }
+ 
+   /* Transitively close the escape solution to compute the reachability set.  */
+   if (compute_reachability_set (ai->escape_solution))
+     {
+       any_pt_anything = true;
+       pt_anything_mask |= ESCAPE_TO_CALL | ESCAPE_STORED_IN_GLOBAL;
+     }
+   else
+     clobber_set (ai->escape_solution, (ESCAPE_TO_CALL
+ 				       | ESCAPE_STORED_IN_GLOBAL));
+ 
    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
*** 561,578 ****
  
  	  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
--- 623,628 ----
*************** done:
*** 1602,1607 ****
--- 1652,1971 ----
    timevar_pop (TV_MEMORY_PARTITIONING);
  }
  
+ /* Process a single escaped argument ARG.  */
+ 
+ static void
+ process_escape (tree arg, struct alias_info *ai)
+ {
+   tree base = arg;
+ 
+   while (handled_component_p (base)
+ 	 || TREE_CODE (base) == WITH_SIZE_EXPR)
+     base = TREE_OPERAND (base, 0);
+ 
+   /* For pointer de-references we have to make all pointed-to
+      pointers escape.  */
+   if (INDIRECT_REF_P (base)
+       && could_have_pointers (base))
+     union_what_p_points_to_indirect (ai->escape_solution,
+ 				     TREE_OPERAND (arg, 0));
+   /* For aggregates that contain pointers we would need only mark the
+      sub-aggregate contained pointers escape.  */
+   else if (DECL_P (base)
+ 	   && could_have_pointers (base))
+     union_what_p_points_to (ai->escape_solution, base);
+ }
+ 
+ /* Update related alias information kept in AI.  This is used when
+    building name tags, alias sets and deciding grouping heuristics.
+    STMT is the statement to process.  This function also updates
+    ADDRESSABLE_VARS.  */
+ 
+ static void
+ update_alias_info (tree stmt, struct alias_info *ai)
+ {
+   bitmap addr_taken;
+   use_operand_p use_p;
+   ssa_op_iter iter;
+   bool stmt_dereferences_ptr_p;
+   enum escape_type stmt_escape_type = is_escape_site (stmt);
+   struct mem_ref_stats_d *mem_ref_stats = gimple_mem_ref_stats (cfun);
+ 
+   stmt_dereferences_ptr_p = false;
+ 
+   if (stmt_escape_type == ESCAPE_TO_CALL
+       || stmt_escape_type == ESCAPE_TO_PURE_CONST)
+     {
+       mem_ref_stats->num_call_sites++;
+       if (stmt_escape_type == ESCAPE_TO_PURE_CONST)
+ 	mem_ref_stats->num_pure_const_call_sites++;
+     }
+   else if (stmt_escape_type == ESCAPE_TO_ASM)
+     mem_ref_stats->num_asm_sites++;
+ 
+   /* 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 (stmt_escape_type & ~(ESCAPE_TO_RETURN|ESCAPE_TO_PURE_CONST))
+ 		union_what_p_points_to (ai->escape_solution, rvar);
+ 	      if (!unmodifiable_var_p (rvar))
+ 		mark_call_clobbered (rvar, stmt_escape_type);
+ 	    }
+ 	}
+     }
+ 
+   /* Deal with escape statements where we need to mark memory
+      objects as escaped.  */
+   if (stmt_escape_type == ESCAPE_TO_CALL)
+     {
+       tree call = get_call_expr_in (stmt);
+       call_expr_arg_iterator iter;
+       tree arg;
+ 
+       FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
+ 	process_escape (arg, ai);
+     }
+   else if (stmt_escape_type == ESCAPE_STORED_IN_GLOBAL
+ 	   && TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
+     process_escape (GIMPLE_STMT_OPERAND (stmt, 1), ai);
+ 
+   /* Process each operand use.  For pointers, determine whether they
+      are dereferenced by the statement, or whether their value
+      escapes, etc.  */
+   FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
+     {
+       tree op, var;
+       var_ann_t v_ann;
+       struct ptr_info_def *pi;
+       unsigned num_uses, num_loads, num_stores;
+ 
+       op = USE_FROM_PTR (use_p);
+ 
+       /* If STMT is a PHI node, OP may be an ADDR_EXPR.  If so, add it
+ 	 to the set of addressable variables.  */
+       if (TREE_CODE (op) == ADDR_EXPR)
+ 	{
+ 	  bitmap addressable_vars = gimple_addressable_vars (cfun);
+ 
+ 	  gcc_assert (TREE_CODE (stmt) == PHI_NODE);
+ 	  gcc_assert (addressable_vars);
+ 
+ 	  /* PHI nodes don't have annotations for pinning the set
+ 	     of addresses taken, so we collect them here.
+ 
+ 	     FIXME, should we allow PHI nodes to have annotations
+ 	     so that they can be treated like regular statements?
+ 	     Currently, they are treated as second-class
+ 	     statements.  */
+ 	  add_to_addressable_set (TREE_OPERAND (op, 0), &addressable_vars);
+ 	  continue;
+ 	}
+ 
+       /* Ignore constants (they may occur in PHI node arguments).  */
+       if (TREE_CODE (op) != SSA_NAME)
+ 	continue;
+ 
+       var = SSA_NAME_VAR (op);
+       v_ann = var_ann (var);
+ 
+       /* The base variable of an SSA name must be a GIMPLE register, and thus
+ 	 it cannot be aliased.  */
+       gcc_assert (!may_be_aliased (var));
+ 
+       /* We are only interested in pointers.  */
+       if (!POINTER_TYPE_P (TREE_TYPE (op)))
+ 	continue;
+ 
+       pi = get_ptr_info (op);
+ 
+       /* Add OP to AI->PROCESSED_PTRS, if it's not there already.  */
+       if (!TEST_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op)))
+ 	{
+ 	  SET_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op));
+ 	  VEC_safe_push (tree, heap, ai->processed_ptrs, op);
+ 	}
+ 
+       /* If STMT is a PHI node, then it will not have pointer
+ 	 dereferences and it will not be an escape point.  */
+       if (TREE_CODE (stmt) == PHI_NODE)
+ 	continue;
+ 
+       /* Determine whether OP is a dereferenced pointer, and if STMT
+ 	 is an escape point, whether OP escapes.  */
+       count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores);
+ 
+       /* Handle a corner case involving address expressions of the
+ 	 form '&PTR->FLD'.  The problem with these expressions is that
+ 	 they do not represent a dereference of PTR.  However, if some
+ 	 other transformation propagates them into an INDIRECT_REF
+ 	 expression, we end up with '*(&PTR->FLD)' which is folded
+ 	 into 'PTR->FLD'.
+ 
+ 	 So, if the original code had no other dereferences of PTR,
+ 	 the aliaser will not create memory tags for it, and when
+ 	 &PTR->FLD gets propagated to INDIRECT_REF expressions, the
+ 	 memory operations will receive no VDEF/VUSE operands.
+ 
+ 	 One solution would be to have count_uses_and_derefs consider
+ 	 &PTR->FLD a dereference of PTR.  But that is wrong, since it
+ 	 is not really a dereference but an offset calculation.
+ 
+ 	 What we do here is to recognize these special ADDR_EXPR
+ 	 nodes.  Since these expressions are never GIMPLE values (they
+ 	 are not GIMPLE invariants), they can only appear on the RHS
+ 	 of an assignment and their base address is always an
+ 	 INDIRECT_REF expression.  */
+       if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
+ 	  && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == ADDR_EXPR
+ 	  && !is_gimple_val (GIMPLE_STMT_OPERAND (stmt, 1)))
+ 	{
+ 	  /* If the RHS if of the form &PTR->FLD and PTR == OP, then
+ 	     this represents a potential dereference of PTR.  */
+ 	  tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
+ 	  tree base = get_base_address (TREE_OPERAND (rhs, 0));
+ 	  if (TREE_CODE (base) == INDIRECT_REF
+ 	      && TREE_OPERAND (base, 0) == op)
+ 	    num_loads++;
+ 	}
+ 
+       if (num_loads + num_stores > 0)
+ 	{
+ 	  /* Mark OP as dereferenced.  In a subsequent pass,
+ 	     dereferenced pointers that point to a set of
+ 	     variables will be assigned a name tag to alias
+ 	     all the variables OP points to.  */
+ 	  pi->is_dereferenced = 1;
+ 
+ 	  /* If this is a store operation, mark OP as being
+ 	     dereferenced to store, otherwise mark it as being
+ 	     dereferenced to load.  */
+ 	  if (num_stores > 0)
+ 	    pointer_set_insert (ai->dereferenced_ptrs_store, var);
+ 	  else
+ 	    pointer_set_insert (ai->dereferenced_ptrs_load, var);
+ 
+ 	  /* Update the frequency estimate for all the dereferences of
+ 	     pointer OP.  */
+ 	  update_mem_sym_stats_from_stmt (op, stmt, num_loads, num_stores);
+ 
+ 	  /* Indicate that STMT contains pointer dereferences.  */
+ 	  stmt_dereferences_ptr_p = true;
+ 	}
+ 
+       if (stmt_escape_type != NO_ESCAPE && num_loads + num_stores < num_uses)
+ 	{
+ 	  /* If STMT is an escape point and STMT contains at
+ 	     least one direct use of OP, then the value of OP
+ 	     escapes and so the pointed-to variables need to
+ 	     be marked call-clobbered.  */
+ 	  pi->value_escapes_p = 1;
+ 	  pi->escape_mask |= stmt_escape_type;
+ 
+ 	  /* If the statement makes a function call, assume
+ 	     that pointer OP will be dereferenced in a store
+ 	     operation inside the called function.  */
+ 	  if (get_call_expr_in (stmt)
+ 	      || stmt_escape_type == ESCAPE_STORED_IN_GLOBAL)
+ 	    {
+ 	      pointer_set_insert (ai->dereferenced_ptrs_store, var);
+ 	      pi->is_dereferenced = 1;
+ 	    }
+ 	}
+     }
+ 
+   if (TREE_CODE (stmt) == PHI_NODE)
+     return;
+ 
+   /* Mark stored variables in STMT as being written to and update the
+      memory reference stats for all memory symbols referenced by STMT.  */
+   if (stmt_references_memory_p (stmt))
+     {
+       unsigned i;
+       bitmap_iterator bi;
+ 
+       mem_ref_stats->num_mem_stmts++;
+ 
+       /* Notice that we only update memory reference stats for symbols
+ 	 loaded and stored by the statement if the statement does not
+ 	 contain pointer dereferences and it is not a call/asm site.
+ 	 This is to avoid double accounting problems when creating
+ 	 memory partitions.  After computing points-to information,
+ 	 pointer dereference statistics are used to update the
+ 	 reference stats of the pointed-to variables, so here we
+ 	 should only update direct references to symbols.
+ 
+ 	 Indirect references are not updated here for two reasons: (1)
+ 	 The first time we compute alias information, the sets
+ 	 LOADED/STORED are empty for pointer dereferences, (2) After
+ 	 partitioning, LOADED/STORED may have references to
+ 	 partitions, not the original pointed-to variables.  So, if we
+ 	 always counted LOADED/STORED here and during partitioning, we
+ 	 would count many symbols more than once.
+ 
+ 	 This does cause some imprecision when a statement has a
+ 	 combination of direct symbol references and pointer
+ 	 dereferences (e.g., MEMORY_VAR = *PTR) or if a call site has
+ 	 memory symbols in its argument list, but these cases do not
+ 	 occur so frequently as to constitute a serious problem.  */
+       if (STORED_SYMS (stmt))
+ 	EXECUTE_IF_SET_IN_BITMAP (STORED_SYMS (stmt), 0, i, bi)
+ 	  {
+ 	    tree sym = referenced_var (i);
+ 	    pointer_set_insert (ai->written_vars, sym);
+ 	    if (!stmt_dereferences_ptr_p
+ 		&& stmt_escape_type != ESCAPE_TO_CALL
+ 		&& stmt_escape_type != ESCAPE_TO_PURE_CONST
+ 		&& stmt_escape_type != ESCAPE_TO_ASM)
+ 	      update_mem_sym_stats_from_stmt (sym, stmt, 0, 1);
+ 	  }
+ 
+       if (!stmt_dereferences_ptr_p
+ 	  && LOADED_SYMS (stmt)
+ 	  && stmt_escape_type != ESCAPE_TO_CALL
+ 	  && stmt_escape_type != ESCAPE_TO_PURE_CONST
+ 	  && stmt_escape_type != ESCAPE_TO_ASM)
+ 	EXECUTE_IF_SET_IN_BITMAP (LOADED_SYMS (stmt), 0, i, bi)
+ 	  update_mem_sym_stats_from_stmt (referenced_var (i), stmt, 1, 0);
+     }
+ }
+ 
+ 
+ /* Update various related attributes like escaped addresses, pointer
+    dereferences for loads and stores.  This is used when creating
+    name tags and alias sets.  */
+ 
+ static void
+ compute_escape_set (struct alias_info *ai)
+ {
+   basic_block bb;
+ 
+   FOR_EACH_BB (bb)
+     {
+       block_stmt_iterator bsi;
+       tree phi;
+ 
+       for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+ 	if (is_gimple_reg (PHI_RESULT (phi)))
+ 	  update_alias_info (phi, ai);
+ 
+       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ 	update_alias_info (bsi_stmt (bsi), ai);
+     }
+ }
+ 
  
  /* Compute may-alias information for every variable referenced in function
     FNDECL.
*************** compute_may_aliases (void)
*** 1726,1736 ****
    ai = init_alias_info ();
  
    /* For each pointer P_i, determine the sets of variables that P_i may
!      point-to.  For every addressable variable V, determine whether the
       address of V escapes the current function, making V call-clobbered
       (i.e., whether &V is stored in a global variable or if its passed as a
       function call argument).  */
!   compute_points_to_sets (ai);
  
    /* Collect all pointers and addressable variables, compute alias sets,
       create memory tags for pointers and promote variables whose address is
--- 2090,2103 ----
    ai = init_alias_info ();
  
    /* For each pointer P_i, determine the sets of variables that P_i may
!      point-to.  */
!   compute_points_to_sets ();
! 
!   /* For every addressable variable V, determine whether the
       address of V escapes the current function, making V call-clobbered
       (i.e., whether &V is stored in a global variable or if its passed as a
       function call argument).  */
!   compute_escape_set (ai);
  
    /* Collect all pointers and addressable variables, compute alias sets,
       create memory tags for pointers and promote variables whose address is
*************** init_alias_info (void)
*** 2077,2082 ****
--- 2444,2450 ----
    ai->written_vars = pointer_set_create ();
    ai->dereferenced_ptrs_store = pointer_set_create ();
    ai->dereferenced_ptrs_load = pointer_set_create ();
+   ai->escape_solution = BITMAP_ALLOC (NULL);
  
    /* Clear out all memory reference stats.  */
    init_mem_ref_stats ();
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;
*************** do_structure_copy (tree lhsop, tree rhso
*** 3255,3510 ****
  }
  
  
- /* Update related alias information kept in AI.  This is used when
-    building name tags, alias sets and deciding grouping heuristics.
-    STMT is the statement to process.  This function also updates
-    ADDRESSABLE_VARS.  */
- 
- static void
- update_alias_info (tree stmt, struct alias_info *ai)
- {
-   bitmap addr_taken;
-   use_operand_p use_p;
-   ssa_op_iter iter;
-   bool stmt_dereferences_ptr_p;
-   enum escape_type stmt_escape_type = is_escape_site (stmt);
-   struct mem_ref_stats_d *mem_ref_stats = gimple_mem_ref_stats (cfun);
- 
-   stmt_dereferences_ptr_p = false;
- 
-   if (stmt_escape_type == ESCAPE_TO_CALL
-       || stmt_escape_type == ESCAPE_TO_PURE_CONST)
-     {
-       mem_ref_stats->num_call_sites++;
-       if (stmt_escape_type == ESCAPE_TO_PURE_CONST)
- 	mem_ref_stats->num_pure_const_call_sites++;
-     }
-   else if (stmt_escape_type == ESCAPE_TO_ASM)
-     mem_ref_stats->num_asm_sites++;
- 
-   /* 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
-      escapes, etc.  */
-   FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
-     {
-       tree op, var;
-       var_ann_t v_ann;
-       struct ptr_info_def *pi;
-       unsigned num_uses, num_loads, num_stores;
- 
-       op = USE_FROM_PTR (use_p);
- 
-       /* If STMT is a PHI node, OP may be an ADDR_EXPR.  If so, add it
- 	 to the set of addressable variables.  */
-       if (TREE_CODE (op) == ADDR_EXPR)
- 	{
- 	  bitmap addressable_vars = gimple_addressable_vars (cfun);
- 
- 	  gcc_assert (TREE_CODE (stmt) == PHI_NODE);
- 	  gcc_assert (addressable_vars);
- 
- 	  /* PHI nodes don't have annotations for pinning the set
- 	     of addresses taken, so we collect them here.
- 
- 	     FIXME, should we allow PHI nodes to have annotations
- 	     so that they can be treated like regular statements?
- 	     Currently, they are treated as second-class
- 	     statements.  */
- 	  add_to_addressable_set (TREE_OPERAND (op, 0), &addressable_vars);
- 	  continue;
- 	}
- 
-       /* Ignore constants (they may occur in PHI node arguments).  */
-       if (TREE_CODE (op) != SSA_NAME)
- 	continue;
- 
-       var = SSA_NAME_VAR (op);
-       v_ann = var_ann (var);
- 
-       /* The base variable of an SSA name must be a GIMPLE register, and thus
- 	 it cannot be aliased.  */
-       gcc_assert (!may_be_aliased (var));
- 
-       /* We are only interested in pointers.  */
-       if (!POINTER_TYPE_P (TREE_TYPE (op)))
- 	continue;
- 
-       pi = get_ptr_info (op);
- 
-       /* Add OP to AI->PROCESSED_PTRS, if it's not there already.  */
-       if (!TEST_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op)))
- 	{
- 	  SET_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op));
- 	  VEC_safe_push (tree, heap, ai->processed_ptrs, op);
- 	}
- 
-       /* If STMT is a PHI node, then it will not have pointer
- 	 dereferences and it will not be an escape point.  */
-       if (TREE_CODE (stmt) == PHI_NODE)
- 	continue;
- 
-       /* Determine whether OP is a dereferenced pointer, and if STMT
- 	 is an escape point, whether OP escapes.  */
-       count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores);
- 
-       /* Handle a corner case involving address expressions of the
- 	 form '&PTR->FLD'.  The problem with these expressions is that
- 	 they do not represent a dereference of PTR.  However, if some
- 	 other transformation propagates them into an INDIRECT_REF
- 	 expression, we end up with '*(&PTR->FLD)' which is folded
- 	 into 'PTR->FLD'.
- 
- 	 So, if the original code had no other dereferences of PTR,
- 	 the aliaser will not create memory tags for it, and when
- 	 &PTR->FLD gets propagated to INDIRECT_REF expressions, the
- 	 memory operations will receive no VDEF/VUSE operands.
- 
- 	 One solution would be to have count_uses_and_derefs consider
- 	 &PTR->FLD a dereference of PTR.  But that is wrong, since it
- 	 is not really a dereference but an offset calculation.
- 
- 	 What we do here is to recognize these special ADDR_EXPR
- 	 nodes.  Since these expressions are never GIMPLE values (they
- 	 are not GIMPLE invariants), they can only appear on the RHS
- 	 of an assignment and their base address is always an
- 	 INDIRECT_REF expression.  */
-       if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
- 	  && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == ADDR_EXPR
- 	  && !is_gimple_val (GIMPLE_STMT_OPERAND (stmt, 1)))
- 	{
- 	  /* If the RHS if of the form &PTR->FLD and PTR == OP, then
- 	     this represents a potential dereference of PTR.  */
- 	  tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
- 	  tree base = get_base_address (TREE_OPERAND (rhs, 0));
- 	  if (TREE_CODE (base) == INDIRECT_REF
- 	      && TREE_OPERAND (base, 0) == op)
- 	    num_loads++;
- 	}
- 
-       if (num_loads + num_stores > 0)
- 	{
- 	  /* Mark OP as dereferenced.  In a subsequent pass,
- 	     dereferenced pointers that point to a set of
- 	     variables will be assigned a name tag to alias
- 	     all the variables OP points to.  */
- 	  pi->is_dereferenced = 1;
- 
- 	  /* If this is a store operation, mark OP as being
- 	     dereferenced to store, otherwise mark it as being
- 	     dereferenced to load.  */
- 	  if (num_stores > 0)
- 	    pointer_set_insert (ai->dereferenced_ptrs_store, var);
- 	  else
- 	    pointer_set_insert (ai->dereferenced_ptrs_load, var);
- 
- 	  /* Update the frequency estimate for all the dereferences of
- 	     pointer OP.  */
- 	  update_mem_sym_stats_from_stmt (op, stmt, num_loads, num_stores);
- 
- 	  /* Indicate that STMT contains pointer dereferences.  */
- 	  stmt_dereferences_ptr_p = true;
- 	}
- 
-       if (stmt_escape_type != NO_ESCAPE && num_loads + num_stores < num_uses)
- 	{
- 	  /* If STMT is an escape point and STMT contains at
- 	     least one direct use of OP, then the value of OP
- 	     escapes and so the pointed-to variables need to
- 	     be marked call-clobbered.  */
- 	  pi->value_escapes_p = 1;
- 	  pi->escape_mask |= stmt_escape_type;
- 
- 	  /* If the statement makes a function call, assume
- 	     that pointer OP will be dereferenced in a store
- 	     operation inside the called function.  */
- 	  if (get_call_expr_in (stmt)
- 	      || stmt_escape_type == ESCAPE_STORED_IN_GLOBAL)
- 	    {
- 	      pointer_set_insert (ai->dereferenced_ptrs_store, var);
- 	      pi->is_dereferenced = 1;
- 	    }
- 	}
-     }
- 
-   if (TREE_CODE (stmt) == PHI_NODE)
-     return;
- 
-   /* Mark stored variables in STMT as being written to and update the
-      memory reference stats for all memory symbols referenced by STMT.  */
-   if (stmt_references_memory_p (stmt))
-     {
-       unsigned i;
-       bitmap_iterator bi;
- 
-       mem_ref_stats->num_mem_stmts++;
- 
-       /* Notice that we only update memory reference stats for symbols
- 	 loaded and stored by the statement if the statement does not
- 	 contain pointer dereferences and it is not a call/asm site.
- 	 This is to avoid double accounting problems when creating
- 	 memory partitions.  After computing points-to information,
- 	 pointer dereference statistics are used to update the
- 	 reference stats of the pointed-to variables, so here we
- 	 should only update direct references to symbols.
- 
- 	 Indirect references are not updated here for two reasons: (1)
- 	 The first time we compute alias information, the sets
- 	 LOADED/STORED are empty for pointer dereferences, (2) After
- 	 partitioning, LOADED/STORED may have references to
- 	 partitions, not the original pointed-to variables.  So, if we
- 	 always counted LOADED/STORED here and during partitioning, we
- 	 would count many symbols more than once.
- 
- 	 This does cause some imprecision when a statement has a
- 	 combination of direct symbol references and pointer
- 	 dereferences (e.g., MEMORY_VAR = *PTR) or if a call site has
- 	 memory symbols in its argument list, but these cases do not
- 	 occur so frequently as to constitute a serious problem.  */
-       if (STORED_SYMS (stmt))
- 	EXECUTE_IF_SET_IN_BITMAP (STORED_SYMS (stmt), 0, i, bi)
- 	  {
- 	    tree sym = referenced_var (i);
- 	    pointer_set_insert (ai->written_vars, sym);
- 	    if (!stmt_dereferences_ptr_p
- 		&& stmt_escape_type != ESCAPE_TO_CALL
- 		&& stmt_escape_type != ESCAPE_TO_PURE_CONST
- 		&& stmt_escape_type != ESCAPE_TO_ASM)
- 	      update_mem_sym_stats_from_stmt (sym, stmt, 0, 1);
- 	  }
- 
-       if (!stmt_dereferences_ptr_p
- 	  && LOADED_SYMS (stmt)
- 	  && stmt_escape_type != ESCAPE_TO_CALL
- 	  && stmt_escape_type != ESCAPE_TO_PURE_CONST
- 	  && stmt_escape_type != ESCAPE_TO_ASM)
- 	EXECUTE_IF_SET_IN_BITMAP (LOADED_SYMS (stmt), 0, i, bi)
- 	  update_mem_sym_stats_from_stmt (referenced_var (i), stmt, 1, 0);
-     }
- }
- 
- 
  /* Handle pointer arithmetic EXPR when creating aliasing constraints.
     Expressions of the type PTR + CST can be handled in two ways:
  
--- 3268,3273 ----
*************** 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
*************** find_what_p_points_to (tree p)
*** 4887,4907 ****
    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.  */
--- 4653,4707 ----
    return false;
  }
  
! /* Union the points-to solution for P into the solution bitmap INTO.
!    Returns true if anything_id or integer_id are in the final INTO.  */
  
  bool
! union_what_p_points_to (bitmap into, tree p)
! {
!   tree lookup_p = p;
!   varinfo_t vi;
! 
!   gcc_assert (have_alias_info);
! 
!   /* 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);
! 
!   /* This variable may have been collapsed, let's get the real
!      variable.  */
!   vi = get_varinfo (find (vi->id));
! 
!   bitmap_ior_into (into, vi->solution);
! 
!   return (bitmap_bit_p (into, anything_id)
! 	  || bitmap_bit_p (into, integer_id));
! }
! 
! /* Union the points-to solution for what is reachable form the memory
!    pointed to by P into the solution bitmap INTO.
!    Returns true if anything_id or integer_id are in the final INTO.  */
! 
! bool
! union_what_p_points_to_indirect (bitmap into, tree p)
  {
    tree lookup_p = p;
    varinfo_t vi;
    unsigned int i;
    bitmap_iterator bi;
  
!   gcc_assert (have_alias_info);
  
    /* For parameters, get at the points-to set for the actual parm
       decl.  */
*************** clobber_what_p_points_to (tree p)
*** 4918,4932 ****
    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)
      {
        varinfo_t vi = get_varinfo (i);
  
        if (vi->is_artificial_var)
--- 4718,4799 ----
    gcc_assert (!vi->is_artificial_var
  	      && vi->size == vi->fullsize);
  
    /* This variable may have been collapsed, let's get the real
       variable.  */
    vi = get_varinfo (find (vi->id));
  
!   /* Now don't add the solution of P, but only those from what P
!      points to.  */
    EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
      {
+       varinfo_t vi2 = get_varinfo (i);
+ 
+       /* If i is not the representative, skip it.  */
+       vi2 = get_varinfo (find (vi2->id));
+       if (vi2->id != i)
+ 	continue;
+ 
+       bitmap_ior_into (into, vi2->solution);
+     }
+ 
+   return (bitmap_bit_p (into, anything_id)
+ 	  || bitmap_bit_p (into, integer_id));
+ }
+ 
+ /* Compute the reachability set of the points-to solution SOLUTION
+    and store it in the bitmap SOLUTION.  Returns true if anything_id
+    or integer_id are in the solution.  */
+ 
+ bool
+ compute_reachability_set (bitmap solution)
+ {
+   bool changed;
+   bitmap worklist, oldsolution;
+ 
+   worklist = BITMAP_ALLOC (NULL);
+   oldsolution = BITMAP_ALLOC (NULL);
+ 
+   do
+     {
+       unsigned int i;
+       bitmap_iterator bi;
+       changed = false;
+ 
+       if (bitmap_bit_p (solution, anything_id)
+ 	  || bitmap_bit_p (solution, integer_id))
+ 	return true;
+ 
+       bitmap_xor (worklist, oldsolution, solution);
+       bitmap_copy (oldsolution, solution);
+ 
+       EXECUTE_IF_SET_IN_BITMAP (worklist, 0, i, bi)
+ 	{
+ 	  varinfo_t vi = get_varinfo (i);
+ 
+ 	  /* If i is not the representative, skip it.  */
+ 	  vi = get_varinfo (find (vi->id));
+ 	  if (vi->id != i)
+ 	    continue;
+ 
+ 	  changed |= bitmap_ior_into (solution, vi->solution);
+ 	}
+     }
+   while (changed);
+ 
+   return false;
+ }
+ 
+ /* Clobber the points-to set SOLUTION with the escape reason ESCAPE_MASK.  */
+ 
+ bool
+ clobber_set (bitmap solution, enum escape_type escape_mask)
+ {
+   unsigned int i;
+   bitmap_iterator bi;
+ 
+   /* Mark variables in the solution call-clobbered.  */
+   EXECUTE_IF_SET_IN_BITMAP (solution, 0, i, bi)
+     {
        varinfo_t vi = get_varinfo (i);
  
        if (vi->is_artificial_var)
*************** clobber_what_p_points_to (tree p)
*** 4947,4958 ****
  	   || 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
--- 4814,4826 ----
  	   || TREE_CODE (vi->decl) == PARM_DECL
  	   || TREE_CODE (vi->decl) == RESULT_DECL)
  	  && !unmodifiable_var_p (vi->decl))
! 	mark_call_clobbered (vi->decl, escape_mask);
      }
  
    return true;
  }
  
+ 
  /* Dump points-to information to OUTFILE.  */
  
  void
*************** compute_tbaa_pruning (void)
*** 5290,5296 ****
     at the start of the file for an algorithmic overview.  */
  
  void
! compute_points_to_sets (struct alias_info *ai)
  {
    struct scc_info *si;
    basic_block bb;
--- 5158,5164 ----
     at the start of the file for an algorithmic overview.  */
  
  void
! compute_points_to_sets (void)
  {
    struct scc_info *si;
    basic_block bb;
*************** compute_points_to_sets (struct alias_inf
*** 5311,5325 ****
        for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
  	{
  	  if (is_gimple_reg (PHI_RESULT (phi)))
! 	    {
! 	      find_func_aliases (phi);
! 
! 	      /* Update various related attributes like escaped
! 		 addresses, pointer dereferences for loads and stores.
! 		 This is used when creating name tags and alias
! 		 sets.  */
! 	      update_alias_info (phi, ai);
! 	    }
  	}
  
        for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
--- 5179,5185 ----
        for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
  	{
  	  if (is_gimple_reg (PHI_RESULT (phi)))
! 	    find_func_aliases (phi);
  	}
  
        for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
*************** compute_points_to_sets (struct alias_inf
*** 5328,5339 ****
  
  	  find_func_aliases (stmt);
  
- 	  /* Update various related attributes like escaped
- 	     addresses, pointer dereferences for loads and stores.
- 	     This is used when creating name tags and alias
- 	     sets.  */
- 	  update_alias_info (stmt, ai);
- 
  	  /* The information in CHANGE_DYNAMIC_TYPE_EXPR nodes has now
  	     been captured, and we can remove them.  */
  	  if (TREE_CODE (stmt) == CHANGE_DYNAMIC_TYPE_EXPR)
--- 5188,5193 ----
*************** compute_points_to_sets (struct alias_inf
*** 5343,5349 ****
  	}
      }
  
- 
    if (dump_file)
      {
        fprintf (dump_file, "Points-to analysis\n\nConstraints:\n\n");
--- 5197,5202 ----
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-05-30 22:19:06.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-05-30 22:19:06.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-05-30 22:19:06.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-05-30 22:19:06.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-05-30 22:19:06.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/tree-flow.h
===================================================================
*** trunk.orig/gcc/tree-flow.h	2008-05-30 21:56:26.000000000 +0200
--- trunk/gcc/tree-flow.h	2008-05-30 22:19:06.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,1176 ----
  
  /* In tree-ssa-structalias.c */
  bool find_what_p_points_to (tree);
! bool union_what_p_points_to (bitmap, tree);
! bool union_what_p_points_to_indirect (bitmap, tree);
! bool compute_reachability_set (bitmap);
! bool clobber_set (bitmap, enum escape_type);
  
  /* In tree-ssa-live.c */
  extern void remove_unused_locals (void);
Index: trunk/gcc/tree-ssa-structalias.h
===================================================================
*** trunk.orig/gcc/tree-ssa-structalias.h	2008-05-30 21:56:26.000000000 +0200
--- trunk/gcc/tree-ssa-structalias.h	2008-05-30 22:19:06.000000000 +0200
***************
*** 24,67 ****
  struct constraint;
  typedef struct constraint *constraint_t;
  
- /* Alias information used by compute_may_aliases and its helpers.  */
- struct alias_info
- {
-   /* SSA names visited while collecting points-to information.  If bit I
-      is set, it means that SSA variable with version I has already been
-      visited.  */
-   sbitmap ssa_names_visited;
- 
-   /* Array of SSA_NAME pointers processed by the points-to collector.  */
-   VEC(tree,heap) *processed_ptrs;
- 
-   /* ADDRESSABLE_VARS contains all the global variables and locals that
-      have had their address taken.  */
-   struct alias_map_d **addressable_vars;
-   size_t num_addressable_vars;
- 
-   /* POINTERS contains all the _DECL pointers with unique memory tags
-      that have been referenced in the program.  */
-   struct alias_map_d **pointers;
-   size_t num_pointers;
- 
-   /* Variables that have been written to directly (i.e., not through a
-      pointer dereference).  */
-   struct pointer_set_t *written_vars;
- 
-   /* Pointers that have been used in an indirect store operation.  */
-   struct pointer_set_t *dereferenced_ptrs_store;
- 
-   /* Pointers that have been used in an indirect load operation.  */
-   struct pointer_set_t *dereferenced_ptrs_load;
- };
- 
  /* In tree-ssa-alias.c.  */
  enum escape_type is_escape_site (tree);
  void update_mem_sym_stats_from_stmt (tree, tree, long, long);
  
  /* In tree-ssa-structalias.c.  */
! extern void compute_points_to_sets (struct alias_info *);
  extern void delete_points_to_sets (void);
  extern void dump_constraint (FILE *, constraint_t);
  extern void dump_constraints (FILE *);
--- 24,35 ----
  struct constraint;
  typedef struct constraint *constraint_t;
  
  /* In tree-ssa-alias.c.  */
  enum escape_type is_escape_site (tree);
  void update_mem_sym_stats_from_stmt (tree, tree, long, long);
  
  /* In tree-ssa-structalias.c.  */
! extern void compute_points_to_sets (void);
  extern void delete_points_to_sets (void);
  extern void dump_constraint (FILE *, constraint_t);
  extern void dump_constraints (FILE *);
*************** extern void debug_solution_for_var (unsi
*** 72,76 ****
--- 40,45 ----
  extern void dump_sa_points_to_info (FILE *);
  extern void debug_sa_points_to_info (void);
  extern void set_used_smts (void);
+ extern bool could_have_pointers (tree);
  
  #endif /* TREE_SSA_STRUCTALIAS_H  */
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-05-30 22:19:06.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-05-30 22:19:06.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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]