[polly] r294092 - [Support] Add computeReachingWrite. NFC.

Michael Kruse via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 4 07:42:03 PST 2017


Author: meinersbur
Date: Sat Feb  4 09:42:01 2017
New Revision: 294092

URL: http://llvm.org/viewvc/llvm-project?rev=294092&view=rev
Log:
[Support] Add computeReachingWrite. NFC.

This function has been extracted from the upcoming DeLICM patch
(https://reviews.llvm.org/D24716).

Modified:
    polly/trunk/include/polly/Support/ISLTools.h
    polly/trunk/lib/Support/ISLTools.cpp
    polly/trunk/unittests/Isl/IslTest.cpp

Modified: polly/trunk/include/polly/Support/ISLTools.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/Support/ISLTools.h?rev=294092&r1=294091&r2=294092&view=diff
==============================================================================
--- polly/trunk/include/polly/Support/ISLTools.h (original)
+++ polly/trunk/include/polly/Support/ISLTools.h Sat Feb  4 09:42:01 2017
@@ -175,6 +175,64 @@ void simplify(IslPtr<isl_map> &Map);
 /// Simplify a union map inplace.
 void simplify(IslPtr<isl_union_map> &UMap);
 
+/// Compute the reaching definition statement or the next overwrite for each
+/// definition of an array element.
+///
+/// The reaching definition of an array element at a specific timepoint is the
+/// statement instance that has written the current element's content.
+/// Alternatively, this function determines for each timepoint and element which
+/// write is going to overwrite an element at a future timepoint. This can be
+/// seen as "reaching definition in reverse" where definitions are found in the
+/// past.
+///
+/// For example:
+///
+/// Schedule := { Write[] -> [0]; Overwrite[] -> [10] }
+/// Defs := { Write[] -> A[5]; Overwrite[] -> A[5] }
+///
+/// If index 5 of array A is written at timepoint 0 and 10, the resulting
+/// reaching definitions are:
+///
+/// { [A[5] -> [i]] -> Write[] : 0 < i < 10;
+///   [A[5] -> [i]] -> Overwrite[] : 10 < i }
+///
+/// Between timepoint 0 (Write[]) and timepoint 10 (Overwrite[]), the
+/// content of A[5] is written by statement instance Write[] and after
+/// timepoint 10 by Overwrite[]. Values not defined in the map have no known
+/// definition. This includes the statement instance timepoints themselves,
+/// because reads at those timepoints could either read the old or the new
+/// value, defined only by the statement itself. But this can be changed by @p
+/// InclPrevDef and @p InclNextDef. InclPrevDef=false and InclNextDef=true
+/// returns a zone. Unless @p InclPrevDef and @p InclNextDef are both true,
+/// there is only one unique definition per element and timepoint.
+///
+/// @param Schedule    { DomainWrite[] -> Scatter[] }
+///                    Schedule of (at least) all array writes. Instances not in
+///                    @p Writes are ignored.
+/// @param Writes      { DomainWrite[] -> Element[] }
+///                    Elements written to by the statement instances.
+/// @param Reverse     If true, look for definitions in the future. That is,
+///                    find the write that is overwrites the current value.
+/// @param InclPrevDef Include the definition's timepoint to the set of
+///                    well-defined elements (any load at that timepoint happen
+///                    at the writes). In the example, enabling this option adds
+///                    {[A[5] -> [0]] -> Write[]; [A[5] -> [10]] -> Overwrite[]}
+///                    to the result.
+/// @param InclNextDef Whether to assume that at the timepoint where an element
+///                    is overwritten, it still contains the old value (any load
+///                    at that timepoint would happen before the overwrite). In
+///                    this example, enabling this adds
+///                    { [A[] -> [10]] -> Write[] } to the result.
+///
+/// @return { [Element[] -> Scatter[]] -> DomainWrite[] }
+///         The reaching definitions or future overwrite as described above, or
+///         nullptr if either @p Schedule or @p Writes is nullptr, or the isl
+///         max operations count has exceeded.
+IslPtr<isl_union_map> computeReachingWrite(IslPtr<isl_union_map> Schedule,
+                                           IslPtr<isl_union_map> Writes,
+                                           bool Reverse, bool InclPrevDef,
+                                           bool InclNextDef);
+
 } // namespace polly
 
 #endif /* POLLY_ISLTOOLS_H */

Modified: polly/trunk/lib/Support/ISLTools.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/ISLTools.cpp?rev=294092&r1=294091&r2=294092&view=diff
==============================================================================
--- polly/trunk/lib/Support/ISLTools.cpp (original)
+++ polly/trunk/lib/Support/ISLTools.cpp Sat Feb  4 09:42:01 2017
@@ -260,3 +260,63 @@ void polly::simplify(IslPtr<isl_union_ma
   UMap = give(isl_union_map_detect_equalities(UMap.take()));
   UMap = give(isl_union_map_coalesce(UMap.take()));
 }
+
+IslPtr<isl_union_map>
+polly::computeReachingWrite(IslPtr<isl_union_map> Schedule,
+                            IslPtr<isl_union_map> Writes, bool Reverse,
+                            bool InclPrevDef, bool InclNextDef) {
+
+  // { Scatter[] }
+  auto ScatterSpace = getScatterSpace(Schedule);
+
+  // { ScatterRead[] -> ScatterWrite[] }
+  IslPtr<isl_map> Relation;
+  if (Reverse)
+    Relation = give(InclPrevDef ? isl_map_lex_lt(ScatterSpace.take())
+                                : isl_map_lex_le(ScatterSpace.take()));
+  else
+    Relation = give(InclNextDef ? isl_map_lex_gt(ScatterSpace.take())
+                                : isl_map_lex_ge(ScatterSpace.take()));
+
+  // { ScatterWrite[] -> [ScatterRead[] -> ScatterWrite[]] }
+  auto RelationMap = give(isl_map_reverse(isl_map_range_map(Relation.take())));
+
+  // { Element[] -> ScatterWrite[] }
+  auto WriteAction =
+      give(isl_union_map_apply_domain(Schedule.copy(), Writes.take()));
+
+  // { ScatterWrite[] -> Element[] }
+  auto WriteActionRev = give(isl_union_map_reverse(WriteAction.copy()));
+
+  // { Element[] -> [ScatterUse[] -> ScatterWrite[]] }
+  auto DefSchedRelation = give(isl_union_map_apply_domain(
+      isl_union_map_from_map(RelationMap.take()), WriteActionRev.take()));
+
+  // For each element, at every point in time, map to the times of previous
+  // definitions. { [Element[] -> ScatterRead[]] -> ScatterWrite[] }
+  auto ReachableWrites = give(isl_union_map_uncurry(DefSchedRelation.take()));
+  if (Reverse)
+    ReachableWrites = give(isl_union_map_lexmin(ReachableWrites.copy()));
+  else
+    ReachableWrites = give(isl_union_map_lexmax(ReachableWrites.copy()));
+
+  // { [Element[] -> ScatterWrite[]] -> ScatterWrite[] }
+  auto SelfUse = give(isl_union_map_range_map(WriteAction.take()));
+
+  if (InclPrevDef && InclNextDef) {
+    // Add the Def itself to the solution.
+    ReachableWrites =
+        give(isl_union_map_union(ReachableWrites.take(), SelfUse.take()));
+    ReachableWrites = give(isl_union_map_coalesce(ReachableWrites.take()));
+  } else if (!InclPrevDef && !InclNextDef) {
+    // Remove Def itself from the solution.
+    ReachableWrites =
+        give(isl_union_map_subtract(ReachableWrites.take(), SelfUse.take()));
+  }
+
+  // { [Element[] -> ScatterRead[]] -> Domain[] }
+  auto ReachableWriteDomain = give(isl_union_map_apply_range(
+      ReachableWrites.take(), isl_union_map_reverse(Schedule.take())));
+
+  return ReachableWriteDomain;
+}

Modified: polly/trunk/unittests/Isl/IslTest.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/unittests/Isl/IslTest.cpp?rev=294092&r1=294091&r2=294092&view=diff
==============================================================================
--- polly/trunk/unittests/Isl/IslTest.cpp (original)
+++ polly/trunk/unittests/Isl/IslTest.cpp Sat Feb  4 09:42:01 2017
@@ -637,4 +637,108 @@ TEST(ISLTools, shiftDim) {
   EXPECT_EQ(USET("[n] -> { [n+1] }"), shiftDim(USET("[n] -> { [n] }"), 0, 1));
 }
 
+TEST(DeLICM, computeReachingWrite) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 < i }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), false, false,
+                                 false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 < i }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), false, false,
+                                 true));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 <= i }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), false, true,
+                                 false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 <= i }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), false, true,
+                                 false));
+
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : i < 0 }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), true, false,
+                                 false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] :  i <= 0 }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), true, false,
+                                 true));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : i < 0 }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), true, true,
+                                 false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : i <= 0 }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), true, true, true));
+
+  // Two writes
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 < i < 10; [Elt[] -> [i]] -> "
+                 "Dom2[] : 10 < i }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 false, false, false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 <= i < 10; [Elt[] -> [i]] -> "
+                 "Dom2[] : 10 <= i }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 false, true, false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 < i <= 10; [Elt[] -> [i]] -> "
+                 "Dom2[] : 10 < i }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 false, false, true));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 <= i <= 10; [Elt[] -> [i]] -> "
+                 "Dom2[] : 10 <= i }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 false, true, true));
+
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 < i < 10; [Elt[] -> [i]] -> "
+                 "Dom1[] : i < 0 }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 true, false, false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 <= i < 10; [Elt[] -> [i]] -> "
+                 "Dom1[] : i < 0 }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 true, true, false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 < i <= 10; [Elt[] -> [i]] -> "
+                 "Dom1[] : i <= 0 }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 true, false, true));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 <= i <= 10; [Elt[] -> [i]] -> "
+                 "Dom1[] : i <= 0 }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 true, true, true));
+
+  // Domain in same space
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[1] : 0 < i <= 10; [Elt[] -> [i]] -> "
+                 "Dom[2] : 10 < i }"),
+            computeReachingWrite(UMAP("{ Dom[i] -> [10i - 10] }"),
+                                 UMAP("{ Dom[1] -> Elt[]; Dom[2] -> Elt[] }"),
+                                 false, false, true));
+
+  // Parametric
+  EXPECT_EQ(UMAP("[p] -> { [Elt[] -> [i]] -> Dom[] : p < i }"),
+            computeReachingWrite(UMAP("[p] -> { Dom[] -> [p] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), false, false,
+                                 false));
+
+  // More realistic example (from reduction_embedded.ll)
+  EXPECT_EQ(
+      UMAP("{ [Elt[] -> [i]] -> Dom[0] : 0 < i <= 3; [Elt[] -> [i]] -> Dom[1] "
+           ": 3 < i <= 6; [Elt[] -> [i]] -> Dom[2] : 6 < i <= 9; [Elt[] -> "
+           "[i]] -> Dom[3] : 9 < i <= 12; [Elt[] -> [i]] -> Dom[4] : 12 < i }"),
+      computeReachingWrite(UMAP("{ Dom[i] -> [3i] : 0 <= i <= 4 }"),
+                           UMAP("{ Dom[i] -> Elt[] : 0 <= i <= 4 }"), false,
+                           false, true));
+}
+
 } // anonymous namespace




More information about the llvm-commits mailing list