[polly] r294093 - [Support] Add computeArrayUnused. NFC.
Michael Kruse via llvm-commits
llvm-commits at lists.llvm.org
Sat Feb 4 07:42:10 PST 2017
Author: meinersbur
Date: Sat Feb 4 09:42:10 2017
New Revision: 294093
URL: http://llvm.org/viewvc/llvm-project?rev=294093&view=rev
Log:
[Support] Add computeArrayUnused. 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=294093&r1=294092&r2=294093&view=diff
==============================================================================
--- polly/trunk/include/polly/Support/ISLTools.h (original)
+++ polly/trunk/include/polly/Support/ISLTools.h Sat Feb 4 09:42:10 2017
@@ -233,6 +233,72 @@ IslPtr<isl_union_map> computeReachingWri
bool Reverse, bool InclPrevDef,
bool InclNextDef);
+/// Compute the timepoints where the contents of an array element are not used.
+///
+/// An element is unused at a timepoint when the element is overwritten in
+/// the future, but it is not read in between. Another way to express this: the
+/// time from when the element is written, to the most recent read before it, or
+/// infinitely into the past if there is no read before. Such unused elements
+/// can be overwritten by any value without changing the scop's semantics. An
+/// example:
+///
+/// Schedule := { Read[] -> [0]; Write[] -> [10]; Def[] -> [20] }
+/// Writes := { Write[] -> A[5]; Def[] -> A[6] }
+/// Reads := { Read[] -> A[5] }
+///
+/// The result is:
+///
+/// { A[5] -> [i] : 0 < i < 10;
+/// A[6] -> [i] : i < 20 }
+///
+/// That is, A[5] is unused between timepoint 0 (the read) and timepoint 10 (the
+/// write). A[6] is unused before timepoint 20, but might be used after the
+/// scop's execution (A[5] and any other A[i] as well). Use InclLastRead=false
+/// and InclWrite=true to interpret the result as zone.
+///
+/// @param Schedule { Domain[] -> Scatter[] }
+/// The schedule of (at least) all statement instances
+/// occurring in @p Writes or @p Reads. All other
+/// instances are ignored.
+/// @param Writes { DomainWrite[] -> Element[] }
+/// Elements written to by the statement instances.
+/// @param Reads { DomainRead[] -> Element[] }
+/// Elements read from by the statement instances.
+/// @param ReadEltInSameInst Whether a load reads the value from a write
+/// that is scheduled at the same timepoint (Writes
+/// happen before reads). Otherwise, loads use the
+/// value of an element that it had before the
+/// timepoint (Reads before writes). For example:
+/// { Read[] -> [0]; Write[] -> [0] }
+/// With ReadEltInSameInst=false it is assumed that the
+/// read happens before the write, such that the
+/// element is never unused, or just at timepoint 0,
+/// depending on InclLastRead/InclWrite.
+/// With ReadEltInSameInst=false it assumes that the
+/// value just written is used. Anything before
+/// timepoint 0 is considered unused.
+/// @param InclLastRead Whether a timepoint where an element is last read
+/// counts as unused (the read happens at the beginning
+/// of its timepoint, and nothing (else) can use it
+/// during the timepoint). In the example, this option
+/// adds { A[5] -> [0] } to the result.
+/// @param InclWrite Whether the timepoint where an element is written
+/// itself counts as unused (the write happens at the
+/// end of its timepoint; no (other) operations uses
+/// the element during the timepoint). In this example,
+/// this adds
+/// { A[5] -> [10]; A[6] -> [20] } to the result.
+///
+/// @return { Element[] -> Scatter[] }
+/// The unused timepoints as defined above, or nullptr if either @p
+/// Schedule, @p Writes are @p Reads is nullptr, or the ISL max
+/// operations count is exceeded.
+IslPtr<isl_union_map> computeArrayUnused(IslPtr<isl_union_map> Schedule,
+ IslPtr<isl_union_map> Writes,
+ IslPtr<isl_union_map> Reads,
+ bool ReadEltInSameInst,
+ bool InclLastRead, bool InclWrite);
+
} // 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=294093&r1=294092&r2=294093&view=diff
==============================================================================
--- polly/trunk/lib/Support/ISLTools.cpp (original)
+++ polly/trunk/lib/Support/ISLTools.cpp Sat Feb 4 09:42:10 2017
@@ -320,3 +320,50 @@ polly::computeReachingWrite(IslPtr<isl_u
return ReachableWriteDomain;
}
+
+IslPtr<isl_union_map> polly::computeArrayUnused(IslPtr<isl_union_map> Schedule,
+ IslPtr<isl_union_map> Writes,
+ IslPtr<isl_union_map> Reads,
+ bool ReadEltInSameInst,
+ bool IncludeLastRead,
+ bool IncludeWrite) {
+ // { Element[] -> Scatter[] }
+ auto ReadActions =
+ give(isl_union_map_apply_domain(Schedule.copy(), Reads.take()));
+ auto WriteActions =
+ give(isl_union_map_apply_domain(Schedule.copy(), Writes.copy()));
+
+ // { [Element[] -> Scatter[] }
+ auto AfterReads = afterScatter(ReadActions, ReadEltInSameInst);
+ auto WritesBeforeAnyReads =
+ give(isl_union_map_subtract(WriteActions.take(), AfterReads.take()));
+ auto BeforeWritesBeforeAnyReads =
+ beforeScatter(WritesBeforeAnyReads, !IncludeWrite);
+
+ // { [Element[] -> DomainWrite[]] -> Scatter[] }
+ auto EltDomWrites = give(isl_union_map_apply_range(
+ isl_union_map_range_map(isl_union_map_reverse(Writes.copy())),
+ Schedule.copy()));
+
+ // { [Element[] -> Scatter[]] -> DomainWrite[] }
+ auto ReachingOverwrite = computeReachingWrite(
+ Schedule, Writes, true, ReadEltInSameInst, !ReadEltInSameInst);
+
+ // { [Element[] -> Scatter[]] -> DomainWrite[] }
+ auto ReadsOverwritten = give(isl_union_map_intersect_domain(
+ ReachingOverwrite.take(), isl_union_map_wrap(ReadActions.take())));
+
+ // { [Element[] -> DomainWrite[]] -> Scatter[] }
+ auto ReadsOverwrittenRotated = give(isl_union_map_reverse(
+ isl_union_map_curry(reverseDomain(ReadsOverwritten).take())));
+ auto LastOverwrittenRead =
+ give(isl_union_map_lexmax(ReadsOverwrittenRotated.take()));
+
+ // { [Element[] -> DomainWrite[]] -> Scatter[] }
+ auto BetweenLastReadOverwrite = betweenScatter(
+ LastOverwrittenRead, EltDomWrites, IncludeLastRead, IncludeWrite);
+
+ return give(isl_union_map_union(
+ BeforeWritesBeforeAnyReads.take(),
+ isl_union_map_domain_factor_domain(BetweenLastReadOverwrite.take())));
+}
Modified: polly/trunk/unittests/Isl/IslTest.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/unittests/Isl/IslTest.cpp?rev=294093&r1=294092&r2=294093&view=diff
==============================================================================
--- polly/trunk/unittests/Isl/IslTest.cpp (original)
+++ polly/trunk/unittests/Isl/IslTest.cpp Sat Feb 4 09:42:10 2017
@@ -741,4 +741,70 @@ TEST(DeLICM, computeReachingWrite) {
false, true));
}
+TEST(DeLICM, computeArrayUnused) {
+ std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+ &isl_ctx_free);
+
+ // The ReadEltInSameInst parameter doesn't matter in simple cases. To also
+ // cover the parameter without duplicating the tests, this loops runs over
+ // other in both settings.
+ for (bool ReadEltInSameInst = false, Done = false; !Done;
+ Done = ReadEltInSameInst, ReadEltInSameInst = true) {
+ // Basic usage: one read, one write
+ EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 < i < 10 }"),
+ computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"),
+ UMAP("{ Write[] -> Elt[] }"),
+ UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst,
+ false, false));
+ EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 < i <= 10 }"),
+ computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"),
+ UMAP("{ Write[] -> Elt[] }"),
+ UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst,
+ false, true));
+ EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 <= i < 10 }"),
+ computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"),
+ UMAP("{ Write[] -> Elt[] }"),
+ UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst,
+ true, false));
+ EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 <= i <= 10 }"),
+ computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"),
+ UMAP("{ Write[] -> Elt[] }"),
+ UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst,
+ true, true));
+
+ // Two reads
+ EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 < i <= 10 }"),
+ computeArrayUnused(
+ UMAP("{ Read[0] -> [-10]; Read[1] -> [0]; Write[] -> [10] }"),
+ UMAP("{ Write[] -> Elt[] }"), UMAP("{ Read[i] -> Elt[] }"),
+ ReadEltInSameInst, false, true));
+
+ // Corner case: no writes
+ EXPECT_EQ(UMAP("{}"),
+ computeArrayUnused(UMAP("{ Read[] -> [0] }"), UMAP("{}"),
+ UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst,
+ false, false));
+
+ // Corner case: no reads
+ EXPECT_EQ(UMAP("{ Elt[] -> [i] : i <= 0 }"),
+ computeArrayUnused(UMAP("{ Write[] -> [0] }"),
+ UMAP("{ Write[] -> Elt[] }"), UMAP("{}"),
+ ReadEltInSameInst, false, true));
+ }
+
+ // Read and write in same statement
+ EXPECT_EQ(UMAP("{ Elt[] -> [i] : i < 0 }"),
+ computeArrayUnused(UMAP("{ RW[] -> [0] }"),
+ UMAP("{ RW[] -> Elt[] }"),
+ UMAP("{ RW[] -> Elt[] }"), true, false, false));
+ EXPECT_EQ(UMAP("{ Elt[] -> [i] : i <= 0 }"),
+ computeArrayUnused(UMAP("{ RW[] -> [0] }"),
+ UMAP("{ RW[] -> Elt[] }"),
+ UMAP("{ RW[] -> Elt[] }"), true, false, true));
+ EXPECT_EQ(UMAP("{ Elt[] -> [0] }"),
+ computeArrayUnused(UMAP("{ RW[] -> [0] }"),
+ UMAP("{ RW[] -> Elt[] }"),
+ UMAP("{ RW[] -> Elt[] }"), false, true, true));
+}
+
} // anonymous namespace
More information about the llvm-commits
mailing list