[PATCH v2 3/5] dr: Add no-wrap bound.

Robin Dapp <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
From: Robin Dapp <[email protected]>

This patch adds a nowrap_bound field to data_reference which denotes the
upper bound under which the DR is non wrapping.

dr_analyze_innermost, create_data_ref, and find_data_references_in_stmt
get an additional parameter to control whether or not a no-wrap bound
should be recorded.

gcc/ChangeLog:

	* tree-data-ref.cc (dr_analyze_innermost): Add nowrap-bound param.
	(dr_analyze_indices): Likewise.
	(create_data_ref): Likewise.
	(find_data_references_in_stmt): Add allow_assumptions param.
	* tree-data-ref.h (struct data_reference): Add nowrap_bound.
	(DR_NOWRAP_BOUND): New.
	(dr_analyze_innermost): Pass on nowrap_bound.
	(find_data_references_in_stmt): Likewise.
---
 gcc/tree-data-ref.cc | 96 +++++++++++++++++++++++++++++++++++---------
 gcc/tree-data-ref.h  | 14 +++++--
 2 files changed, 88 insertions(+), 22 deletions(-)

diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc
index 8e9d7871348..364fd1214b7 100644
--- a/gcc/tree-data-ref.cc
+++ b/gcc/tree-data-ref.cc
@@ -1129,11 +1129,15 @@ canonicalize_base_object_address (tree addr)
    dummy outermost loop.  In other cases perform loop analysis.
 
    Return true if the analysis succeeded and store the results in DRB if so.
-   BB analysis can only fail for bitfield or reversed-storage accesses.  */
+   BB analysis can only fail for bitfield or reversed-storage accesses.
+
+   If NOWRAP_BOUND is nonzero, allow simple_iv to record no-wrap bounds.
+   Then, store non-trivial bounds in NOWRAP_BOUND.  */
 
 opt_result
 dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
-		      class loop *loop, const gimple *stmt)
+		      class loop *loop, const gimple *stmt,
+		      tree *nowrap_bound)
 {
   poly_int64 pbitsize, pbitpos;
   tree base, poffset;
@@ -1195,9 +1199,11 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
       base = build_fold_addr_expr (base);
     }
 
+  bool allow_wrapping = (nowrap_bound != nullptr);
+
   if (in_loop)
     {
-      if (!simple_iv (loop, loop, base, &base_iv, true))
+      if (!simple_iv (loop, loop, base, &base_iv, true, allow_wrapping))
 	return opt_result::failure_at
 	  (stmt, "failed: evolution of base is not affine.\n");
     }
@@ -1206,25 +1212,35 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
       base_iv.base = base;
       base_iv.step = ssize_int (0);
       base_iv.no_overflow = true;
+      base_iv.nowrap_bound = NULL_TREE;
     }
 
   if (!poffset)
     {
       offset_iv.base = ssize_int (0);
       offset_iv.step = ssize_int (0);
+      offset_iv.nowrap_bound = NULL_TREE;
     }
   else
     {
       if (!in_loop)
-        {
-          offset_iv.base = poffset;
-          offset_iv.step = ssize_int (0);
-        }
-      else if (!simple_iv (loop, loop, poffset, &offset_iv, true))
+	{
+	  offset_iv.base = poffset;
+	  offset_iv.step = ssize_int (0);
+	  offset_iv.nowrap_bound = NULL_TREE;
+	}
+      else if (!simple_iv (loop, loop, poffset, &offset_iv, true,
+			   allow_wrapping))
 	return opt_result::failure_at
 	  (stmt, "failed: evolution of offset is not affine.\n");
     }
 
+  if (nowrap_bound)
+    {
+      *nowrap_bound = base_iv.nowrap_bound;
+      scev_combine_nowrap_bounds (nowrap_bound, offset_iv.nowrap_bound);
+    }
+
   init = ssize_int (pbytepos);
 
   /* Subtract any constant component from the base and add it to INIT instead.
@@ -1322,10 +1338,14 @@ base_supports_access_fn_components_p (tree base)
 }
 
 /* Determines the base object and the list of indices of memory reference
-   DR, analyzed in LOOP and instantiated before NEST.  */
+   DR, analyzed in LOOP and instantiated before NEST.
+
+   If NOWRAP_BOUND is nonzero, pass it to scev which will then store
+   the bound under which we do not wrap.  */
 
 static void
-dr_analyze_indices (struct indices *dri, tree ref, edge nest, loop_p loop)
+dr_analyze_indices (struct indices *dri, tree ref, edge nest, loop_p loop,
+		    tree *nowrap_bound = nullptr)
 {
   /* If analyzing a basic-block there are no indices to analyze
      and thus no access functions.  */
@@ -1360,7 +1380,7 @@ dr_analyze_indices (struct indices *dri, tree ref, edge nest, loop_p loop)
       if (TREE_CODE (ref) == ARRAY_REF)
 	{
 	  tree op = TREE_OPERAND (ref, 1);
-	  tree access_fn = analyze_scalar_evolution (loop, op);
+	  tree access_fn = analyze_scalar_evolution (loop, op, nowrap_bound);
 	  access_fn = instantiate_scev (nest, loop, access_fn);
 	  access_fns.safe_push (access_fn);
 	}
@@ -1402,7 +1422,7 @@ dr_analyze_indices (struct indices *dri, tree ref, edge nest, loop_p loop)
   if (TREE_CODE (ref) == MEM_REF)
     {
       tree op = TREE_OPERAND (ref, 0);
-      tree access_fn = analyze_scalar_evolution (loop, op);
+      tree access_fn = analyze_scalar_evolution (loop, op, nowrap_bound);
       access_fn = instantiate_scev (nest, loop, access_fn);
       STRIP_NOPS (access_fn);
       if (TREE_CODE (access_fn) == POLYNOMIAL_CHREC)
@@ -1508,11 +1528,16 @@ free_data_ref (data_reference_p dr)
 
    Return the data_reference description of MEMREF.  NEST is the outermost
    loop in which the reference should be instantiated, LOOP is the loop
-   in which the data reference should be analyzed.  */
+   in which the data reference should be analyzed.
+
+   If ALLOW_ASSUMPTIONS is true, pass an empty no-wrap bound to scev and
+   have it store its assumptions there.  If we got a nontrivial
+   assumption, save it in DR's DR_NOWRAP_BOUND.  */
 
 struct data_reference *
 create_data_ref (edge nest, loop_p loop, tree memref, gimple *stmt,
-		 bool is_read, bool is_conditional_in_stmt)
+		 bool is_read, bool is_conditional_in_stmt,
+		 bool allow_assumptions)
 {
   struct data_reference *dr;
 
@@ -1529,11 +1554,25 @@ create_data_ref (edge nest, loop_p loop, tree memref, gimple *stmt,
   DR_IS_READ (dr) = is_read;
   DR_IS_CONDITIONAL_IN_STMT (dr) = is_conditional_in_stmt;
 
+  tree nowrap_bound = NULL_TREE;
   dr_analyze_innermost (&DR_INNERMOST (dr), memref,
-			nest != NULL ? loop : NULL, stmt);
-  dr_analyze_indices (&dr->indices, DR_REF (dr), nest, loop);
+			nest != NULL ? loop : NULL, stmt,
+			allow_assumptions ? &nowrap_bound : nullptr);
+  dr_analyze_indices (&dr->indices, DR_REF (dr), nest, loop,
+		      allow_assumptions ? &nowrap_bound : nullptr);
   dr_analyze_alias (dr);
 
+  if (nowrap_bound)
+    {
+      /* If there is a bound but it is zero, the assumption we build with it
+	 would never hold and we would always fall back to the scalar loop.
+	 Reset the DR so we can still get gather/scatter.  */
+      if (integer_zerop (nowrap_bound))
+	dr_reset (dr);
+      else
+	DR_NOWRAP_BOUND (dr) = nowrap_bound;
+    }
+
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       unsigned i;
@@ -1553,6 +1592,11 @@ create_data_ref (edge nest, loop_p loop, tree memref, gimple *stmt,
       fprintf (dump_file, "\n\tstep alignment: %d", DR_STEP_ALIGNMENT (dr));
       fprintf (dump_file, "\n\tbase_object: ");
       print_generic_expr (dump_file, DR_BASE_OBJECT (dr), TDF_SLIM);
+      if (DR_NOWRAP_BOUND (dr))
+	{
+	  fprintf (dump_file, "\n\tnowrap bound: ");
+	  print_generic_expr (dump_file, DR_NOWRAP_BOUND (dr), TDF_SLIM);
+	}
       fprintf (dump_file, "\n");
       for (i = 0; i < DR_NUM_DIMENSIONS (dr); i++)
 	{
@@ -6037,11 +6081,14 @@ loop_nest_has_data_refs (loop_p loop)
 
 /* Stores the data references in STMT to DATAREFS.  If there is an unanalyzable
    reference, returns false, otherwise returns true.  NEST is the outermost
-   loop of the loop nest in which the references should be analyzed.  */
+   loop of the loop nest in which the references should be analyzed.
+   ALLOW_ASSUMPTIONS determines whether or not no-wrap assumptions
+   are allowed.  */
 
 opt_result
 find_data_references_in_stmt (class loop *nest, gimple *stmt,
-			      vec<data_reference_p> *datarefs)
+			      vec<data_reference_p> *datarefs,
+			      bool allow_assumptions)
 {
   auto_vec<data_ref_loc, 2> references;
   data_reference_p dr;
@@ -6054,7 +6101,8 @@ find_data_references_in_stmt (class loop *nest, gimple *stmt,
     {
       dr = create_data_ref (nest ? loop_preheader_edge (nest) : NULL,
 			    loop_containing_stmt (stmt), ref.ref,
-			    stmt, ref.is_read, ref.is_conditional_in_stmt);
+			    stmt, ref.is_read, ref.is_conditional_in_stmt,
+			    allow_assumptions);
       gcc_assert (dr != NULL);
       datarefs->safe_push (dr);
     }
@@ -6407,6 +6455,16 @@ free_data_refs (vec<data_reference_p>& datarefs)
   datarefs.release ();
 }
 
+/* Reset DR_INNERMOST, DR_NOWRAP_BOUND, and access functions of DR.  */
+
+void
+dr_reset (data_reference *dr)
+{
+  DR_INNERMOST (dr) = innermost_loop_behavior ();
+  DR_NOWRAP_BOUND (dr) = NULL_TREE;
+  dr->indices.access_fns.release ();
+}
+
 /* Common routine implementing both dr_direction_indicator and
    dr_zero_step_indicator.  Return USEFUL_MIN if the indicator is known
    to be >= USEFUL_MIN and -1 if the indicator is known to be negative.
diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
index e25f98d2966..ba901a5f6ce 100644
--- a/gcc/tree-data-ref.h
+++ b/gcc/tree-data-ref.h
@@ -172,6 +172,10 @@ struct data_reference
   /* Behavior of the memory reference in the innermost loop.  */
   struct innermost_loop_behavior innermost;
 
+  /* Upper bound for the number of loop iterations for which this DR's
+     IV does not wrap.  */
+  tree nowrap_bound;
+
   /* Subscripts of this data reference.  */
   struct indices indices;
 
@@ -201,6 +205,7 @@ struct data_reference
 #define DR_OFFSET_ALIGNMENT(DR)    (DR)->innermost.offset_alignment
 #define DR_STEP_ALIGNMENT(DR)      (DR)->innermost.step_alignment
 #define DR_INNERMOST(DR)           (DR)->innermost
+#define DR_NOWRAP_BOUND(DR)        (DR)->nowrap_bound
 
 typedef struct data_reference *data_reference_p;
 
@@ -520,7 +525,8 @@ typedef struct data_dependence_relation *ddr_p;
 
 
 opt_result dr_analyze_innermost (innermost_loop_behavior *, tree,
-				 class loop *, const gimple *);
+				 class loop *, const gimple *,
+				 tree * = nullptr);
 extern bool compute_data_dependences_for_loop (class loop *, bool,
 					       vec<loop_p> *,
 					       vec<data_reference_p> *,
@@ -542,14 +548,16 @@ extern void free_dependence_relation (struct data_dependence_relation *);
 extern void free_dependence_relations (vec<ddr_p>& );
 extern void free_data_ref (data_reference_p);
 extern void free_data_refs (vec<data_reference_p>& );
+void dr_reset (data_reference *);
 extern opt_result find_data_references_in_stmt (class loop *, gimple *,
-						vec<data_reference_p> *);
+						vec<data_reference_p> *,
+						bool = false);
 extern bool graphite_find_data_references_in_stmt (edge, loop_p, gimple *,
 						   vec<data_reference_p> *);
 tree find_data_references_in_loop (class loop *, vec<data_reference_p> *);
 bool loop_nest_has_data_refs (loop_p loop);
 struct data_reference *create_data_ref (edge, loop_p, tree, gimple *, bool,
-					bool);
+					bool, bool = false);
 extern bool find_loop_nest (class loop *, vec<loop_p> *);
 extern struct data_dependence_relation *initialize_data_dependence_relation
      (struct data_reference *, struct data_reference *, vec<loop_p>);
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.