tree-ssa-structalias.c (callused_id, [...]): Add.
authorRichard Guenther <rguenther@suse.de>
Sat, 28 Jun 2008 13:17:20 +0000 (13:17 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Sat, 28 Jun 2008 13:17:20 +0000 (13:17 +0000)
2008-06-28  Richard Guenther  <rguenther@suse.de>

* tree-ssa-structalias.c (callused_id, var_callused,
callused_tree): Add.
(handle_pure_call): New function.
(find_func_aliases): Call it.
(find_what_p_points_to): Handle the call-used set.
(clobber_what_escaped): Likewise.
(compute_call_used_vars): New function.
(init_base_vars): Init the call-used variable.
(do_sd_constraint): Do not propagate the solution from CALLUSED
but use CALLUSED as a placeholder.
(solve_graph): Likewise.
* tree-flow-inline.h (gimple_call_used_vars): New function.
* tree-flow.h (struct gimple_df): Add call_used_vars bitmap.
(compute_call_used_vars): Declare.
* tree-ssa-alias.c (set_initial_properties): Call
compute_call_used_vars.
(reset_alias_info): Clear call-used variables.
(add_call_clobber_ops): Assert we are not called for const/pure
functions.  Remove handling of them.
(add_call_read_ops): Handle pure functions by adding the
call-used set of variables as VUSEs.
* tree-ssa.c (init_tree_ssa): Allocate call-used bitmap.
(delete_tree_ssa): Free it.
* tree-dfa.c (remove_referenced_var): Clear the var from the
call-used bitmap.

* gcc.dg/tree-ssa/pr24287.c: Remove XFAIL.

From-SVN: r137222

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/pr24287.c
gcc/tree-dfa.c
gcc/tree-flow-inline.h
gcc/tree-flow.h
gcc/tree-ssa-alias.c
gcc/tree-ssa-operands.c
gcc/tree-ssa-structalias.c
gcc/tree-ssa.c

index 3dc9e8f66038ffc7fd376ac3641045ee8d1e3c56..8a53395b23f5a73a2e6b7bac3995d0cb1a789566 100644 (file)
@@ -1,3 +1,31 @@
+2008-06-28  Richard Guenther  <rguenther@suse.de>
+
+       * tree-ssa-structalias.c (callused_id, var_callused,
+       callused_tree): Add.
+       (handle_pure_call): New function.
+       (find_func_aliases): Call it.
+       (find_what_p_points_to): Handle the call-used set.
+       (clobber_what_escaped): Likewise.
+       (compute_call_used_vars): New function.
+       (init_base_vars): Init the call-used variable.
+       (do_sd_constraint): Do not propagate the solution from CALLUSED
+       but use CALLUSED as a placeholder.
+       (solve_graph): Likewise.
+       * tree-flow-inline.h (gimple_call_used_vars): New function.
+       * tree-flow.h (struct gimple_df): Add call_used_vars bitmap.
+       (compute_call_used_vars): Declare.
+       * tree-ssa-alias.c (set_initial_properties): Call
+       compute_call_used_vars.
+       (reset_alias_info): Clear call-used variables.
+       (add_call_clobber_ops): Assert we are not called for const/pure
+       functions.  Remove handling of them.
+       (add_call_read_ops): Handle pure functions by adding the
+       call-used set of variables as VUSEs.
+       * tree-ssa.c (init_tree_ssa): Allocate call-used bitmap.
+       (delete_tree_ssa): Free it.
+       * tree-dfa.c (remove_referenced_var): Clear the var from the
+       call-used bitmap.
+
 2008-06-28  Kai Tietz  <kai.tietz@onevision.com>
 
        * tree.c (build_varargs_function_type_list): New.
index d4de302f794d84251870ebb75d96fd84825e5222..e3f8556acacc617ae005660758b0d013c00e5599 100644 (file)
@@ -1,3 +1,7 @@
+2008-06-28  Richard Guenther  <rguenther@suse.de>
+
+       * gcc.dg/tree-ssa/pr24287.c: Remove XFAIL.
+
 2008-06-27  Mark Mitchell  <mark@codesourcery.com>
 
        * g++.dg/abi/arm_cxa_vec2.C: New test.
index c4b172295b4fdf07e52fe5b7b8aa93e26a43fcde..63120457c4de8dfce2f2a89f2048d5a74da13f8a 100644 (file)
@@ -21,5 +21,5 @@ int g(void)
     link_error ();
   return t2 == 2;
 }
-/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" } } */
 /* { dg-final { cleanup-tree-dump "optimized" } } */
index a1780399cc6c5fc6002396dc845e3b63a9970865..285af39b3cadbc020d78090bed1269907e0168bc 100644 (file)
@@ -746,6 +746,7 @@ remove_referenced_var (tree var)
   unsigned int uid = DECL_UID (var);
 
   clear_call_clobbered (var);
+  bitmap_clear_bit (gimple_call_used_vars (cfun), uid);
   if ((v_ann = var_ann (var)))
     {
       /* Preserve var_anns of globals, but clear their alias info.  */
index c84964c1cdd205f9942d8226181ef0425fd2ed9f..bff697db5ae089a9478a1756f10ea0b9950dfc69 100644 (file)
@@ -66,6 +66,15 @@ gimple_call_clobbered_vars (const struct function *fun)
   return fun->gimple_df->call_clobbered_vars;
 }
 
+/* Call-used variables in the function.  If bit I is set, then
+   REFERENCED_VARS (I) is call-used at pure function call-sites.  */
+static inline bitmap
+gimple_call_used_vars (const struct function *fun)
+{
+  gcc_assert (fun && fun->gimple_df);
+  return fun->gimple_df->call_used_vars;
+}
+
 /* Array of all variables referenced in the function.  */
 static inline htab_t
 gimple_referenced_vars (const struct function *fun)
index ded7687b75ebf7a572b7e97e0521fc0551d41879..961054703dba5414ee0f7064ffef2de38c2d943b 100644 (file)
@@ -162,6 +162,10 @@ struct gimple_df GTY(())
      REFERENCED_VARS (I) is call-clobbered.  */
   bitmap call_clobbered_vars;
 
+  /* Call-used variables in the function.  If bit I is set, then
+     REFERENCED_VARS (I) is call-used at pure function call-sites.  */
+  bitmap call_used_vars;
+
   /* Addressable variables in the function.  If bit I is set, then
      REFERENCED_VARS (I) has had its address taken.  Note that
      CALL_CLOBBERED_VARS and ADDRESSABLE_VARS are not related.  An
@@ -1174,6 +1178,7 @@ tree gimple_fold_indirect_ref (tree);
 /* In tree-ssa-structalias.c */
 bool find_what_p_points_to (tree);
 bool clobber_what_escaped (void);
+void compute_call_used_vars (void);
 
 /* In tree-ssa-live.c */
 extern void remove_unused_locals (void);
index 7c24739e407ab960fcebec00a079938b22cabd01..9a6552bb9d5006fbfa0a05def2c3b4459d6c1780 100644 (file)
@@ -505,7 +505,7 @@ compute_tag_properties (void)
   VEC_free (tree, heap, taglist);
 }
 
-/* Set up the initial variable clobbers and globalness.
+/* Set up the initial variable clobbers, call-uses and globalness.
    When this function completes, only tags whose aliases need to be
    clobbered will be set clobbered.  Tags clobbered because they   
    contain call clobbered vars are handled in compute_tag_properties.  */
@@ -543,6 +543,8 @@ set_initial_properties (struct alias_info *ai)
       pt_anything_mask |= ESCAPE_TO_CALL;
     }
 
+  compute_call_used_vars ();
+
   for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
     {
       struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
@@ -2000,6 +2002,9 @@ reset_alias_info (void)
   /* There should be no call-clobbered variable left.  */
   gcc_assert (bitmap_empty_p (gimple_call_clobbered_vars (cfun)));
 
+  /* Clear the call-used variables.  */
+  bitmap_clear (gimple_call_used_vars (cfun));
+
   /* Clear flow-sensitive points-to information from each SSA name.  */
   for (i = 1; i < num_ssa_names; i++)
     {
index 71fb883f84a4f101bd8a1e47a289efc57a37e916..0aeea9f7f93c244876e32e21eb134bb023d2a81c 100644 (file)
@@ -1660,7 +1660,10 @@ add_call_clobber_ops (tree stmt, tree callee)
   bitmap_iterator bi;
   stmt_ann_t s_ann = stmt_ann (stmt);
   bitmap not_read_b, not_written_b;
-  
+  tree call = get_call_expr_in (stmt);
+
+  gcc_assert (!(call_expr_flags (call) & (ECF_PURE | ECF_CONST)));
+
   /* If we created .GLOBAL_VAR earlier, just use it.  */
   if (gimple_global_var (cfun))
     {
@@ -1674,12 +1677,10 @@ add_call_clobber_ops (tree stmt, tree callee)
      or write that variable.  */
   not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL; 
   not_written_b = callee ? ipa_reference_get_not_written_global (callee) : NULL; 
-
   /* Add a VDEF operand for every call clobbered variable.  */
   EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, u, bi)
     {
       tree var = referenced_var_lookup (u);
-      unsigned int escape_mask = var_ann (var)->escape_mask;
       tree real_var = var;
       bool not_read;
       bool not_written;
@@ -1697,24 +1698,6 @@ add_call_clobber_ops (tree stmt, tree callee)
 
       /* See if this variable is really clobbered by this function.  */
 
-      /* Trivial case: Things escaping only to pure/const are not
-        clobbered by non-pure-const, and only read by pure/const. */
-      if ((escape_mask & ~(ESCAPE_TO_PURE_CONST)) == 0)
-       {
-         tree call = get_call_expr_in (stmt);
-         if (call_expr_flags (call) & (ECF_CONST | ECF_PURE))
-           {
-             add_virtual_operand (var, s_ann, opf_use, NULL, 0, -1, true);
-             clobber_stats.unescapable_clobbers_avoided++;
-             continue;
-           }
-         else
-           {
-             clobber_stats.unescapable_clobbers_avoided++;
-             continue;
-           }
-       }
-            
       if (not_written)
        {
          clobber_stats.static_write_clobbers_avoided++;
@@ -1739,18 +1722,47 @@ add_call_read_ops (tree stmt, tree callee)
   bitmap_iterator bi;
   stmt_ann_t s_ann = stmt_ann (stmt);
   bitmap not_read_b;
+  tree call = get_call_expr_in (stmt);
+
+  /* Const functions do not reference memory.  */
+  if (call_expr_flags (call) & ECF_CONST)
+    return;
 
-  /* if the function is not pure, it may reference memory.  Add
-     a VUSE for .GLOBAL_VAR if it has been created.  See add_referenced_var
-     for the heuristic used to decide whether to create .GLOBAL_VAR.  */
+  not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL;
+
+  /* For pure functions we compute non-escaped uses separately.  */
+  if (call_expr_flags (call) & ECF_PURE)
+    EXECUTE_IF_SET_IN_BITMAP (gimple_call_used_vars (cfun), 0, u, bi)
+      {
+       tree var = referenced_var_lookup (u);
+       tree real_var = var;
+       bool not_read;
+
+       if (unmodifiable_var_p (var))
+         continue;
+
+       not_read = not_read_b
+           ? bitmap_bit_p (not_read_b, DECL_UID (real_var))
+           : false;
+
+       clobber_stats.readonly_clobbers++;
+
+       /* See if this variable is really used by this function.  */
+       if (!not_read)
+         add_virtual_operand (var, s_ann, opf_use, NULL, 0, -1, true);
+       else
+         clobber_stats.static_readonly_clobbers_avoided++;
+      }
+
+  /* Add a VUSE for .GLOBAL_VAR if it has been created.  See
+     add_referenced_var for the heuristic used to decide whether to
+     create .GLOBAL_VAR.  */
   if (gimple_global_var (cfun))
     {
       tree var = gimple_global_var (cfun);
       add_virtual_operand (var, s_ann, opf_use, NULL, 0, -1, true);
       return;
     }
-  
-  not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL; 
 
   /* Add a VUSE for each call-clobbered variable.  */
   EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, u, bi)
index 2b6c56fa1a706a98df98543133f8db9a093198aa..4a3896bc4406e68562a22caf64d6f8d5813d8f42 100644 (file)
@@ -296,7 +296,7 @@ get_varinfo_fc (unsigned int n)
 
 /* 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 };
+       escaped_id = 3, nonlocal_id = 4, callused_id = 5, integer_id = 6 };
 
 /* Variable that represents the unknown pointer.  */
 static varinfo_t var_anything;
@@ -318,6 +318,10 @@ static tree escaped_tree;
 static varinfo_t var_nonlocal;
 static tree nonlocal_tree;
 
+/* Variable that represents call-used memory.  */
+static varinfo_t var_callused;
+static tree callused_tree;
+
 /* Variable that represents integers.  This is used for when people do things
    like &0->a.b.  */
 static varinfo_t var_integer;
@@ -1429,11 +1433,13 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
          if (get_varinfo (t)->is_special_var)
            flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
          /* Merging the solution from ESCAPED needlessly increases
-            the set.  Use ESCAPED as representative instead.  */
-         else if (get_varinfo (t)->id == escaped_id
+            the set.  Use ESCAPED as representative instead.
+            Same for CALLUSED.  */
+         else if ((get_varinfo (t)->id == escaped_id
+                   || get_varinfo (t)->id == callused_id)
                   && !bitmap_bit_p (sol, get_varinfo (t)->id))
            {
-             bitmap_set_bit (sol, escaped_id);
+             bitmap_set_bit (sol, get_varinfo (t)->id);
              flag = true;
            }
          else if (add_graph_edge (graph, lhs, t))
@@ -2369,8 +2375,9 @@ solve_graph (constraint_graph_t graph)
              solution_empty = bitmap_empty_p (solution);
 
              if (!solution_empty
-                 /* Do not propagate the ESCAPED solution.  */
-                 && i != escaped_id)
+                 /* Do not propagate the ESCAPED/CALLUSED solutions.  */
+                 && i != escaped_id
+                 && i != callused_id)
                {
                  bitmap_iterator bi;
 
@@ -3702,6 +3709,61 @@ handle_const_call (tree stmt)
   VEC_free (ce_s, heap, lhsc);
 }
 
+/* For non-IPA mode, generate constraints necessary for a call to a
+   pure function in statement STMT.  */
+
+static void
+handle_pure_call (tree stmt)
+{
+  tree call = get_call_expr_in (stmt);
+  tree arg;
+  call_expr_arg_iterator iter;
+
+  /* Memory reached from pointer arguments is call-used.  */
+  FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
+    if (could_have_pointers (arg))
+      make_constraint_to (callused_id, arg);
+
+  /* The static chain is used as well.  */
+  if (CALL_EXPR_STATIC_CHAIN (call))
+    make_constraint_to (callused_id, CALL_EXPR_STATIC_CHAIN (call));
+
+  /* If the call returns a pointer it may point to reachable memory
+     from the arguments.  */
+  if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
+      && could_have_pointers (GIMPLE_STMT_OPERAND (stmt, 0)))
+    {
+      tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+      VEC(ce_s, heap) *lhsc = NULL;
+      struct constraint_expr rhsc;
+      struct constraint_expr *lhsp;
+      unsigned j;
+
+      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;
+       }
+
+      /* Else just add the call-used memory here.  Escaped variables
+         and globals will be dealt with in handle_lhs_call.  */
+      rhsc.var = callused_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);
+    }
+}
+
 /* Walk statement T setting up aliasing constraints according to the
    references found in T.  This function is the main part of the
    constraint builder.  AI points to auxiliary alias information used
@@ -3778,6 +3840,13 @@ find_func_aliases (tree origt)
                  && could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
                handle_const_call (t);
            }
+         else if (flags & ECF_PURE)
+           {
+             handle_pure_call (t);
+             if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
+                 && could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
+               handle_lhs_call (GIMPLE_STMT_OPERAND (t, 0));
+           }
          /* 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
@@ -4940,7 +5009,8 @@ find_what_p_points_to (tree p)
                    pi->pt_null = 1;
                  else if (vi->id == anything_id
                           || vi->id == nonlocal_id
-                          || vi->id == escaped_id)
+                          || vi->id == escaped_id
+                          || vi->id == callused_id)
                    was_pt_anything = 1;
                  else if (vi->id == readonly_id)
                    was_pt_anything = 1;
@@ -5007,6 +5077,15 @@ clobber_what_escaped (void)
      variable for escaped_id.  */
   vi = get_varinfo (find (escaped_id));
 
+  /* If call-used memory escapes we need to include it in the
+     set of escaped variables.  This can happen if a pure
+     function returns a pointer and this pointer escapes.  */
+  if (bitmap_bit_p (vi->solution, callused_id))
+    {
+      varinfo_t cu_vi = get_varinfo (find (callused_id));
+      bitmap_ior_into (vi->solution, cu_vi->solution);
+    }
+
   /* Mark variables in the solution call-clobbered.  */
   EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
     {
@@ -5036,6 +5115,54 @@ clobber_what_escaped (void)
   return true;
 }
 
+/* Compute the call-used variables.  */
+
+void
+compute_call_used_vars (void)
+{
+  varinfo_t vi;
+  unsigned int i;
+  bitmap_iterator bi;
+  bool has_anything_id = false;
+
+  if (!have_alias_info)
+    return;
+
+  /* This variable may have been collapsed, let's get the real
+     variable for escaped_id.  */
+  vi = get_varinfo (find (callused_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)
+       {
+         /* For anything_id and integer_id we need to make
+            all local addressable vars call-used.  */
+         if (vi->id == anything_id
+             || vi->id == integer_id)
+           has_anything_id = true;
+       }
+
+      /* Only artificial heap-vars are further interesting.  */
+      if (vi->is_artificial_var && !vi->is_heap_var)
+       continue;
+
+      if ((TREE_CODE (vi->decl) == VAR_DECL
+          || TREE_CODE (vi->decl) == PARM_DECL
+          || TREE_CODE (vi->decl) == RESULT_DECL)
+         && !unmodifiable_var_p (vi->decl))
+       bitmap_set_bit (gimple_call_used_vars (cfun), DECL_UID (vi->decl));
+    }
+
+  /* If anything is call-used, add all addressable locals to the set.  */
+  if (has_anything_id)
+    bitmap_ior_into (gimple_call_used_vars (cfun),
+                    gimple_addressable_vars (cfun));
+}
+
 
 /* Dump points-to information to OUTFILE.  */
 
@@ -5193,6 +5320,27 @@ init_base_vars (void)
   rhs.offset = 0;
   process_constraint (new_constraint (lhs, rhs));
 
+  /* Create the CALLUSED variable, used to represent the set of call-used
+     memory.  */
+  callused_tree = create_tmp_var_raw (void_type_node, "CALLUSED");
+  var_callused = new_var_info (callused_tree, callused_id, "CALLUSED");
+  insert_vi_for_tree (callused_tree, var_callused);
+  var_callused->is_artificial_var = 1;
+  var_callused->offset = 0;
+  var_callused->size = ~0;
+  var_callused->fullsize = ~0;
+  var_callused->is_special_var = 0;
+  VEC_safe_push (varinfo_t, heap, varmap, var_callused);
+
+  /* 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_1 (new_constraint (lhs, rhs), true);
+
   /* Create the INTEGER variable, used to represent that a variable points
      to an INTEGER.  */
   integer_tree = create_tmp_var_raw (void_type_node, "INTEGER");
index 5a7446482719bbf0a347619227adcd39512c1947..7f567b57a2ed1d3594ba9d3870e2f5f88d024fe5 100644 (file)
@@ -937,6 +937,7 @@ init_tree_ssa (struct function *fn)
   fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash, 
                                                 uid_ssaname_map_eq, NULL);
   fn->gimple_df->call_clobbered_vars = BITMAP_GGC_ALLOC ();
+  fn->gimple_df->call_used_vars = BITMAP_GGC_ALLOC ();
   fn->gimple_df->addressable_vars = BITMAP_GGC_ALLOC ();
   init_ssanames (fn, 0);
   init_phinodes ();
@@ -1009,6 +1010,7 @@ delete_tree_ssa (void)
   htab_delete (cfun->gimple_df->default_defs);
   cfun->gimple_df->default_defs = NULL;
   cfun->gimple_df->call_clobbered_vars = NULL;
+  cfun->gimple_df->call_used_vars = NULL;
   cfun->gimple_df->addressable_vars = NULL;
   cfun->gimple_df->modified_noreturn_calls = NULL;
   if (gimple_aliases_computed_p (cfun))