ZoneAlgo.cpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172
  1. //===------ ZoneAlgo.cpp ----------------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // Derive information about array elements between statements ("Zones").
  10. //
  11. // The algorithms here work on the scatter space - the image space of the
  12. // schedule returned by Scop::getSchedule(). We call an element in that space a
  13. // "timepoint". Timepoints are lexicographically ordered such that we can
  14. // defined ranges in the scatter space. We use two flavors of such ranges:
  15. // Timepoint sets and zones. A timepoint set is simply a subset of the scatter
  16. // space and is directly stored as isl_set.
  17. //
  18. // Zones are used to describe the space between timepoints as open sets, i.e.
  19. // they do not contain the extrema. Using isl rational sets to express these
  20. // would be overkill. We also cannot store them as the integer timepoints they
  21. // contain; the (nonempty) zone between 1 and 2 would be empty and
  22. // indistinguishable from e.g. the zone between 3 and 4. Also, we cannot store
  23. // the integer set including the extrema; the set ]1,2[ + ]3,4[ could be
  24. // coalesced to ]1,3[, although we defined the range [2,3] to be not in the set.
  25. // Instead, we store the "half-open" integer extrema, including the lower bound,
  26. // but excluding the upper bound. Examples:
  27. //
  28. // * The set { [i] : 1 <= i <= 3 } represents the zone ]0,3[ (which contains the
  29. // integer points 1 and 2, but not 0 or 3)
  30. //
  31. // * { [1] } represents the zone ]0,1[
  32. //
  33. // * { [i] : i = 1 or i = 3 } represents the zone ]0,1[ + ]2,3[
  34. //
  35. // Therefore, an integer i in the set represents the zone ]i-1,i[, i.e. strictly
  36. // speaking the integer points never belong to the zone. However, depending an
  37. // the interpretation, one might want to include them. Part of the
  38. // interpretation may not be known when the zone is constructed.
  39. //
  40. // Reads are assumed to always take place before writes, hence we can think of
  41. // reads taking place at the beginning of a timepoint and writes at the end.
  42. //
  43. // Let's assume that the zone represents the lifetime of a variable. That is,
  44. // the zone begins with a write that defines the value during its lifetime and
  45. // ends with the last read of that value. In the following we consider whether a
  46. // read/write at the beginning/ending of the lifetime zone should be within the
  47. // zone or outside of it.
  48. //
  49. // * A read at the timepoint that starts the live-range loads the previous
  50. // value. Hence, exclude the timepoint starting the zone.
  51. //
  52. // * A write at the timepoint that starts the live-range is not defined whether
  53. // it occurs before or after the write that starts the lifetime. We do not
  54. // allow this situation to occur. Hence, we include the timepoint starting the
  55. // zone to determine whether they are conflicting.
  56. //
  57. // * A read at the timepoint that ends the live-range reads the same variable.
  58. // We include the timepoint at the end of the zone to include that read into
  59. // the live-range. Doing otherwise would mean that the two reads access
  60. // different values, which would mean that the value they read are both alive
  61. // at the same time but occupy the same variable.
  62. //
  63. // * A write at the timepoint that ends the live-range starts a new live-range.
  64. // It must not be included in the live-range of the previous definition.
  65. //
  66. // All combinations of reads and writes at the endpoints are possible, but most
  67. // of the time only the write->read (for instance, a live-range from definition
  68. // to last use) and read->write (for instance, an unused range from last use to
  69. // overwrite) and combinations are interesting (half-open ranges). write->write
  70. // zones might be useful as well in some context to represent
  71. // output-dependencies.
  72. //
  73. // @see convertZoneToTimepoints
  74. //
  75. //
  76. // The code makes use of maps and sets in many different spaces. To not loose
  77. // track in which space a set or map is expected to be in, variables holding an
  78. // isl reference are usually annotated in the comments. They roughly follow isl
  79. // syntax for spaces, but only the tuples, not the dimensions. The tuples have a
  80. // meaning as follows:
  81. //
  82. // * Space[] - An unspecified tuple. Used for function parameters such that the
  83. // function caller can use it for anything they like.
  84. //
  85. // * Domain[] - A statement instance as returned by ScopStmt::getDomain()
  86. // isl_id_get_name: Stmt_<NameOfBasicBlock>
  87. // isl_id_get_user: Pointer to ScopStmt
  88. //
  89. // * Element[] - An array element as in the range part of
  90. // MemoryAccess::getAccessRelation()
  91. // isl_id_get_name: MemRef_<NameOfArrayVariable>
  92. // isl_id_get_user: Pointer to ScopArrayInfo
  93. //
  94. // * Scatter[] - Scatter space or space of timepoints
  95. // Has no tuple id
  96. //
  97. // * Zone[] - Range between timepoints as described above
  98. // Has no tuple id
  99. //
  100. // * ValInst[] - An llvm::Value as defined at a specific timepoint.
  101. //
  102. // A ValInst[] itself can be structured as one of:
  103. //
  104. // * [] - An unknown value.
  105. // Always zero dimensions
  106. // Has no tuple id
  107. //
  108. // * Value[] - An llvm::Value that is read-only in the SCoP, i.e. its
  109. // runtime content does not depend on the timepoint.
  110. // Always zero dimensions
  111. // isl_id_get_name: Val_<NameOfValue>
  112. // isl_id_get_user: A pointer to an llvm::Value
  113. //
  114. // * SCEV[...] - A synthesizable llvm::SCEV Expression.
  115. // In contrast to a Value[] is has at least one dimension per
  116. // SCEVAddRecExpr in the SCEV.
  117. //
  118. // * [Domain[] -> Value[]] - An llvm::Value that may change during the
  119. // Scop's execution.
  120. // The tuple itself has no id, but it wraps a map space holding a
  121. // statement instance which defines the llvm::Value as the map's domain
  122. // and llvm::Value itself as range.
  123. //
  124. // @see makeValInst()
  125. //
  126. // An annotation "{ Domain[] -> Scatter[] }" therefore means: A map from a
  127. // statement instance to a timepoint, aka a schedule. There is only one scatter
  128. // space, but most of the time multiple statements are processed in one set.
  129. // This is why most of the time isl_union_map has to be used.
  130. //
  131. // The basic algorithm works as follows:
  132. // At first we verify that the SCoP is compatible with this technique. For
  133. // instance, two writes cannot write to the same location at the same statement
  134. // instance because we cannot determine within the polyhedral model which one
  135. // comes first. Once this was verified, we compute zones at which an array
  136. // element is unused. This computation can fail if it takes too long. Then the
  137. // main algorithm is executed. Because every store potentially trails an unused
  138. // zone, we start at stores. We search for a scalar (MemoryKind::Value or
  139. // MemoryKind::PHI) that we can map to the array element overwritten by the
  140. // store, preferably one that is used by the store or at least the ScopStmt.
  141. // When it does not conflict with the lifetime of the values in the array
  142. // element, the map is applied and the unused zone updated as it is now used. We
  143. // continue to try to map scalars to the array element until there are no more
  144. // candidates to map. The algorithm is greedy in the sense that the first scalar
  145. // not conflicting will be mapped. Other scalars processed later that could have
  146. // fit the same unused zone will be rejected. As such the result depends on the
  147. // processing order.
  148. //
  149. //===----------------------------------------------------------------------===//
  150. #include "polly/ZoneAlgo.h"
  151. #include "polly/ScopInfo.h"
  152. #include "polly/Support/GICHelper.h"
  153. #include "polly/Support/ISLTools.h"
  154. #include "polly/Support/VirtualInstruction.h"
  155. #include "llvm/ADT/Statistic.h"
  156. #include "llvm/Support/raw_ostream.h"
  157. #define DEBUG_TYPE "polly-zone"
  158. STATISTIC(NumIncompatibleArrays, "Number of not zone-analyzable arrays");
  159. STATISTIC(NumCompatibleArrays, "Number of zone-analyzable arrays");
  160. STATISTIC(NumRecursivePHIs, "Number of recursive PHIs");
  161. STATISTIC(NumNormalizablePHIs, "Number of normalizable PHIs");
  162. STATISTIC(NumPHINormialization, "Number of PHI executed normalizations");
  163. using namespace polly;
  164. using namespace llvm;
  165. static isl::union_map computeReachingDefinition(isl::union_map Schedule,
  166. isl::union_map Writes,
  167. bool InclDef, bool InclRedef) {
  168. return computeReachingWrite(Schedule, Writes, false, InclDef, InclRedef);
  169. }
  170. /// Compute the reaching definition of a scalar.
  171. ///
  172. /// Compared to computeReachingDefinition, there is just one element which is
  173. /// accessed and therefore only a set if instances that accesses that element is
  174. /// required.
  175. ///
  176. /// @param Schedule { DomainWrite[] -> Scatter[] }
  177. /// @param Writes { DomainWrite[] }
  178. /// @param InclDef Include the timepoint of the definition to the result.
  179. /// @param InclRedef Include the timepoint of the overwrite into the result.
  180. ///
  181. /// @return { Scatter[] -> DomainWrite[] }
  182. static isl::union_map computeScalarReachingDefinition(isl::union_map Schedule,
  183. isl::union_set Writes,
  184. bool InclDef,
  185. bool InclRedef) {
  186. // { DomainWrite[] -> Element[] }
  187. isl::union_map Defs = isl::union_map::from_domain(Writes);
  188. // { [Element[] -> Scatter[]] -> DomainWrite[] }
  189. auto ReachDefs =
  190. computeReachingDefinition(Schedule, Defs, InclDef, InclRedef);
  191. // { Scatter[] -> DomainWrite[] }
  192. return ReachDefs.curry().range().unwrap();
  193. }
  194. /// Compute the reaching definition of a scalar.
  195. ///
  196. /// This overload accepts only a single writing statement as an isl_map,
  197. /// consequently the result also is only a single isl_map.
  198. ///
  199. /// @param Schedule { DomainWrite[] -> Scatter[] }
  200. /// @param Writes { DomainWrite[] }
  201. /// @param InclDef Include the timepoint of the definition to the result.
  202. /// @param InclRedef Include the timepoint of the overwrite into the result.
  203. ///
  204. /// @return { Scatter[] -> DomainWrite[] }
  205. static isl::map computeScalarReachingDefinition(isl::union_map Schedule,
  206. isl::set Writes, bool InclDef,
  207. bool InclRedef) {
  208. isl::space DomainSpace = Writes.get_space();
  209. isl::space ScatterSpace = getScatterSpace(Schedule);
  210. // { Scatter[] -> DomainWrite[] }
  211. isl::union_map UMap = computeScalarReachingDefinition(
  212. Schedule, isl::union_set(Writes), InclDef, InclRedef);
  213. isl::space ResultSpace = ScatterSpace.map_from_domain_and_range(DomainSpace);
  214. return singleton(UMap, ResultSpace);
  215. }
  216. isl::union_map polly::makeUnknownForDomain(isl::union_set Domain) {
  217. return isl::union_map::from_domain(Domain);
  218. }
  219. /// Create a domain-to-unknown value mapping.
  220. ///
  221. /// @see makeUnknownForDomain(isl::union_set)
  222. ///
  223. /// @param Domain { Domain[] }
  224. ///
  225. /// @return { Domain[] -> ValInst[] }
  226. static isl::map makeUnknownForDomain(isl::set Domain) {
  227. return isl::map::from_domain(Domain);
  228. }
  229. /// Return whether @p Map maps to an unknown value.
  230. ///
  231. /// @param { [] -> ValInst[] }
  232. static bool isMapToUnknown(const isl::map &Map) {
  233. isl::space Space = Map.get_space().range();
  234. return Space.has_tuple_id(isl::dim::set).is_false() &&
  235. Space.is_wrapping().is_false() &&
  236. Space.dim(isl::dim::set).release() == 0;
  237. }
  238. isl::union_map polly::filterKnownValInst(const isl::union_map &UMap) {
  239. isl::union_map Result = isl::union_map::empty(UMap.ctx());
  240. for (isl::map Map : UMap.get_map_list()) {
  241. if (!isMapToUnknown(Map))
  242. Result = Result.unite(Map);
  243. }
  244. return Result;
  245. }
  246. ZoneAlgorithm::ZoneAlgorithm(const char *PassName, Scop *S, LoopInfo *LI)
  247. : PassName(PassName), IslCtx(S->getSharedIslCtx()), S(S), LI(LI),
  248. Schedule(S->getSchedule()) {
  249. auto Domains = S->getDomains();
  250. Schedule = Schedule.intersect_domain(Domains);
  251. ParamSpace = Schedule.get_space();
  252. ScatterSpace = getScatterSpace(Schedule);
  253. }
  254. /// Check if all stores in @p Stmt store the very same value.
  255. ///
  256. /// This covers a special situation occurring in Polybench's
  257. /// covariance/correlation (which is typical for algorithms that cover symmetric
  258. /// matrices):
  259. ///
  260. /// for (int i = 0; i < n; i += 1)
  261. /// for (int j = 0; j <= i; j += 1) {
  262. /// double x = ...;
  263. /// C[i][j] = x;
  264. /// C[j][i] = x;
  265. /// }
  266. ///
  267. /// For i == j, the same value is written twice to the same element.Double
  268. /// writes to the same element are not allowed in DeLICM because its algorithm
  269. /// does not see which of the writes is effective.But if its the same value
  270. /// anyway, it doesn't matter.
  271. ///
  272. /// LLVM passes, however, cannot simplify this because the write is necessary
  273. /// for i != j (unless it would add a condition for one of the writes to occur
  274. /// only if i != j).
  275. ///
  276. /// TODO: In the future we may want to extent this to make the checks
  277. /// specific to different memory locations.
  278. static bool onlySameValueWrites(ScopStmt *Stmt) {
  279. Value *V = nullptr;
  280. for (auto *MA : *Stmt) {
  281. if (!MA->isLatestArrayKind() || !MA->isMustWrite() ||
  282. !MA->isOriginalArrayKind())
  283. continue;
  284. if (!V) {
  285. V = MA->getAccessValue();
  286. continue;
  287. }
  288. if (V != MA->getAccessValue())
  289. return false;
  290. }
  291. return true;
  292. }
  293. /// Is @p InnerLoop nested inside @p OuterLoop?
  294. static bool isInsideLoop(Loop *OuterLoop, Loop *InnerLoop) {
  295. // If OuterLoop is nullptr, we cannot call its contains() method. In this case
  296. // OuterLoop represents the 'top level' and therefore contains all loop.
  297. return !OuterLoop || OuterLoop->contains(InnerLoop);
  298. }
  299. void ZoneAlgorithm::collectIncompatibleElts(ScopStmt *Stmt,
  300. isl::union_set &IncompatibleElts,
  301. isl::union_set &AllElts) {
  302. auto Stores = makeEmptyUnionMap();
  303. auto Loads = makeEmptyUnionMap();
  304. // This assumes that the MemoryKind::Array MemoryAccesses are iterated in
  305. // order.
  306. for (auto *MA : *Stmt) {
  307. if (!MA->isOriginalArrayKind())
  308. continue;
  309. isl::map AccRelMap = getAccessRelationFor(MA);
  310. isl::union_map AccRel = AccRelMap;
  311. // To avoid solving any ILP problems, always add entire arrays instead of
  312. // just the elements that are accessed.
  313. auto ArrayElts = isl::set::universe(AccRelMap.get_space().range());
  314. AllElts = AllElts.unite(ArrayElts);
  315. if (MA->isRead()) {
  316. // Reject load after store to same location.
  317. if (!Stores.is_disjoint(AccRel)) {
  318. LLVM_DEBUG(
  319. dbgs() << "Load after store of same element in same statement\n");
  320. OptimizationRemarkMissed R(PassName, "LoadAfterStore",
  321. MA->getAccessInstruction());
  322. R << "load after store of same element in same statement";
  323. R << " (previous stores: " << Stores;
  324. R << ", loading: " << AccRel << ")";
  325. S->getFunction().getContext().diagnose(R);
  326. IncompatibleElts = IncompatibleElts.unite(ArrayElts);
  327. }
  328. Loads = Loads.unite(AccRel);
  329. continue;
  330. }
  331. // In region statements the order is less clear, eg. the load and store
  332. // might be in a boxed loop.
  333. if (Stmt->isRegionStmt() && !Loads.is_disjoint(AccRel)) {
  334. LLVM_DEBUG(dbgs() << "WRITE in non-affine subregion not supported\n");
  335. OptimizationRemarkMissed R(PassName, "StoreInSubregion",
  336. MA->getAccessInstruction());
  337. R << "store is in a non-affine subregion";
  338. S->getFunction().getContext().diagnose(R);
  339. IncompatibleElts = IncompatibleElts.unite(ArrayElts);
  340. }
  341. // Do not allow more than one store to the same location.
  342. if (!Stores.is_disjoint(AccRel) && !onlySameValueWrites(Stmt)) {
  343. LLVM_DEBUG(dbgs() << "WRITE after WRITE to same element\n");
  344. OptimizationRemarkMissed R(PassName, "StoreAfterStore",
  345. MA->getAccessInstruction());
  346. R << "store after store of same element in same statement";
  347. R << " (previous stores: " << Stores;
  348. R << ", storing: " << AccRel << ")";
  349. S->getFunction().getContext().diagnose(R);
  350. IncompatibleElts = IncompatibleElts.unite(ArrayElts);
  351. }
  352. Stores = Stores.unite(AccRel);
  353. }
  354. }
  355. void ZoneAlgorithm::addArrayReadAccess(MemoryAccess *MA) {
  356. assert(MA->isLatestArrayKind());
  357. assert(MA->isRead());
  358. ScopStmt *Stmt = MA->getStatement();
  359. // { DomainRead[] -> Element[] }
  360. auto AccRel = intersectRange(getAccessRelationFor(MA), CompatibleElts);
  361. AllReads = AllReads.unite(AccRel);
  362. if (LoadInst *Load = dyn_cast_or_null<LoadInst>(MA->getAccessInstruction())) {
  363. // { DomainRead[] -> ValInst[] }
  364. isl::map LoadValInst = makeValInst(
  365. Load, Stmt, LI->getLoopFor(Load->getParent()), Stmt->isBlockStmt());
  366. // { DomainRead[] -> [Element[] -> DomainRead[]] }
  367. isl::map IncludeElement = AccRel.domain_map().curry();
  368. // { [Element[] -> DomainRead[]] -> ValInst[] }
  369. isl::map EltLoadValInst = LoadValInst.apply_domain(IncludeElement);
  370. AllReadValInst = AllReadValInst.unite(EltLoadValInst);
  371. }
  372. }
  373. isl::union_map ZoneAlgorithm::getWrittenValue(MemoryAccess *MA,
  374. isl::map AccRel) {
  375. if (!MA->isMustWrite())
  376. return {};
  377. Value *AccVal = MA->getAccessValue();
  378. ScopStmt *Stmt = MA->getStatement();
  379. Instruction *AccInst = MA->getAccessInstruction();
  380. // Write a value to a single element.
  381. auto L = MA->isOriginalArrayKind() ? LI->getLoopFor(AccInst->getParent())
  382. : Stmt->getSurroundingLoop();
  383. if (AccVal &&
  384. AccVal->getType() == MA->getLatestScopArrayInfo()->getElementType() &&
  385. AccRel.is_single_valued().is_true())
  386. return makeNormalizedValInst(AccVal, Stmt, L);
  387. // memset(_, '0', ) is equivalent to writing the null value to all touched
  388. // elements. isMustWrite() ensures that all of an element's bytes are
  389. // overwritten.
  390. if (auto *Memset = dyn_cast<MemSetInst>(AccInst)) {
  391. auto *WrittenConstant = dyn_cast<Constant>(Memset->getValue());
  392. Type *Ty = MA->getLatestScopArrayInfo()->getElementType();
  393. if (WrittenConstant && WrittenConstant->isZeroValue()) {
  394. Constant *Zero = Constant::getNullValue(Ty);
  395. return makeNormalizedValInst(Zero, Stmt, L);
  396. }
  397. }
  398. return {};
  399. }
  400. void ZoneAlgorithm::addArrayWriteAccess(MemoryAccess *MA) {
  401. assert(MA->isLatestArrayKind());
  402. assert(MA->isWrite());
  403. auto *Stmt = MA->getStatement();
  404. // { Domain[] -> Element[] }
  405. isl::map AccRel = intersectRange(getAccessRelationFor(MA), CompatibleElts);
  406. if (MA->isMustWrite())
  407. AllMustWrites = AllMustWrites.unite(AccRel);
  408. if (MA->isMayWrite())
  409. AllMayWrites = AllMayWrites.unite(AccRel);
  410. // { Domain[] -> ValInst[] }
  411. isl::union_map WriteValInstance = getWrittenValue(MA, AccRel);
  412. if (WriteValInstance.is_null())
  413. WriteValInstance = makeUnknownForDomain(Stmt);
  414. // { Domain[] -> [Element[] -> Domain[]] }
  415. isl::map IncludeElement = AccRel.domain_map().curry();
  416. // { [Element[] -> DomainWrite[]] -> ValInst[] }
  417. isl::union_map EltWriteValInst =
  418. WriteValInstance.apply_domain(IncludeElement);
  419. AllWriteValInst = AllWriteValInst.unite(EltWriteValInst);
  420. }
  421. /// For an llvm::Value defined in @p DefStmt, compute the RAW dependency for a
  422. /// use in every instance of @p UseStmt.
  423. ///
  424. /// @param UseStmt Statement a scalar is used in.
  425. /// @param DefStmt Statement a scalar is defined in.
  426. ///
  427. /// @return { DomainUse[] -> DomainDef[] }
  428. isl::map ZoneAlgorithm::computeUseToDefFlowDependency(ScopStmt *UseStmt,
  429. ScopStmt *DefStmt) {
  430. // { DomainUse[] -> Scatter[] }
  431. isl::map UseScatter = getScatterFor(UseStmt);
  432. // { Zone[] -> DomainDef[] }
  433. isl::map ReachDefZone = getScalarReachingDefinition(DefStmt);
  434. // { Scatter[] -> DomainDef[] }
  435. isl::map ReachDefTimepoints =
  436. convertZoneToTimepoints(ReachDefZone, isl::dim::in, false, true);
  437. // { DomainUse[] -> DomainDef[] }
  438. return UseScatter.apply_range(ReachDefTimepoints);
  439. }
  440. /// Return whether @p PHI refers (also transitively through other PHIs) to
  441. /// itself.
  442. ///
  443. /// loop:
  444. /// %phi1 = phi [0, %preheader], [%phi1, %loop]
  445. /// br i1 %c, label %loop, label %exit
  446. ///
  447. /// exit:
  448. /// %phi2 = phi [%phi1, %bb]
  449. ///
  450. /// In this example, %phi1 is recursive, but %phi2 is not.
  451. static bool isRecursivePHI(const PHINode *PHI) {
  452. SmallVector<const PHINode *, 8> Worklist;
  453. SmallPtrSet<const PHINode *, 8> Visited;
  454. Worklist.push_back(PHI);
  455. while (!Worklist.empty()) {
  456. const PHINode *Cur = Worklist.pop_back_val();
  457. if (Visited.count(Cur))
  458. continue;
  459. Visited.insert(Cur);
  460. for (const Use &Incoming : Cur->incoming_values()) {
  461. Value *IncomingVal = Incoming.get();
  462. auto *IncomingPHI = dyn_cast<PHINode>(IncomingVal);
  463. if (!IncomingPHI)
  464. continue;
  465. if (IncomingPHI == PHI)
  466. return true;
  467. Worklist.push_back(IncomingPHI);
  468. }
  469. }
  470. return false;
  471. }
  472. isl::union_map ZoneAlgorithm::computePerPHI(const ScopArrayInfo *SAI) {
  473. // TODO: If the PHI has an incoming block from before the SCoP, it is not
  474. // represented in any ScopStmt.
  475. auto *PHI = cast<PHINode>(SAI->getBasePtr());
  476. auto It = PerPHIMaps.find(PHI);
  477. if (It != PerPHIMaps.end())
  478. return It->second;
  479. // Cannot reliably compute immediate predecessor for undefined executions, so
  480. // bail out if we do not know. This in particular applies to undefined control
  481. // flow.
  482. isl::set DefinedContext = S->getDefinedBehaviorContext();
  483. if (DefinedContext.is_null())
  484. return {};
  485. assert(SAI->isPHIKind());
  486. // { DomainPHIWrite[] -> Scatter[] }
  487. isl::union_map PHIWriteScatter = makeEmptyUnionMap();
  488. // Collect all incoming block timepoints.
  489. for (MemoryAccess *MA : S->getPHIIncomings(SAI)) {
  490. isl::map Scatter = getScatterFor(MA);
  491. PHIWriteScatter = PHIWriteScatter.unite(Scatter);
  492. }
  493. // { DomainPHIRead[] -> Scatter[] }
  494. isl::map PHIReadScatter = getScatterFor(S->getPHIRead(SAI));
  495. // { DomainPHIRead[] -> Scatter[] }
  496. isl::map BeforeRead = beforeScatter(PHIReadScatter, true);
  497. // { Scatter[] }
  498. isl::set WriteTimes = singleton(PHIWriteScatter.range(), ScatterSpace);
  499. // { DomainPHIRead[] -> Scatter[] }
  500. isl::map PHIWriteTimes = BeforeRead.intersect_range(WriteTimes);
  501. // Remove instances outside the context.
  502. PHIWriteTimes = PHIWriteTimes.intersect_params(DefinedContext);
  503. isl::map LastPerPHIWrites = PHIWriteTimes.lexmax();
  504. // { DomainPHIRead[] -> DomainPHIWrite[] }
  505. isl::union_map Result =
  506. isl::union_map(LastPerPHIWrites).apply_range(PHIWriteScatter.reverse());
  507. assert(!Result.is_single_valued().is_false());
  508. assert(!Result.is_injective().is_false());
  509. PerPHIMaps.insert({PHI, Result});
  510. return Result;
  511. }
  512. isl::union_set ZoneAlgorithm::makeEmptyUnionSet() const {
  513. return isl::union_set::empty(ParamSpace.ctx());
  514. }
  515. isl::union_map ZoneAlgorithm::makeEmptyUnionMap() const {
  516. return isl::union_map::empty(ParamSpace.ctx());
  517. }
  518. void ZoneAlgorithm::collectCompatibleElts() {
  519. // First find all the incompatible elements, then take the complement.
  520. // We compile the list of compatible (rather than incompatible) elements so
  521. // users can intersect with the list, not requiring a subtract operation. It
  522. // also allows us to define a 'universe' of all elements and makes it more
  523. // explicit in which array elements can be used.
  524. isl::union_set AllElts = makeEmptyUnionSet();
  525. isl::union_set IncompatibleElts = makeEmptyUnionSet();
  526. for (auto &Stmt : *S)
  527. collectIncompatibleElts(&Stmt, IncompatibleElts, AllElts);
  528. NumIncompatibleArrays += isl_union_set_n_set(IncompatibleElts.get());
  529. CompatibleElts = AllElts.subtract(IncompatibleElts);
  530. NumCompatibleArrays += isl_union_set_n_set(CompatibleElts.get());
  531. }
  532. isl::map ZoneAlgorithm::getScatterFor(ScopStmt *Stmt) const {
  533. isl::space ResultSpace =
  534. Stmt->getDomainSpace().map_from_domain_and_range(ScatterSpace);
  535. return Schedule.extract_map(ResultSpace);
  536. }
  537. isl::map ZoneAlgorithm::getScatterFor(MemoryAccess *MA) const {
  538. return getScatterFor(MA->getStatement());
  539. }
  540. isl::union_map ZoneAlgorithm::getScatterFor(isl::union_set Domain) const {
  541. return Schedule.intersect_domain(Domain);
  542. }
  543. isl::map ZoneAlgorithm::getScatterFor(isl::set Domain) const {
  544. auto ResultSpace = Domain.get_space().map_from_domain_and_range(ScatterSpace);
  545. auto UDomain = isl::union_set(Domain);
  546. auto UResult = getScatterFor(std::move(UDomain));
  547. auto Result = singleton(std::move(UResult), std::move(ResultSpace));
  548. assert(Result.is_null() || Result.domain().is_equal(Domain) == isl_bool_true);
  549. return Result;
  550. }
  551. isl::set ZoneAlgorithm::getDomainFor(ScopStmt *Stmt) const {
  552. return Stmt->getDomain().remove_redundancies();
  553. }
  554. isl::set ZoneAlgorithm::getDomainFor(MemoryAccess *MA) const {
  555. return getDomainFor(MA->getStatement());
  556. }
  557. isl::map ZoneAlgorithm::getAccessRelationFor(MemoryAccess *MA) const {
  558. auto Domain = getDomainFor(MA);
  559. auto AccRel = MA->getLatestAccessRelation();
  560. return AccRel.intersect_domain(Domain);
  561. }
  562. isl::map ZoneAlgorithm::getDefToTarget(ScopStmt *DefStmt,
  563. ScopStmt *TargetStmt) {
  564. // No translation required if the definition is already at the target.
  565. if (TargetStmt == DefStmt)
  566. return isl::map::identity(
  567. getDomainFor(TargetStmt).get_space().map_from_set());
  568. isl::map &Result = DefToTargetCache[std::make_pair(TargetStmt, DefStmt)];
  569. // This is a shortcut in case the schedule is still the original and
  570. // TargetStmt is in the same or nested inside DefStmt's loop. With the
  571. // additional assumption that operand trees do not cross DefStmt's loop
  572. // header, then TargetStmt's instance shared coordinates are the same as
  573. // DefStmt's coordinates. All TargetStmt instances with this prefix share
  574. // the same DefStmt instance.
  575. // Model:
  576. //
  577. // for (int i < 0; i < N; i+=1) {
  578. // DefStmt:
  579. // D = ...;
  580. // for (int j < 0; j < N; j+=1) {
  581. // TargetStmt:
  582. // use(D);
  583. // }
  584. // }
  585. //
  586. // Here, the value used in TargetStmt is defined in the corresponding
  587. // DefStmt, i.e.
  588. //
  589. // { DefStmt[i] -> TargetStmt[i,j] }
  590. //
  591. // In practice, this should cover the majority of cases.
  592. if (Result.is_null() && S->isOriginalSchedule() &&
  593. isInsideLoop(DefStmt->getSurroundingLoop(),
  594. TargetStmt->getSurroundingLoop())) {
  595. isl::set DefDomain = getDomainFor(DefStmt);
  596. isl::set TargetDomain = getDomainFor(TargetStmt);
  597. assert(unsignedFromIslSize(DefDomain.tuple_dim()) <=
  598. unsignedFromIslSize(TargetDomain.tuple_dim()));
  599. Result = isl::map::from_domain_and_range(DefDomain, TargetDomain);
  600. for (unsigned i : rangeIslSize(0, DefDomain.tuple_dim()))
  601. Result = Result.equate(isl::dim::in, i, isl::dim::out, i);
  602. }
  603. if (Result.is_null()) {
  604. // { DomainDef[] -> DomainTarget[] }
  605. Result = computeUseToDefFlowDependency(TargetStmt, DefStmt).reverse();
  606. simplify(Result);
  607. }
  608. return Result;
  609. }
  610. isl::map ZoneAlgorithm::getScalarReachingDefinition(ScopStmt *Stmt) {
  611. auto &Result = ScalarReachDefZone[Stmt];
  612. if (!Result.is_null())
  613. return Result;
  614. auto Domain = getDomainFor(Stmt);
  615. Result = computeScalarReachingDefinition(Schedule, Domain, false, true);
  616. simplify(Result);
  617. return Result;
  618. }
  619. isl::map ZoneAlgorithm::getScalarReachingDefinition(isl::set DomainDef) {
  620. auto DomId = DomainDef.get_tuple_id();
  621. auto *Stmt = static_cast<ScopStmt *>(isl_id_get_user(DomId.get()));
  622. auto StmtResult = getScalarReachingDefinition(Stmt);
  623. return StmtResult.intersect_range(DomainDef);
  624. }
  625. isl::map ZoneAlgorithm::makeUnknownForDomain(ScopStmt *Stmt) const {
  626. return ::makeUnknownForDomain(getDomainFor(Stmt));
  627. }
  628. isl::id ZoneAlgorithm::makeValueId(Value *V) {
  629. if (!V)
  630. return {};
  631. auto &Id = ValueIds[V];
  632. if (Id.is_null()) {
  633. auto Name = getIslCompatibleName("Val_", V, ValueIds.size() - 1,
  634. std::string(), UseInstructionNames);
  635. Id = isl::id::alloc(IslCtx.get(), Name.c_str(), V);
  636. }
  637. return Id;
  638. }
  639. isl::space ZoneAlgorithm::makeValueSpace(Value *V) {
  640. auto Result = ParamSpace.set_from_params();
  641. return Result.set_tuple_id(isl::dim::set, makeValueId(V));
  642. }
  643. isl::set ZoneAlgorithm::makeValueSet(Value *V) {
  644. auto Space = makeValueSpace(V);
  645. return isl::set::universe(Space);
  646. }
  647. isl::map ZoneAlgorithm::makeValInst(Value *Val, ScopStmt *UserStmt, Loop *Scope,
  648. bool IsCertain) {
  649. // If the definition/write is conditional, the value at the location could
  650. // be either the written value or the old value. Since we cannot know which
  651. // one, consider the value to be unknown.
  652. if (!IsCertain)
  653. return makeUnknownForDomain(UserStmt);
  654. auto DomainUse = getDomainFor(UserStmt);
  655. auto VUse = VirtualUse::create(S, UserStmt, Scope, Val, true);
  656. switch (VUse.getKind()) {
  657. case VirtualUse::Constant:
  658. case VirtualUse::Block:
  659. case VirtualUse::Hoisted:
  660. case VirtualUse::ReadOnly: {
  661. // The definition does not depend on the statement which uses it.
  662. auto ValSet = makeValueSet(Val);
  663. return isl::map::from_domain_and_range(DomainUse, ValSet);
  664. }
  665. case VirtualUse::Synthesizable: {
  666. auto *ScevExpr = VUse.getScevExpr();
  667. auto UseDomainSpace = DomainUse.get_space();
  668. // Construct the SCEV space.
  669. // TODO: Add only the induction variables referenced in SCEVAddRecExpr
  670. // expressions, not just all of them.
  671. auto ScevId = isl::manage(isl_id_alloc(UseDomainSpace.ctx().get(), nullptr,
  672. const_cast<SCEV *>(ScevExpr)));
  673. auto ScevSpace = UseDomainSpace.drop_dims(isl::dim::set, 0, 0);
  674. ScevSpace = ScevSpace.set_tuple_id(isl::dim::set, ScevId);
  675. // { DomainUse[] -> ScevExpr[] }
  676. auto ValInst =
  677. isl::map::identity(UseDomainSpace.map_from_domain_and_range(ScevSpace));
  678. return ValInst;
  679. }
  680. case VirtualUse::Intra: {
  681. // Definition and use is in the same statement. We do not need to compute
  682. // a reaching definition.
  683. // { llvm::Value }
  684. auto ValSet = makeValueSet(Val);
  685. // { UserDomain[] -> llvm::Value }
  686. auto ValInstSet = isl::map::from_domain_and_range(DomainUse, ValSet);
  687. // { UserDomain[] -> [UserDomain[] - >llvm::Value] }
  688. auto Result = ValInstSet.domain_map().reverse();
  689. simplify(Result);
  690. return Result;
  691. }
  692. case VirtualUse::Inter: {
  693. // The value is defined in a different statement.
  694. auto *Inst = cast<Instruction>(Val);
  695. auto *ValStmt = S->getStmtFor(Inst);
  696. // If the llvm::Value is defined in a removed Stmt, we cannot derive its
  697. // domain. We could use an arbitrary statement, but this could result in
  698. // different ValInst[] for the same llvm::Value.
  699. if (!ValStmt)
  700. return ::makeUnknownForDomain(DomainUse);
  701. // { DomainUse[] -> DomainDef[] }
  702. auto UsedInstance = getDefToTarget(ValStmt, UserStmt).reverse();
  703. // { llvm::Value }
  704. auto ValSet = makeValueSet(Val);
  705. // { DomainUse[] -> llvm::Value[] }
  706. auto ValInstSet = isl::map::from_domain_and_range(DomainUse, ValSet);
  707. // { DomainUse[] -> [DomainDef[] -> llvm::Value] }
  708. auto Result = UsedInstance.range_product(ValInstSet);
  709. simplify(Result);
  710. return Result;
  711. }
  712. }
  713. llvm_unreachable("Unhandled use type");
  714. }
  715. /// Remove all computed PHIs out of @p Input and replace by their incoming
  716. /// value.
  717. ///
  718. /// @param Input { [] -> ValInst[] }
  719. /// @param ComputedPHIs Set of PHIs that are replaced. Its ValInst must appear
  720. /// on the LHS of @p NormalizeMap.
  721. /// @param NormalizeMap { ValInst[] -> ValInst[] }
  722. static isl::union_map normalizeValInst(isl::union_map Input,
  723. const DenseSet<PHINode *> &ComputedPHIs,
  724. isl::union_map NormalizeMap) {
  725. isl::union_map Result = isl::union_map::empty(Input.ctx());
  726. for (isl::map Map : Input.get_map_list()) {
  727. isl::space Space = Map.get_space();
  728. isl::space RangeSpace = Space.range();
  729. // Instructions within the SCoP are always wrapped. Non-wrapped tuples
  730. // are therefore invariant in the SCoP and don't need normalization.
  731. if (!RangeSpace.is_wrapping()) {
  732. Result = Result.unite(Map);
  733. continue;
  734. }
  735. auto *PHI = dyn_cast<PHINode>(static_cast<Value *>(
  736. RangeSpace.unwrap().get_tuple_id(isl::dim::out).get_user()));
  737. // If no normalization is necessary, then the ValInst stands for itself.
  738. if (!ComputedPHIs.count(PHI)) {
  739. Result = Result.unite(Map);
  740. continue;
  741. }
  742. // Otherwise, apply the normalization.
  743. isl::union_map Mapped = isl::union_map(Map).apply_range(NormalizeMap);
  744. Result = Result.unite(Mapped);
  745. NumPHINormialization++;
  746. }
  747. return Result;
  748. }
  749. isl::union_map ZoneAlgorithm::makeNormalizedValInst(llvm::Value *Val,
  750. ScopStmt *UserStmt,
  751. llvm::Loop *Scope,
  752. bool IsCertain) {
  753. isl::map ValInst = makeValInst(Val, UserStmt, Scope, IsCertain);
  754. isl::union_map Normalized =
  755. normalizeValInst(ValInst, ComputedPHIs, NormalizeMap);
  756. return Normalized;
  757. }
  758. bool ZoneAlgorithm::isCompatibleAccess(MemoryAccess *MA) {
  759. if (!MA)
  760. return false;
  761. if (!MA->isLatestArrayKind())
  762. return false;
  763. Instruction *AccInst = MA->getAccessInstruction();
  764. return isa<StoreInst>(AccInst) || isa<LoadInst>(AccInst);
  765. }
  766. bool ZoneAlgorithm::isNormalizable(MemoryAccess *MA) {
  767. assert(MA->isRead());
  768. // Exclude ExitPHIs, we are assuming that a normalizable PHI has a READ
  769. // MemoryAccess.
  770. if (!MA->isOriginalPHIKind())
  771. return false;
  772. // Exclude recursive PHIs, normalizing them would require a transitive
  773. // closure.
  774. auto *PHI = cast<PHINode>(MA->getAccessInstruction());
  775. if (RecursivePHIs.count(PHI))
  776. return false;
  777. // Ensure that each incoming value can be represented by a ValInst[].
  778. // We do represent values from statements associated to multiple incoming
  779. // value by the PHI itself, but we do not handle this case yet (especially
  780. // isNormalized()) when normalizing.
  781. const ScopArrayInfo *SAI = MA->getOriginalScopArrayInfo();
  782. auto Incomings = S->getPHIIncomings(SAI);
  783. for (MemoryAccess *Incoming : Incomings) {
  784. if (Incoming->getIncoming().size() != 1)
  785. return false;
  786. }
  787. return true;
  788. }
  789. isl::boolean ZoneAlgorithm::isNormalized(isl::map Map) {
  790. isl::space Space = Map.get_space();
  791. isl::space RangeSpace = Space.range();
  792. isl::boolean IsWrapping = RangeSpace.is_wrapping();
  793. if (!IsWrapping.is_true())
  794. return !IsWrapping;
  795. isl::space Unwrapped = RangeSpace.unwrap();
  796. isl::id OutTupleId = Unwrapped.get_tuple_id(isl::dim::out);
  797. if (OutTupleId.is_null())
  798. return isl::boolean();
  799. auto *PHI = dyn_cast<PHINode>(static_cast<Value *>(OutTupleId.get_user()));
  800. if (!PHI)
  801. return true;
  802. isl::id InTupleId = Unwrapped.get_tuple_id(isl::dim::in);
  803. if (OutTupleId.is_null())
  804. return isl::boolean();
  805. auto *IncomingStmt = static_cast<ScopStmt *>(InTupleId.get_user());
  806. MemoryAccess *PHIRead = IncomingStmt->lookupPHIReadOf(PHI);
  807. if (!isNormalizable(PHIRead))
  808. return true;
  809. return false;
  810. }
  811. isl::boolean ZoneAlgorithm::isNormalized(isl::union_map UMap) {
  812. isl::boolean Result = true;
  813. for (isl::map Map : UMap.get_map_list()) {
  814. Result = isNormalized(Map);
  815. if (Result.is_true())
  816. continue;
  817. break;
  818. }
  819. return Result;
  820. }
  821. void ZoneAlgorithm::computeCommon() {
  822. AllReads = makeEmptyUnionMap();
  823. AllMayWrites = makeEmptyUnionMap();
  824. AllMustWrites = makeEmptyUnionMap();
  825. AllWriteValInst = makeEmptyUnionMap();
  826. AllReadValInst = makeEmptyUnionMap();
  827. // Default to empty, i.e. no normalization/replacement is taking place. Call
  828. // computeNormalizedPHIs() to initialize.
  829. NormalizeMap = makeEmptyUnionMap();
  830. ComputedPHIs.clear();
  831. for (auto &Stmt : *S) {
  832. for (auto *MA : Stmt) {
  833. if (!MA->isLatestArrayKind())
  834. continue;
  835. if (MA->isRead())
  836. addArrayReadAccess(MA);
  837. if (MA->isWrite())
  838. addArrayWriteAccess(MA);
  839. }
  840. }
  841. // { DomainWrite[] -> Element[] }
  842. AllWrites = AllMustWrites.unite(AllMayWrites);
  843. // { [Element[] -> Zone[]] -> DomainWrite[] }
  844. WriteReachDefZone =
  845. computeReachingDefinition(Schedule, AllWrites, false, true);
  846. simplify(WriteReachDefZone);
  847. }
  848. void ZoneAlgorithm::computeNormalizedPHIs() {
  849. // Determine which PHIs can reference themselves. They are excluded from
  850. // normalization to avoid problems with transitive closures.
  851. for (ScopStmt &Stmt : *S) {
  852. for (MemoryAccess *MA : Stmt) {
  853. if (!MA->isPHIKind())
  854. continue;
  855. if (!MA->isRead())
  856. continue;
  857. // TODO: Can be more efficient since isRecursivePHI can theoretically
  858. // determine recursiveness for multiple values and/or cache results.
  859. auto *PHI = cast<PHINode>(MA->getAccessInstruction());
  860. if (isRecursivePHI(PHI)) {
  861. NumRecursivePHIs++;
  862. RecursivePHIs.insert(PHI);
  863. }
  864. }
  865. }
  866. // { PHIValInst[] -> IncomingValInst[] }
  867. isl::union_map AllPHIMaps = makeEmptyUnionMap();
  868. // Discover new PHIs and try to normalize them.
  869. DenseSet<PHINode *> AllPHIs;
  870. for (ScopStmt &Stmt : *S) {
  871. for (MemoryAccess *MA : Stmt) {
  872. if (!MA->isOriginalPHIKind())
  873. continue;
  874. if (!MA->isRead())
  875. continue;
  876. if (!isNormalizable(MA))
  877. continue;
  878. auto *PHI = cast<PHINode>(MA->getAccessInstruction());
  879. const ScopArrayInfo *SAI = MA->getOriginalScopArrayInfo();
  880. // Determine which instance of the PHI statement corresponds to which
  881. // incoming value. Skip if we cannot determine PHI predecessors.
  882. // { PHIDomain[] -> IncomingDomain[] }
  883. isl::union_map PerPHI = computePerPHI(SAI);
  884. if (PerPHI.is_null())
  885. continue;
  886. // { PHIDomain[] -> PHIValInst[] }
  887. isl::map PHIValInst = makeValInst(PHI, &Stmt, Stmt.getSurroundingLoop());
  888. // { IncomingDomain[] -> IncomingValInst[] }
  889. isl::union_map IncomingValInsts = makeEmptyUnionMap();
  890. // Get all incoming values.
  891. for (MemoryAccess *MA : S->getPHIIncomings(SAI)) {
  892. ScopStmt *IncomingStmt = MA->getStatement();
  893. auto Incoming = MA->getIncoming();
  894. assert(Incoming.size() == 1 && "The incoming value must be "
  895. "representable by something else than "
  896. "the PHI itself");
  897. Value *IncomingVal = Incoming[0].second;
  898. // { IncomingDomain[] -> IncomingValInst[] }
  899. isl::map IncomingValInst = makeValInst(
  900. IncomingVal, IncomingStmt, IncomingStmt->getSurroundingLoop());
  901. IncomingValInsts = IncomingValInsts.unite(IncomingValInst);
  902. }
  903. // { PHIValInst[] -> IncomingValInst[] }
  904. isl::union_map PHIMap =
  905. PerPHI.apply_domain(PHIValInst).apply_range(IncomingValInsts);
  906. assert(!PHIMap.is_single_valued().is_false());
  907. // Resolve transitiveness: The incoming value of the newly discovered PHI
  908. // may reference a previously normalized PHI. At the same time, already
  909. // normalized PHIs might be normalized to the new PHI. At the end, none of
  910. // the PHIs may appear on the right-hand-side of the normalization map.
  911. PHIMap = normalizeValInst(PHIMap, AllPHIs, AllPHIMaps);
  912. AllPHIs.insert(PHI);
  913. AllPHIMaps = normalizeValInst(AllPHIMaps, AllPHIs, PHIMap);
  914. AllPHIMaps = AllPHIMaps.unite(PHIMap);
  915. NumNormalizablePHIs++;
  916. }
  917. }
  918. simplify(AllPHIMaps);
  919. // Apply the normalization.
  920. ComputedPHIs = AllPHIs;
  921. NormalizeMap = AllPHIMaps;
  922. assert(NormalizeMap.is_null() || isNormalized(NormalizeMap));
  923. }
  924. void ZoneAlgorithm::printAccesses(llvm::raw_ostream &OS, int Indent) const {
  925. OS.indent(Indent) << "After accesses {\n";
  926. for (auto &Stmt : *S) {
  927. OS.indent(Indent + 4) << Stmt.getBaseName() << "\n";
  928. for (auto *MA : Stmt)
  929. MA->print(OS);
  930. }
  931. OS.indent(Indent) << "}\n";
  932. }
  933. isl::union_map ZoneAlgorithm::computeKnownFromMustWrites() const {
  934. // { [Element[] -> Zone[]] -> [Element[] -> DomainWrite[]] }
  935. isl::union_map EltReachdDef = distributeDomain(WriteReachDefZone.curry());
  936. // { [Element[] -> DomainWrite[]] -> ValInst[] }
  937. isl::union_map AllKnownWriteValInst = filterKnownValInst(AllWriteValInst);
  938. // { [Element[] -> Zone[]] -> ValInst[] }
  939. return EltReachdDef.apply_range(AllKnownWriteValInst);
  940. }
  941. isl::union_map ZoneAlgorithm::computeKnownFromLoad() const {
  942. // { Element[] }
  943. isl::union_set AllAccessedElts = AllReads.range().unite(AllWrites.range());
  944. // { Element[] -> Scatter[] }
  945. isl::union_map EltZoneUniverse = isl::union_map::from_domain_and_range(
  946. AllAccessedElts, isl::set::universe(ScatterSpace));
  947. // This assumes there are no "holes" in
  948. // isl_union_map_domain(WriteReachDefZone); alternatively, compute the zone
  949. // before the first write or that are not written at all.
  950. // { Element[] -> Scatter[] }
  951. isl::union_set NonReachDef =
  952. EltZoneUniverse.wrap().subtract(WriteReachDefZone.domain());
  953. // { [Element[] -> Zone[]] -> ReachDefId[] }
  954. isl::union_map DefZone =
  955. WriteReachDefZone.unite(isl::union_map::from_domain(NonReachDef));
  956. // { [Element[] -> Scatter[]] -> Element[] }
  957. isl::union_map EltZoneElt = EltZoneUniverse.domain_map();
  958. // { [Element[] -> Zone[]] -> [Element[] -> ReachDefId[]] }
  959. isl::union_map DefZoneEltDefId = EltZoneElt.range_product(DefZone);
  960. // { Element[] -> [Zone[] -> ReachDefId[]] }
  961. isl::union_map EltDefZone = DefZone.curry();
  962. // { [Element[] -> Zone[] -> [Element[] -> ReachDefId[]] }
  963. isl::union_map EltZoneEltDefid = distributeDomain(EltDefZone);
  964. // { [Element[] -> Scatter[]] -> DomainRead[] }
  965. isl::union_map Reads = AllReads.range_product(Schedule).reverse();
  966. // { [Element[] -> Scatter[]] -> [Element[] -> DomainRead[]] }
  967. isl::union_map ReadsElt = EltZoneElt.range_product(Reads);
  968. // { [Element[] -> Scatter[]] -> ValInst[] }
  969. isl::union_map ScatterKnown = ReadsElt.apply_range(AllReadValInst);
  970. // { [Element[] -> ReachDefId[]] -> ValInst[] }
  971. isl::union_map DefidKnown =
  972. DefZoneEltDefId.apply_domain(ScatterKnown).reverse();
  973. // { [Element[] -> Zone[]] -> ValInst[] }
  974. return DefZoneEltDefId.apply_range(DefidKnown);
  975. }
  976. isl::union_map ZoneAlgorithm::computeKnown(bool FromWrite,
  977. bool FromRead) const {
  978. isl::union_map Result = makeEmptyUnionMap();
  979. if (FromWrite)
  980. Result = Result.unite(computeKnownFromMustWrites());
  981. if (FromRead)
  982. Result = Result.unite(computeKnownFromLoad());
  983. simplify(Result);
  984. return Result;
  985. }