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][RFC] Make pure/const call clobber analysis context-sensitive


This uses the context sensitive information on call statements to
provide finer granularity for pure and const function calls.

Lightly tested sofar, but nothing non-obvious.  Queued for stage1.

Richard.

2009-11-19  Richard Guenther  <rguenther@suse.de>

	* tree-ssa-structalias.c (callused_id): Remove.
	(call_stmt_vars): New.
	(get_call_vi): Likewise.
	(lookup_call_use_vi): Likewise.
	(lookup_call_clobber_vi): Likewise.
	(get_call_use_vi): Likewise.
	(get_call_clobber_vi): Likewise.
	(make_transitive_closure_constraints): Likewise.
	(handle_const_call): Adjust to do per-call call-used handling.
	(handle_pure_call): Likewise.
	(find_what_var_points_to): Remove general callused handling.
	(init_base_vars): Likewise.
	(init_alias_vars): Initialize call_stmt_vars.
	(compute_points_to_sets): Process call-used and call-clobbered
	vars for call statements.
	(delete_points_to_sets): Free call_stmt_vars.

Index: trunk/gcc/tree-ssa-structalias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-structalias.c	2009-11-19 13:55:23.000000000 +0100
--- trunk/gcc/tree-ssa-structalias.c	2009-11-19 16:40:09.000000000 +0100
*************** get_varinfo (unsigned int n)
*** 287,294 ****
  
  /* Static IDs for the special variables.  */
  enum { nothing_id = 0, anything_id = 1, readonly_id = 2,
!        escaped_id = 3, nonlocal_id = 4, callused_id = 5,
!        storedanything_id = 6, integer_id = 7 };
  
  struct GTY(()) heapvar_map {
    struct tree_map map;
--- 287,294 ----
  
  /* Static IDs for the special variables.  */
  enum { nothing_id = 0, anything_id = 1, readonly_id = 2,
!        escaped_id = 3, nonlocal_id = 4,
!        storedanything_id = 5, integer_id = 6 };
  
  struct GTY(()) heapvar_map {
    struct tree_map map;
*************** new_var_info (tree t, const char *name)
*** 378,383 ****
--- 378,463 ----
    return ret;
  }
  
+ 
+ /* A map mapping call statements to per-stmt variables for uses
+    and clobbers specific to the call.  */
+ struct pointer_map_t *call_stmt_vars;
+ 
+ /* Lookup or create the variable for the call statement CALL.  */
+ 
+ static varinfo_t
+ get_call_vi (gimple call)
+ {
+   void **slot_p;
+   varinfo_t vi, vi2;
+ 
+   slot_p = pointer_map_insert (call_stmt_vars, call);
+   if (*slot_p)
+     return (varinfo_t) *slot_p;
+ 
+   vi = new_var_info (NULL_TREE, "CALLUSED");
+   vi->offset = 0;
+   vi->size = 1;
+   vi->fullsize = 2;
+   vi->is_full_var = true;
+ 
+   vi->next = vi2 = new_var_info (NULL_TREE, "CALLCLOBBERED");
+   vi2->offset = 1;
+   vi2->size = 1;
+   vi2->fullsize = 2;
+   vi2->is_full_var = true;
+ 
+   *slot_p = (void *) vi;
+   return vi;
+ }
+ 
+ /* Lookup the variable for the call statement CALL representing
+    the uses.  Returns NULL if there is nothing special about this call.  */
+ 
+ static varinfo_t
+ lookup_call_use_vi (gimple call)
+ {
+   void **slot_p;
+ 
+   slot_p = pointer_map_contains (call_stmt_vars, call);
+   if (slot_p)
+     return (varinfo_t) *slot_p;
+ 
+   return NULL;
+ }
+ 
+ /* Lookup the variable for the call statement CALL representing
+    the clobbers.  Returns NULL if there is nothing special about this call.  */
+ 
+ static varinfo_t
+ lookup_call_clobber_vi (gimple call)
+ {
+   varinfo_t uses = lookup_call_use_vi (call);
+   if (!uses)
+     return NULL;
+ 
+   return uses->next;
+ }
+ 
+ /* Lookup or create the variable for the call statement CALL representing
+    the uses.  */
+ 
+ static varinfo_t
+ get_call_use_vi (gimple call)
+ {
+   return get_call_vi (call);
+ }
+ 
+ /* Lookup or create the variable for the call statement CALL representing
+    the clobbers.  */
+ 
+ static varinfo_t ATTRIBUTE_UNUSED
+ get_call_clobber_vi (gimple call)
+ {
+   return get_call_vi (call)->next;
+ }
+ 
+ 
  typedef enum {SCALAR, DEREF, ADDRESSOF} constraint_expr_type;
  
  /* An expression that appears in a constraint.  */
*************** make_escape_constraint (tree op)
*** 3381,3386 ****
--- 3461,3492 ----
    make_constraint_to (escaped_id, op);
  }
  
+ /* Add constraints to that the solution of VI is transitively closed.  */
+ 
+ static void
+ make_transitive_closure_constraints (varinfo_t vi)
+ {
+   struct constraint_expr lhs, rhs;
+ 
+   /* VAR = *VAR;  */
+   lhs.type = SCALAR;
+   lhs.var = vi->id;
+   lhs.offset = 0;
+   rhs.type = DEREF;
+   rhs.var = vi->id;
+   rhs.offset = 0;
+   process_constraint (new_constraint (lhs, rhs));
+ 
+   /* VAR = VAR + UNKNOWN;  */
+   lhs.type = SCALAR;
+   lhs.var = vi->id;
+   lhs.offset = 0;
+   rhs.type = SCALAR;
+   rhs.var = vi->id;
+   rhs.offset = UNKNOWN_OFFSET;
+   process_constraint (new_constraint (lhs, rhs));
+ }
+ 
  /* Create a new artificial heap variable with NAME and make a
     constraint from it to LHS.  Return the created variable.  */
  
*************** handle_const_call (gimple stmt, VEC(ce_s
*** 3536,3543 ****
       as the static chain is concerned.  */
    if (gimple_call_chain (stmt))
      {
!       make_constraint_to (callused_id, gimple_call_chain (stmt));
!       rhsc.var = callused_id;
        rhsc.offset = 0;
        rhsc.type = SCALAR;
        VEC_safe_push (ce_s, heap, *results, &rhsc);
--- 3642,3651 ----
       as the static chain is concerned.  */
    if (gimple_call_chain (stmt))
      {
!       varinfo_t uses = get_call_use_vi (stmt);
!       make_transitive_closure_constraints (uses);
!       make_constraint_to (uses->id, gimple_call_chain (stmt));
!       rhsc.var = uses->id;
        rhsc.offset = 0;
        rhsc.type = SCALAR;
        VEC_safe_push (ce_s, heap, *results, &rhsc);
*************** handle_pure_call (gimple stmt, VEC(ce_s,
*** 3575,3581 ****
  {
    struct constraint_expr rhsc;
    unsigned i;
!   bool need_callused = false;
  
    /* Memory reached from pointer arguments is call-used.  */
    for (i = 0; i < gimple_call_num_args (stmt); ++i)
--- 3683,3689 ----
  {
    struct constraint_expr rhsc;
    unsigned i;
!   varinfo_t uses = NULL;
  
    /* Memory reached from pointer arguments is call-used.  */
    for (i = 0; i < gimple_call_num_args (stmt); ++i)
*************** handle_pure_call (gimple stmt, VEC(ce_s,
*** 3584,3605 ****
  
        if (could_have_pointers (arg))
  	{
! 	  make_constraint_to (callused_id, arg);
! 	  need_callused = true;
  	}
      }
  
    /* The static chain is used as well.  */
    if (gimple_call_chain (stmt))
      {
!       make_constraint_to (callused_id, gimple_call_chain (stmt));
!       need_callused = true;
      }
  
!   /* Pure functions may return callused and nonlocal memory.  */
!   if (need_callused)
      {
!       rhsc.var = callused_id;
        rhsc.offset = 0;
        rhsc.type = SCALAR;
        VEC_safe_push (ce_s, heap, *results, &rhsc);
--- 3692,3721 ----
  
        if (could_have_pointers (arg))
  	{
! 	  if (!uses)
! 	    {
! 	      uses = get_call_use_vi (stmt);
! 	      make_transitive_closure_constraints (uses);
! 	    }
! 	  make_constraint_to (uses->id, arg);
  	}
      }
  
    /* The static chain is used as well.  */
    if (gimple_call_chain (stmt))
      {
!       if (!uses)
! 	{
! 	  uses = get_call_use_vi (stmt);
! 	  make_transitive_closure_constraints (uses);
! 	}
!       make_constraint_to (uses->id, gimple_call_chain (stmt));
      }
  
!   /* Pure functions may return call-used and nonlocal memory.  */
!   if (uses)
      {
!       rhsc.var = uses->id;
        rhsc.offset = 0;
        rhsc.type = SCALAR;
        VEC_safe_push (ce_s, heap, *results, &rhsc);
*************** find_func_aliases (gimple origt)
*** 4004,4011 ****
  	  if (!allows_reg && allows_mem)
  	    make_escape_constraint (build_fold_addr_expr (op));
  	  /* Strictly we'd only need the constraint to ESCAPED if
! 	     the asm clobbers memory, otherwise using CALLUSED
! 	     would be enough.  */
  	  else if (op && could_have_pointers (op))
  	    make_escape_constraint (op);
  	}
--- 4120,4127 ----
  	  if (!allows_reg && allows_mem)
  	    make_escape_constraint (build_fold_addr_expr (op));
  	  /* Strictly we'd only need the constraint to ESCAPED if
! 	     the asm clobbers memory, otherwise using something
! 	     along the lines of per-call clobbers/uses would be enough.  */
  	  else if (op && could_have_pointers (op))
  	    make_escape_constraint (op);
  	}
*************** find_what_var_points_to (varinfo_t vi, s
*** 4809,4816 ****
  	    pt->null = 1;
  	  else if (vi->id == escaped_id)
  	    pt->escaped = 1;
- 	  else if (vi->id == callused_id)
- 	    gcc_unreachable ();
  	  else if (vi->id == nonlocal_id)
  	    pt->nonlocal = 1;
  	  else if (vi->is_heap_var)
--- 4925,4930 ----
*************** init_base_vars (void)
*** 5136,5142 ****
    varinfo_t var_readonly;
    varinfo_t var_escaped;
    varinfo_t var_nonlocal;
-   varinfo_t var_callused;
    varinfo_t var_storedanything;
    varinfo_t var_integer;
  
--- 5250,5255 ----
*************** init_base_vars (void)
*** 5263,5297 ****
    rhs.offset = 0;
    process_constraint (new_constraint (lhs, rhs));
  
-   /* Create the CALLUSED variable, used to represent the set of call-used
-      memory.  */
-   var_callused = new_var_info (NULL_TREE, "CALLUSED");
-   gcc_assert (var_callused->id == callused_id);
-   var_callused->is_artificial_var = 1;
-   var_callused->offset = 0;
-   var_callused->size = ~0;
-   var_callused->fullsize = ~0;
-   var_callused->is_special_var = 0;
- 
-   /* CALLUSED = *CALLUSED, because call-used is may-deref'd at calls, etc.  */
-   lhs.type = SCALAR;
-   lhs.var = callused_id;
-   lhs.offset = 0;
-   rhs.type = DEREF;
-   rhs.var = callused_id;
-   rhs.offset = 0;
-   process_constraint (new_constraint (lhs, rhs));
- 
-   /* CALLUSED = CALLUSED + UNKNOWN, because if a sub-field is call-used the
-      whole variable is call-used.  */
-   lhs.type = SCALAR;
-   lhs.var = callused_id;
-   lhs.offset = 0;
-   rhs.type = SCALAR;
-   rhs.var = callused_id;
-   rhs.offset = UNKNOWN_OFFSET;
-   process_constraint (new_constraint (lhs, rhs));
- 
    /* Create the STOREDANYTHING variable, used to represent the set of
       variables stored to *ANYTHING.  */
    var_storedanything = new_var_info (NULL_TREE, "STOREDANYTHING");
--- 5376,5381 ----
*************** init_alias_vars (void)
*** 5342,5347 ****
--- 5426,5432 ----
    constraints = VEC_alloc (constraint_t, heap, 8);
    varmap = VEC_alloc (varinfo_t, heap, 8);
    vi_for_tree = pointer_map_create ();
+   call_stmt_vars = pointer_map_create ();
  
    memset (&stats, 0, sizeof (stats));
    shared_bitmap_table = htab_create (511, shared_bitmap_hash,
*************** compute_points_to_sets (void)
*** 5478,5484 ****
    basic_block bb;
    unsigned i;
    varinfo_t vi;
-   struct pt_solution callused;
  
    timevar_push (TV_TREE_PTA);
  
--- 5563,5568 ----
*************** compute_points_to_sets (void)
*** 5511,5521 ****
    /* From the constraints compute the points-to sets.  */
    solve_constraints ();
  
!   /* Compute the points-to sets for ESCAPED and CALLUSED used for
!      call-clobber analysis.  */
    find_what_var_points_to (get_varinfo (escaped_id),
  			   &cfun->gimple_df->escaped);
-   find_what_var_points_to (get_varinfo (callused_id), &callused);
  
    /* Make sure the ESCAPED solution (which is used as placeholder in
       other solutions) does not reference itself.  This simplifies
--- 5595,5603 ----
    /* From the constraints compute the points-to sets.  */
    solve_constraints ();
  
!   /* Compute the points-to set for ESCAPED used for call-clobber analysis.  */
    find_what_var_points_to (get_varinfo (escaped_id),
  			   &cfun->gimple_df->escaped);
  
    /* Make sure the ESCAPED solution (which is used as placeholder in
       other solutions) does not reference itself.  This simplifies
*************** compute_points_to_sets (void)
*** 5554,5564 ****
  	  pt = gimple_call_use_set (stmt);
  	  if (gimple_call_flags (stmt) & ECF_CONST)
  	    memset (pt, 0, sizeof (struct pt_solution));
! 	  else if (gimple_call_flags (stmt) & ECF_PURE)
  	    {
! 	      /* For const calls we should now be able to compute the
! 		 call-used set per function.  */
! 	      *pt = callused;
  	      /* ???  ESCAPED can be empty even though NONLOCAL
  		 always escaped.  */
  	      pt->nonlocal = 1;
--- 5636,5646 ----
  	  pt = gimple_call_use_set (stmt);
  	  if (gimple_call_flags (stmt) & ECF_CONST)
  	    memset (pt, 0, sizeof (struct pt_solution));
! 	  else if ((vi = lookup_call_use_vi (stmt)) != NULL)
  	    {
! 	      find_what_var_points_to (vi, pt);
! 	      /* Escaped (and thus nonlocal) variables are always
! 	         implicitly used by calls.  */
  	      /* ???  ESCAPED can be empty even though NONLOCAL
  		 always escaped.  */
  	      pt->nonlocal = 1;
*************** compute_points_to_sets (void)
*** 5566,5571 ****
--- 5648,5655 ----
  	    }
  	  else
  	    {
+ 	      /* If there is nothing special about this call then
+ 		 we have made everything that is used also escape.  */
  	      *pt = cfun->gimple_df->escaped;
  	      pt->nonlocal = 1;
  	    }
*************** compute_points_to_sets (void)
*** 5573,5580 ****
--- 5657,5676 ----
  	  pt = gimple_call_clobber_set (stmt);
  	  if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
  	    memset (pt, 0, sizeof (struct pt_solution));
+ 	  else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
+ 	    {
+ 	      find_what_var_points_to (vi, pt);
+ 	      /* Escaped (and thus nonlocal) variables are always
+ 	         implicitly clobbered by calls.  */
+ 	      /* ???  ESCAPED can be empty even though NONLOCAL
+ 		 always escaped.  */
+ 	      pt->nonlocal = 1;
+ 	      pt->escaped = 1;
+ 	    }
  	  else
  	    {
+ 	      /* If there is nothing special about this call then
+ 		 we have made everything that is used also escape.  */
  	      *pt = cfun->gimple_df->escaped;
  	      pt->nonlocal = 1;
  	    }
*************** delete_points_to_sets (void)
*** 5598,5603 ****
--- 5694,5700 ----
  	     stats.points_to_sets_created);
  
    pointer_map_destroy (vi_for_tree);
+   pointer_map_destroy (call_stmt_vars);
    bitmap_obstack_release (&pta_obstack);
    VEC_free (constraint_t, heap, constraints);
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]