re PR tree-optimization/55334 (mgrid regression (ipa-cp disables vectorization))
authorRichard Biener <rguenth@gcc.gnu.org>
Mon, 24 Nov 2014 09:24:50 +0000 (09:24 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Mon, 24 Nov 2014 09:24:50 +0000 (09:24 +0000)
2014-11-24  Richard Biener  <rguenther@suse.de>

PR tree-optimization/55334
* function.h (struct function): Add last_clique member.
* tree-inline.c (remap_dependence_clique): New function.
(remap_gimple_op_r): Remap dependence cliques in MEM_REFs.
(copy_tree_body_r): Likewise.
(copy_cfg_body): Free dependence map.
(copy_gimple_seq_and_replace_locals): Likewise.
* tree-pretty-print.c (dump_generic_node): Dump
dependence info.
* tree-ssa-alias.c (refs_may_alias_p_1): Use dependence info
to answer alias query.
* tree-ssa-structalias.c: Include tree-phinodes.h, ssa-iterators.h,
tree-pretty-print.h and gimple-walk.h.
(struct variable_info): Add is_restrict_var flag and ruid
member.
(new_var_info): Initialize is_restrict_var.
(make_constraint_from_restrict): Likewise.
(create_variable_info_for): Exclude restricts from global vars
from new handling.
(intra_create_variable_infos): But not those from parameters.
(visit_loadstore): New function.
(maybe_set_dependence_info): Likewise.
(compute_dependence_clique): Likewise.
(compute_may_aliases): Call compute_dependence_clique.
* tree-data-ref.c (dr_analyze_indices): Copy dependence info
to fake MEM_REF.
(dr_may_alias_p): Use recorded dependence info to answer
alias query.
* tree-core.h (struct tree_base): Add clique, base struct in
union.
* tree.h (MR_DEPENDENCE_CLIQUE): New macro.
(MR_DEPENDENCE_BASE): Likewise.
* tree-inline.h (dependence_hasher): New hash-map kind.
(struct copy_body_data): Add dependence_map pointer.
* gimple-fold.c (maybe_canonicalize_mem_ref_addr): Avoid
throwing away dependence info.
* tree-streamer-in.c (unpack_value_fields): Stream dependence info.
* tree-streamer-out.c (streamer_pack_tree_bitfields): Likewise.

* gcc.dg/tree-ssa/restrict-5.c: New testcase.

From-SVN: r218005

gcc/tree-ssa-structalias.c

index e065f1a1b4c81d421cc9b356eccb7b7bc7f7c2c8..69cf60b08951e3021dd4a2fc7bf170f411fcc99d 100644 (file)
 #include "splay-tree.h"
 #include "params.h"
 #include "alias.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "tree-pretty-print.h"
+#include "gimple-walk.h"
 
 /* The idea behind this analyzer is to generate set constraints from the
    program, then solve the resulting constraints in order to generate the
@@ -284,12 +288,19 @@ struct variable_info
   /* True if this field has only restrict qualified pointers.  */
   unsigned int only_restrict_pointers : 1;
 
+  /* True if this represents a heap var created for a restrict qualified
+     pointer.  */
+  unsigned int is_restrict_var : 1;
+
   /* True if this represents a global variable.  */
   unsigned int is_global_var : 1;
 
   /* True if this represents a IPA function info.  */
   unsigned int is_fn_info : 1;
 
+  /* ???  Store somewhere better.  */
+  unsigned short ruid;
+
   /* The ID of the variable for the next field in this structure
      or zero for the last field in this structure.  */
   unsigned next;
@@ -381,6 +392,7 @@ new_var_info (tree t, const char *name)
   ret->is_heap_var = false;
   ret->may_have_pointers = true;
   ret->only_restrict_pointers = false;
+  ret->is_restrict_var = false;
   ret->is_global_var = (t == NULL_TREE);
   ret->is_fn_info = false;
   if (t && DECL_P (t))
@@ -3785,6 +3797,7 @@ static varinfo_t
 make_constraint_from_restrict (varinfo_t lhs, const char *name)
 {
   varinfo_t vi = make_heapvar (name);
+  vi->is_restrict_var = 1;
   vi->is_global_var = 1;
   vi->may_have_pointers = 1;
   make_constraint_from (lhs, vi->id);
@@ -5749,7 +5762,11 @@ create_variable_info_for (tree decl, const char *name)
           && TYPE_RESTRICT (TREE_TYPE (decl)))
          || vi->only_restrict_pointers)
        {
-         make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT");
+         varinfo_t rvi
+           = make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT");
+         /* ???  For now exclude reads from globals as restrict sources
+            if those are not (indirectly) from incoming parameters.  */
+         rvi->is_restrict_var = false;
          continue;
        }
 
@@ -5859,6 +5876,7 @@ intra_create_variable_infos (struct function *fn)
          tree heapvar = build_fake_var_decl (TREE_TYPE (TREE_TYPE (t)));
          DECL_EXTERNAL (heapvar) = 1;
          vi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS");
+         vi->is_restrict_var = 1;
          insert_vi_for_tree (heapvar, vi);
          lhsc.var = p->id;
          lhsc.type = SCALAR;
@@ -6933,6 +6951,186 @@ delete_points_to_sets (void)
   obstack_free (&final_solutions_obstack, NULL);
 }
 
+/* Mark "other" loads and stores as belonging to CLIQUE and with
+   base zero.  */
+
+static bool
+visit_loadstore (gimple, tree base, tree ref, void *clique_)
+{
+  unsigned short clique = (uintptr_t)clique_;
+  if (TREE_CODE (base) == MEM_REF
+      || TREE_CODE (base) == TARGET_MEM_REF)
+    {
+      tree ptr = TREE_OPERAND (base, 0);
+      if (TREE_CODE (ptr) == SSA_NAME)
+       {
+         /* ???  We need to make sure 'ptr' doesn't include any of
+            the restrict tags in its points-to set.  */
+         return false;
+       }
+
+      /* For now let decls through.  */
+
+      /* Do not overwrite existing cliques (that includes clique, base
+         pairs we just set).  */
+      if (MR_DEPENDENCE_CLIQUE (base) == 0)
+       {
+         MR_DEPENDENCE_CLIQUE (base) = clique;
+         MR_DEPENDENCE_BASE (base) = 0;
+       }
+    }
+
+  /* For plain decl accesses see whether they are accesses to globals
+     and rewrite them to MEM_REFs with { clique, 0 }.  */
+  if (TREE_CODE (base) == VAR_DECL
+      && is_global_var (base)
+      /* ???  We can't rewrite a plain decl with the walk_stmt_load_store
+        ops callback.  */
+      && base != ref)
+    {
+      tree *basep = &ref;
+      while (handled_component_p (*basep))
+       basep = &TREE_OPERAND (*basep, 0);
+      gcc_assert (TREE_CODE (*basep) == VAR_DECL);
+      tree ptr = build_fold_addr_expr (*basep);
+      tree zero = build_int_cst (TREE_TYPE (ptr), 0);
+      *basep = build2 (MEM_REF, TREE_TYPE (*basep), ptr, zero);
+      MR_DEPENDENCE_CLIQUE (*basep) = clique;
+      MR_DEPENDENCE_BASE (*basep) = 0;
+    }
+
+  return false;
+}
+
+/* If REF is a MEM_REF then assign a clique, base pair to it, updating
+   CLIQUE, *RESTRICT_VAR and LAST_RUID.  Return whether dependence info
+   was assigned to REF.  */
+
+static bool
+maybe_set_dependence_info (tree ref, tree ptr,
+                          unsigned short &clique, varinfo_t restrict_var,
+                          unsigned short &last_ruid)
+{
+  while (handled_component_p (ref))
+    ref = TREE_OPERAND (ref, 0);
+  if ((TREE_CODE (ref) == MEM_REF
+       || TREE_CODE (ref) == TARGET_MEM_REF)
+      && TREE_OPERAND (ref, 0) == ptr)
+    {
+      /* Do not overwrite existing cliques.  This avoids overwriting dependence
+        info inlined from a function with restrict parameters inlined
+        into a function with restrict parameters.  This usually means we
+        prefer to be precise in innermost loops.  */
+      if (MR_DEPENDENCE_CLIQUE (ref) == 0)
+       {
+         if (clique == 0)
+           clique = ++cfun->last_clique;
+         if (restrict_var->ruid == 0)
+           restrict_var->ruid = ++last_ruid;
+         MR_DEPENDENCE_CLIQUE (ref) = clique;
+         MR_DEPENDENCE_BASE (ref) = restrict_var->ruid;
+         return true;
+       }
+    }
+  return false;
+}
+
+/* Compute the set of independend memory references based on restrict
+   tags and their conservative propagation to the points-to sets.  */
+
+static void
+compute_dependence_clique (void)
+{
+  unsigned short clique = 0;
+  unsigned short last_ruid = 0;
+  for (unsigned i = 0; i < num_ssa_names; ++i)
+    {
+      tree ptr = ssa_name (i);
+      if (!ptr || !POINTER_TYPE_P (TREE_TYPE (ptr)))
+       continue;
+
+      /* Avoid all this when ptr is not dereferenced?  */
+      tree p = ptr;
+      if (SSA_NAME_IS_DEFAULT_DEF (ptr)
+         && (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL
+             || TREE_CODE (SSA_NAME_VAR (ptr)) == RESULT_DECL))
+       p = SSA_NAME_VAR (ptr);
+      varinfo_t vi = lookup_vi_for_tree (p);
+      if (!vi)
+       continue;
+      vi = get_varinfo (find (vi->id));
+      bitmap_iterator bi;
+      unsigned j;
+      varinfo_t restrict_var = NULL;
+      EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, j, bi)
+       {
+         varinfo_t oi = get_varinfo (j);
+         if (oi->is_restrict_var)
+           {
+             if (restrict_var)
+               {
+                 if (dump_file && (dump_flags & TDF_DETAILS))
+                   {
+                     fprintf (dump_file, "found restrict pointed-to "
+                              "for ");
+                     print_generic_expr (dump_file, ptr, 0);
+                     fprintf (dump_file, " but not exclusively\n");
+                   }
+                 restrict_var = NULL;
+                 break;
+               }
+             restrict_var = oi;
+           }
+         /* NULL is the only other valid points-to entry.  */
+         else if (oi->id != nothing_id)
+           {
+             restrict_var = NULL;
+             break;
+           }
+       }
+      /* Ok, found that ptr must(!) point to a single(!) restrict
+        variable.  */
+      /* ???  PTA isn't really a proper propagation engine to compute
+        this property.
+        ???  We could handle merging of two restricts by unifying them.  */
+      if (restrict_var)
+       {
+         /* Now look at possible dereferences of ptr.  */
+         imm_use_iterator ui;
+         gimple use_stmt;
+         FOR_EACH_IMM_USE_STMT (use_stmt, ui, ptr)
+           {
+             /* ???  Calls and asms.  */
+             if (!gimple_assign_single_p (use_stmt))
+               continue;
+             maybe_set_dependence_info (gimple_assign_lhs (use_stmt), ptr,
+                                        clique, restrict_var, last_ruid);
+             maybe_set_dependence_info (gimple_assign_rhs1 (use_stmt), ptr,
+                                        clique, restrict_var, last_ruid);
+           }
+       }
+    }
+
+  if (clique == 0)
+    return;
+
+  /* Assign the BASE id zero to all accesses not based on a restrict
+     pointer.  That way they get disabiguated against restrict
+     accesses but not against each other.  */
+  /* ???  For restricts derived from globals (thus not incoming
+     parameters) we can't restrict scoping properly thus the following
+     is too aggressive there.  For now we have excluded those globals from
+     getting into the MR_DEPENDENCE machinery.  */
+  basic_block bb;
+  FOR_EACH_BB_FN (bb, cfun)
+    for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+        !gsi_end_p (gsi); gsi_next (&gsi))
+      {
+       gimple stmt = gsi_stmt (gsi);
+       walk_stmt_load_store_ops (stmt, (void *)(uintptr_t)clique,
+                                 visit_loadstore, visit_loadstore);
+      }
+}
 
 /* Compute points-to information for every SSA_NAME pointer in the
    current function and compute the transitive closure of escaped
@@ -6964,6 +7162,9 @@ compute_may_aliases (void)
   if (dump_file)
     dump_alias_info (dump_file);
 
+  /* Compute restrict-based memory disambiguations.  */
+  compute_dependence_clique ();
+
   /* Deallocate memory used by aliasing data structures and the internal
      points-to solution.  */
   delete_points_to_sets ();