public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Fix PR55334 - preserve restrict through inlining/cloning
@ 2014-11-17 15:38 Richard Biener
  0 siblings, 0 replies; only message in thread
From: Richard Biener @ 2014-11-17 15:38 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jakub Jelinek, Michael Matz


Posted again, compared to last post on Sep 8 the patch got LTO
support and minor cleanups.

---

The following addresses PR55334 which is about us losing restrict
properties of parameters when inlining or cloning (in the case of the
PR it's cloning via IPA-CP).

It does that by introducing another means of tracking non-dependences
introduced by usages of 'restrict'.  The scheme is simple - we
partition the set of memory accesses in a function into groups
in which we can determine non-dependence by comparing a UID like
in dr_may_alias_p:

+   if ((TREE_CODE (addr_a) == MEM_REF || TREE_CODE (addr_a) == TARGET_MEM_REF)
+       && (TREE_CODE (addr_b) == MEM_REF || TREE_CODE (addr_b) == TARGET_MEM_REF)
+       && MR_DEPENDENCE_CLIQUE (addr_a) == MR_DEPENDENCE_CLIQUE (addr_b)
+       && MR_DEPENDENCE_BASE (addr_a) != MR_DEPENDENCE_BASE (addr_b))
+     return false;

the 'group' is determined by MR_DEPENDENCE_CLIQUE and if that is equal
then non-equal MR_DEPENDENCE_BASE means the two memory references
do not alias.  We cannot derive anything if MR_DEPENDENCE_CLIQUE
are distinct.

For a simple function like

void foo (int * restrict p, int *q, int *r)
{
  *p = 1;
  *q = 0;
  *r = 3;
}

this will annotate *p with MR_DEPENDENCE_CLIQUE == 1 and
MR_DEPENDENCE_BASE with 1 and both *q and *r with MR_DEPENDENCE_CLIQUE == 1
and MR_DEPENDENCE_BASE with 0.

MR_DEPENDENCE_CLIQUE are assigned function-specific unique IDs
and thus they get re-mapped during inlining.  This means inlining
the above twice into bar() will get you one set of references with
MR_DEPENDENCE_CLIQUE == 1 and one with MR_DEPENDENCE_CLIQUE == 2.

The following patch is aimed at function parameters only, I didn't try
to invent "magic" with restrict properties we derive from accessing
global pointers.

Note that the old mechanism for tracking restrict via PTA remains
and the new scheme builds ontop of the PTA restrict solving.

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

Ok for trunk?

Thanks,
Richard.

2014-11-17  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.

Index: trunk/gcc/function.h
===================================================================
*** trunk.orig/gcc/function.h	2014-11-11 09:39:40.987864355 +0100
--- trunk/gcc/function.h	2014-11-17 13:48:03.668526869 +0100
*************** struct GTY(()) function {
*** 589,594 ****
--- 589,597 ----
       a string describing the reason for failure.  */
    const char * GTY((skip)) cannot_be_copied_reason;
  
+   /* Last assigned dependence info clique.  */
+   unsigned short last_clique;
+ 
    /* Collected bit flags.  */
  
    /* Number of units of general registers that need saving in stdarg
Index: trunk/gcc/tree-inline.c
===================================================================
*** trunk.orig/gcc/tree-inline.c	2014-11-17 10:07:56.546104816 +0100
--- trunk/gcc/tree-inline.c	2014-11-17 13:48:03.710526867 +0100
*************** is_parm (tree decl)
*** 849,854 ****
--- 849,872 ----
    return (TREE_CODE (decl) == PARM_DECL);
  }
  
+ /* Remap the dependence CLIQUE from the source to the destination function
+    as specified in ID.  */
+ 
+ static unsigned short
+ remap_dependence_clique (copy_body_data *id, unsigned short clique)
+ {
+   if (clique == 0)
+     return 0;
+   if (!id->dependence_map)
+     id->dependence_map
+       = new hash_map<unsigned short, unsigned short, dependence_hasher>;
+   bool existed;
+   unsigned short &newc = id->dependence_map->get_or_insert (clique, &existed);
+   if (!existed)
+     newc = ++cfun->last_clique;
+   return newc;
+ }
+ 
  /* Remap the GIMPLE operand pointed to by *TP.  DATA is really a
     'struct walk_stmt_info *'.  DATA->INFO is a 'copy_body_data *'.
     WALK_SUBTREES is used to indicate walk_gimple_op whether to keep
*************** remap_gimple_op_r (tree *tp, int *walk_s
*** 947,952 ****
--- 965,976 ----
  	  TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
  	  TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old);
  	  TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
+ 	  if (MR_DEPENDENCE_CLIQUE (old) != 0)
+ 	    {
+ 	      MR_DEPENDENCE_CLIQUE (*tp)
+ 	        = remap_dependence_clique (id, MR_DEPENDENCE_CLIQUE (old));
+ 	      MR_DEPENDENCE_BASE (*tp) = MR_DEPENDENCE_BASE (old);
+ 	    }
  	  /* We cannot propagate the TREE_THIS_NOTRAP flag if we have
  	     remapped a parameter as the property might be valid only
  	     for the parameter itself.  */
*************** copy_tree_body_r (tree *tp, int *walk_su
*** 1198,1203 ****
--- 1222,1233 ----
  	  TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
  	  TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old);
  	  TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
+ 	  if (MR_DEPENDENCE_CLIQUE (old) != 0)
+ 	    {
+ 	      MR_DEPENDENCE_CLIQUE (*tp)
+ 		= remap_dependence_clique (id, MR_DEPENDENCE_CLIQUE (old));
+ 	      MR_DEPENDENCE_BASE (*tp) = MR_DEPENDENCE_BASE (old);
+ 	    }
  	  /* We cannot propagate the TREE_THIS_NOTRAP flag if we have
  	     remapped a parameter as the property might be valid only
  	     for the parameter itself.  */
*************** copy_cfg_body (copy_body_data * id, gcov
*** 2738,2743 ****
--- 2768,2778 ----
        delete id->eh_map;
        id->eh_map = NULL;
      }
+   if (id->dependence_map)
+     {
+       delete id->dependence_map;
+       id->dependence_map = NULL;
+     }
  
    return new_fndecl;
  }
*************** copy_gimple_seq_and_replace_locals (gimp
*** 5113,5118 ****
--- 5148,5158 ----
    delete id.decl_map;
    if (id.debug_map)
      delete id.debug_map;
+   if (id.dependence_map)
+     {
+       delete id.dependence_map;
+       id.dependence_map = NULL;
+     }
  
    return copy;
  }
Index: trunk/gcc/tree-pretty-print.c
===================================================================
*** trunk.orig/gcc/tree-pretty-print.c	2014-11-14 12:13:29.646117836 +0100
--- trunk/gcc/tree-pretty-print.c	2014-11-17 13:48:03.722526866 +0100
*************** dump_generic_node (pretty_printer *buffe
*** 1093,1099 ****
  	    /* Same value types ignoring qualifiers.  */
  	    && (TYPE_MAIN_VARIANT (TREE_TYPE (node))
  		== TYPE_MAIN_VARIANT
! 		    (TREE_TYPE (TREE_TYPE (TREE_OPERAND (node, 1))))))
  	  {
  	    if (TREE_CODE (TREE_OPERAND (node, 0)) != ADDR_EXPR)
  	      {
--- 1093,1100 ----
  	    /* Same value types ignoring qualifiers.  */
  	    && (TYPE_MAIN_VARIANT (TREE_TYPE (node))
  		== TYPE_MAIN_VARIANT
! 		    (TREE_TYPE (TREE_TYPE (TREE_OPERAND (node, 1)))))
! 	    && MR_DEPENDENCE_CLIQUE (node) == 0)
  	  {
  	    if (TREE_CODE (TREE_OPERAND (node, 0)) != ADDR_EXPR)
  	      {
*************** dump_generic_node (pretty_printer *buffe
*** 1124,1129 ****
--- 1125,1137 ----
  		dump_generic_node (buffer, TREE_OPERAND (node, 1),
  				   spc, flags, false);
  	      }
+ 	    if (MR_DEPENDENCE_CLIQUE (node) != 0)
+ 	      {
+ 		pp_string (buffer, " clique ");
+ 		pp_unsigned_wide_integer (buffer, MR_DEPENDENCE_CLIQUE (node));
+ 		pp_string (buffer, " base ");
+ 		pp_unsigned_wide_integer (buffer, MR_DEPENDENCE_BASE (node));
+ 	      }
  	    pp_right_bracket (buffer);
  	  }
  	break;
*************** dump_generic_node (pretty_printer *buffe
*** 1462,1468 ****
  		  /* Same value types ignoring qualifiers.  */
  		  && (TYPE_MAIN_VARIANT (TREE_TYPE (op0))
  		      == TYPE_MAIN_VARIANT
! 		          (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 1))))))))
  	{
  	  op0 = TREE_OPERAND (op0, 0);
  	  str = "->";
--- 1470,1477 ----
  		  /* Same value types ignoring qualifiers.  */
  		  && (TYPE_MAIN_VARIANT (TREE_TYPE (op0))
  		      == TYPE_MAIN_VARIANT
! 		          (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 1)))))
! 		  && MR_DEPENDENCE_CLIQUE (op0) == 0)))
  	{
  	  op0 = TREE_OPERAND (op0, 0);
  	  str = "->";
Index: trunk/gcc/tree-ssa-alias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-alias.c	2014-10-29 10:19:36.173243112 +0100
--- trunk/gcc/tree-ssa-alias.c	2014-11-17 13:48:03.729526866 +0100
*************** refs_may_alias_p_1 (ao_ref *ref1, ao_ref
*** 1384,1389 ****
--- 1384,1417 ----
      return decl_refs_may_alias_p (ref1->ref, base1, offset1, max_size1,
  				  ref2->ref, base2, offset2, max_size2);
  
+   /* Handle restrict based accesses.
+      ???  ao_ref_base strips inner MEM_REF [&decl], recover from that
+      here.  */
+   tree rbase1 = base1;
+   tree rbase2 = base2;
+   if (var1_p)
+     {
+       rbase1 = ref1->ref;
+       if (rbase1)
+ 	while (handled_component_p (rbase1))
+ 	  rbase1 = TREE_OPERAND (rbase1, 0);
+     }
+   if (var2_p)
+     {
+       rbase2 = ref2->ref;
+       if (rbase2)
+ 	while (handled_component_p (rbase2))
+ 	  rbase2 = TREE_OPERAND (rbase2, 0);
+     }
+   if (rbase1 && rbase2
+       && (TREE_CODE (base1) == MEM_REF || TREE_CODE (base1) == TARGET_MEM_REF)
+       && (TREE_CODE (base2) == MEM_REF || TREE_CODE (base2) == TARGET_MEM_REF)
+       /* If the accesses are in the same restrict clique... */
+       && MR_DEPENDENCE_CLIQUE (base1) == MR_DEPENDENCE_CLIQUE (base2)
+       /* But based on different pointers they do not alias.  */
+       && MR_DEPENDENCE_BASE (base1) != MR_DEPENDENCE_BASE (base2))
+     return false;
+ 
    ind1_p = (TREE_CODE (base1) == MEM_REF
  	    || TREE_CODE (base1) == TARGET_MEM_REF);
    ind2_p = (TREE_CODE (base2) == MEM_REF
Index: trunk/gcc/tree-ssa-structalias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-structalias.c	2014-11-17 10:07:56.547104816 +0100
--- trunk/gcc/tree-ssa-structalias.c	2014-11-17 15:58:05.242185469 +0100
***************
*** 64,69 ****
--- 64,73 ----
  #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
*************** struct variable_info
*** 284,295 ****
--- 288,306 ----
    /* 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;
*************** new_var_info (tree t, const char *name)
*** 381,386 ****
--- 392,398 ----
    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))
*************** static varinfo_t
*** 3785,3790 ****
--- 3797,3803 ----
  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);
*************** create_variable_info_for (tree decl, con
*** 5840,5846 ****
  	   && TYPE_RESTRICT (TREE_TYPE (decl)))
  	  || vi->only_restrict_pointers)
  	{
! 	  make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT");
  	  continue;
  	}
  
--- 5853,5863 ----
  	   && TYPE_RESTRICT (TREE_TYPE (decl)))
  	  || vi->only_restrict_pointers)
  	{
! 	  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;
  	}
  
*************** intra_create_variable_infos (struct func
*** 5950,5955 ****
--- 5967,5973 ----
  	  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;
*************** delete_points_to_sets (void)
*** 7022,7027 ****
--- 7040,7225 ----
    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
*************** compute_may_aliases (void)
*** 7053,7058 ****
--- 7251,7259 ----
    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 ();
Index: trunk/gcc/tree-data-ref.c
===================================================================
*** trunk.orig/gcc/tree-data-ref.c	2014-11-11 09:39:40.990864355 +0100
--- trunk/gcc/tree-data-ref.c	2014-11-17 13:48:03.763526864 +0100
*************** dr_analyze_indices (struct data_referenc
*** 991,999 ****
--- 991,1002 ----
  	     guaranteed.
  	     As a band-aid, mark the access so we can special-case
  	     it in dr_may_alias_p.  */
+ 	  tree old = ref;
  	  ref = fold_build2_loc (EXPR_LOCATION (ref),
  				 MEM_REF, TREE_TYPE (ref),
  				 base, memoff);
+ 	  MR_DEPENDENCE_CLIQUE (ref) = MR_DEPENDENCE_CLIQUE (old);
+ 	  MR_DEPENDENCE_BASE (ref) = MR_DEPENDENCE_BASE (old);
  	  access_fns.safe_push (access_fn);
  	}
      }
*************** dr_may_alias_p (const struct data_refere
*** 1400,1405 ****
--- 1403,1414 ----
  	return false;
      }
  
+   if ((TREE_CODE (addr_a) == MEM_REF || TREE_CODE (addr_a) == TARGET_MEM_REF)
+       && (TREE_CODE (addr_b) == MEM_REF || TREE_CODE (addr_b) == TARGET_MEM_REF)
+       && MR_DEPENDENCE_CLIQUE (addr_a) == MR_DEPENDENCE_CLIQUE (addr_b)
+       && MR_DEPENDENCE_BASE (addr_a) != MR_DEPENDENCE_BASE (addr_b))
+     return false;
+ 
    /* If we had an evolution in a pointer-based MEM_REF BASE_OBJECT we
       do not know the size of the base-object.  So we cannot do any
       offset/overlap based analysis but have to rely on points-to
Index: trunk/gcc/tree-core.h
===================================================================
*** trunk.orig/gcc/tree-core.h	2014-11-12 11:23:51.787809928 +0100
--- trunk/gcc/tree-core.h	2014-11-17 13:48:03.770526864 +0100
*************** struct GTY(()) tree_base {
*** 812,817 ****
--- 812,827 ----
  
      /* Internal function code.  */
      enum internal_fn ifn;
+ 
+     /* The following two fields are used for MEM_REF and TARGET_MEM_REF
+        expression trees and specify known data non-dependences.  For
+        two memory references in a function they are known to not
+        alias if dependence_info.clique are equal and dependence_info.base
+        are distinct.  */
+     struct {
+       unsigned short clique;
+       unsigned short base;
+     } dependence_info;
    } GTY((skip(""))) u;
  };
  
Index: trunk/gcc/tree.h
===================================================================
*** trunk.orig/gcc/tree.h	2014-11-14 12:13:29.667117835 +0100
--- trunk/gcc/tree.h	2014-11-17 13:48:03.782526864 +0100
*************** extern void protected_set_expr_location
*** 1105,1110 ****
--- 1105,1115 ----
  #define TMR_STEP(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 3))
  #define TMR_INDEX2(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 4))
  
+ #define MR_DEPENDENCE_CLIQUE(NODE) \
+   (TREE_CHECK2 (NODE, MEM_REF, TARGET_MEM_REF)->base.u.dependence_info.clique)
+ #define MR_DEPENDENCE_BASE(NODE) \
+   (TREE_CHECK2 (NODE, MEM_REF, TARGET_MEM_REF)->base.u.dependence_info.base)
+ 
  /* The operands of a BIND_EXPR.  */
  #define BIND_EXPR_VARS(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 0))
  #define BIND_EXPR_BODY(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 1))
Index: trunk/gcc/tree-inline.h
===================================================================
*** trunk.orig/gcc/tree-inline.h	2014-11-11 09:39:42.715864279 +0100
--- trunk/gcc/tree-inline.h	2014-11-17 13:48:03.793526863 +0100
*************** enum copy_body_cge_which
*** 37,42 ****
--- 37,62 ----
    CB_CGE_MOVE_CLONES
  };
  
+ struct dependence_hasher : default_hashmap_traits
+ {
+   template<typename T>
+   static void
+   mark_deleted (T &e)
+     { gcc_unreachable (); }
+ 
+   template<typename T>
+   static void
+   mark_empty (T &e)
+     { e.m_key = 0; }
+ 
+   template<typename T>
+   static bool
+   is_deleted (T &)
+     { return false; }
+ 
+   template<typename T> static bool is_empty (T &e) { return e.m_key == 0; }
+ };
+ 
  /* Data required for function body duplication.  */
  
  struct copy_body_data
*************** struct copy_body_data
*** 144,149 ****
--- 164,173 ----
    /* Cilk keywords currently need to replace some variables that
       ordinary nested functions do not.  */ 
    bool remap_var_for_cilk;
+ 
+   /* A map from the inlined functions dependence info cliques to
+      equivalents in the function into which it is being inlined.  */
+   hash_map<unsigned short, unsigned short, dependence_hasher> *dependence_map;
  };
  
  /* Weights of constructions for estimate_num_insns.  */
Index: trunk/gcc/gimple-fold.c
===================================================================
*** trunk.orig/gcc/gimple-fold.c	2014-11-14 14:33:54.417749165 +0100
--- trunk/gcc/gimple-fold.c	2014-11-17 13:48:03.799526863 +0100
*************** maybe_canonicalize_mem_ref_addr (tree *t
*** 3042,3048 ****
       accessed is a decl that has the same access semantics as the MEM_REF.  */
    if (TREE_CODE (*t) == MEM_REF
        && TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR
!       && integer_zerop (TREE_OPERAND (*t, 1)))
      {
        tree decl = TREE_OPERAND (TREE_OPERAND (*t, 0), 0);
        tree alias_type = TREE_TYPE (TREE_OPERAND (*t, 1));
--- 3042,3049 ----
       accessed is a decl that has the same access semantics as the MEM_REF.  */
    if (TREE_CODE (*t) == MEM_REF
        && TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR
!       && integer_zerop (TREE_OPERAND (*t, 1))
!       && MR_DEPENDENCE_CLIQUE (*t) == 0)
      {
        tree decl = TREE_OPERAND (TREE_OPERAND (*t, 0), 0);
        tree alias_type = TREE_TYPE (TREE_OPERAND (*t, 1));
Index: trunk/gcc/tree-streamer-in.c
===================================================================
*** trunk.orig/gcc/tree-streamer-in.c	2014-11-17 10:07:56.546104816 +0100
--- trunk/gcc/tree-streamer-in.c	2014-11-17 16:07:09.480161653 +0100
*************** unpack_value_fields (struct data_in *dat
*** 483,489 ****
      unpack_ts_type_common_value_fields (bp, expr);
  
    if (CODE_CONTAINS_STRUCT (code, TS_EXP))
!     SET_EXPR_LOCATION (expr, stream_input_location (bp, data_in));
  
    if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
      unpack_ts_block_value_fields (data_in, bp, expr);
--- 483,500 ----
      unpack_ts_type_common_value_fields (bp, expr);
  
    if (CODE_CONTAINS_STRUCT (code, TS_EXP))
!     {
!       SET_EXPR_LOCATION (expr, stream_input_location (bp, data_in));
!       if (code == MEM_REF
! 	  || code == TARGET_MEM_REF)
! 	{
! 	  MR_DEPENDENCE_CLIQUE (expr)
! 	    = (unsigned)bp_unpack_value (bp, sizeof (short) * 8);
! 	  if (MR_DEPENDENCE_CLIQUE (expr) != 0)
! 	    MR_DEPENDENCE_BASE (expr)
! 	      = (unsigned)bp_unpack_value (bp, sizeof (short) * 8);
! 	}
!     }
  
    if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
      unpack_ts_block_value_fields (data_in, bp, expr);
Index: trunk/gcc/tree-streamer-out.c
===================================================================
*** trunk.orig/gcc/tree-streamer-out.c	2014-11-17 10:07:56.543104816 +0100
--- trunk/gcc/tree-streamer-out.c	2014-11-17 16:07:11.495161565 +0100
*************** streamer_pack_tree_bitfields (struct out
*** 446,452 ****
      pack_ts_type_common_value_fields (bp, expr);
  
    if (CODE_CONTAINS_STRUCT (code, TS_EXP))
!     stream_output_location (ob, bp, EXPR_LOCATION (expr));
  
    if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
      pack_ts_block_value_fields (ob, bp, expr);
--- 446,461 ----
      pack_ts_type_common_value_fields (bp, expr);
  
    if (CODE_CONTAINS_STRUCT (code, TS_EXP))
!     {
!       stream_output_location (ob, bp, EXPR_LOCATION (expr));
!       if (code == MEM_REF
! 	  || code == TARGET_MEM_REF)
! 	{
! 	  bp_pack_value (bp, MR_DEPENDENCE_CLIQUE (expr), sizeof (short) * 8);
! 	  if (MR_DEPENDENCE_CLIQUE (expr) != 0)
! 	    bp_pack_value (bp, MR_DEPENDENCE_BASE (expr), sizeof (short) * 8);
! 	}
!     }
  
    if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
      pack_ts_block_value_fields (ob, bp, expr);

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2014-11-17 15:24 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-17 15:38 [PATCH] Fix PR55334 - preserve restrict through inlining/cloning Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).