ISLTools.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. //===------ ISLTools.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. // Tools, utilities, helpers and extensions useful in conjunction with the
  10. // Integer Set Library (isl).
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "polly/Support/ISLTools.h"
  14. #include "polly/Support/GICHelper.h"
  15. #include "llvm/Support/raw_ostream.h"
  16. #include <cassert>
  17. #include <vector>
  18. using namespace polly;
  19. namespace {
  20. /// Create a map that shifts one dimension by an offset.
  21. ///
  22. /// Example:
  23. /// makeShiftDimAff({ [i0, i1] -> [o0, o1] }, 1, -2)
  24. /// = { [i0, i1] -> [i0, i1 - 1] }
  25. ///
  26. /// @param Space The map space of the result. Must have equal number of in- and
  27. /// out-dimensions.
  28. /// @param Pos Position to shift.
  29. /// @param Amount Value added to the shifted dimension.
  30. ///
  31. /// @return An isl_multi_aff for the map with this shifted dimension.
  32. isl::multi_aff makeShiftDimAff(isl::space Space, int Pos, int Amount) {
  33. auto Identity = isl::multi_aff::identity(Space);
  34. if (Amount == 0)
  35. return Identity;
  36. auto ShiftAff = Identity.at(Pos);
  37. ShiftAff = ShiftAff.set_constant_si(Amount);
  38. return Identity.set_aff(Pos, ShiftAff);
  39. }
  40. /// Construct a map that swaps two nested tuples.
  41. ///
  42. /// @param FromSpace1 { Space1[] }
  43. /// @param FromSpace2 { Space2[] }
  44. ///
  45. /// @return { [Space1[] -> Space2[]] -> [Space2[] -> Space1[]] }
  46. isl::basic_map makeTupleSwapBasicMap(isl::space FromSpace1,
  47. isl::space FromSpace2) {
  48. // Fast-path on out-of-quota.
  49. if (FromSpace1.is_null() || FromSpace2.is_null())
  50. return {};
  51. assert(FromSpace1.is_set());
  52. assert(FromSpace2.is_set());
  53. unsigned Dims1 = unsignedFromIslSize(FromSpace1.dim(isl::dim::set));
  54. unsigned Dims2 = unsignedFromIslSize(FromSpace2.dim(isl::dim::set));
  55. isl::space FromSpace =
  56. FromSpace1.map_from_domain_and_range(FromSpace2).wrap();
  57. isl::space ToSpace = FromSpace2.map_from_domain_and_range(FromSpace1).wrap();
  58. isl::space MapSpace = FromSpace.map_from_domain_and_range(ToSpace);
  59. isl::basic_map Result = isl::basic_map::universe(MapSpace);
  60. for (unsigned i = 0u; i < Dims1; i += 1)
  61. Result = Result.equate(isl::dim::in, i, isl::dim::out, Dims2 + i);
  62. for (unsigned i = 0u; i < Dims2; i += 1) {
  63. Result = Result.equate(isl::dim::in, Dims1 + i, isl::dim::out, i);
  64. }
  65. return Result;
  66. }
  67. /// Like makeTupleSwapBasicMap(isl::space,isl::space), but returns
  68. /// an isl_map.
  69. isl::map makeTupleSwapMap(isl::space FromSpace1, isl::space FromSpace2) {
  70. isl::basic_map BMapResult = makeTupleSwapBasicMap(FromSpace1, FromSpace2);
  71. return isl::map(BMapResult);
  72. }
  73. } // anonymous namespace
  74. isl::map polly::beforeScatter(isl::map Map, bool Strict) {
  75. isl::space RangeSpace = Map.get_space().range();
  76. isl::map ScatterRel =
  77. Strict ? isl::map::lex_gt(RangeSpace) : isl::map::lex_ge(RangeSpace);
  78. return Map.apply_range(ScatterRel);
  79. }
  80. isl::union_map polly::beforeScatter(isl::union_map UMap, bool Strict) {
  81. isl::union_map Result = isl::union_map::empty(UMap.ctx());
  82. for (isl::map Map : UMap.get_map_list()) {
  83. isl::map After = beforeScatter(Map, Strict);
  84. Result = Result.unite(After);
  85. }
  86. return Result;
  87. }
  88. isl::map polly::afterScatter(isl::map Map, bool Strict) {
  89. isl::space RangeSpace = Map.get_space().range();
  90. isl::map ScatterRel =
  91. Strict ? isl::map::lex_lt(RangeSpace) : isl::map::lex_le(RangeSpace);
  92. return Map.apply_range(ScatterRel);
  93. }
  94. isl::union_map polly::afterScatter(const isl::union_map &UMap, bool Strict) {
  95. isl::union_map Result = isl::union_map::empty(UMap.ctx());
  96. for (isl::map Map : UMap.get_map_list()) {
  97. isl::map After = afterScatter(Map, Strict);
  98. Result = Result.unite(After);
  99. }
  100. return Result;
  101. }
  102. isl::map polly::betweenScatter(isl::map From, isl::map To, bool InclFrom,
  103. bool InclTo) {
  104. isl::map AfterFrom = afterScatter(From, !InclFrom);
  105. isl::map BeforeTo = beforeScatter(To, !InclTo);
  106. return AfterFrom.intersect(BeforeTo);
  107. }
  108. isl::union_map polly::betweenScatter(isl::union_map From, isl::union_map To,
  109. bool InclFrom, bool InclTo) {
  110. isl::union_map AfterFrom = afterScatter(From, !InclFrom);
  111. isl::union_map BeforeTo = beforeScatter(To, !InclTo);
  112. return AfterFrom.intersect(BeforeTo);
  113. }
  114. isl::map polly::singleton(isl::union_map UMap, isl::space ExpectedSpace) {
  115. if (UMap.is_null())
  116. return {};
  117. if (isl_union_map_n_map(UMap.get()) == 0)
  118. return isl::map::empty(ExpectedSpace);
  119. isl::map Result = isl::map::from_union_map(UMap);
  120. assert(Result.is_null() ||
  121. Result.get_space().has_equal_tuples(ExpectedSpace));
  122. return Result;
  123. }
  124. isl::set polly::singleton(isl::union_set USet, isl::space ExpectedSpace) {
  125. if (USet.is_null())
  126. return {};
  127. if (isl_union_set_n_set(USet.get()) == 0)
  128. return isl::set::empty(ExpectedSpace);
  129. isl::set Result(USet);
  130. assert(Result.is_null() ||
  131. Result.get_space().has_equal_tuples(ExpectedSpace));
  132. return Result;
  133. }
  134. unsigned polly::getNumScatterDims(const isl::union_map &Schedule) {
  135. unsigned Dims = 0;
  136. for (isl::map Map : Schedule.get_map_list()) {
  137. if (Map.is_null())
  138. continue;
  139. Dims = std::max(Dims, unsignedFromIslSize(Map.range_tuple_dim()));
  140. }
  141. return Dims;
  142. }
  143. isl::space polly::getScatterSpace(const isl::union_map &Schedule) {
  144. if (Schedule.is_null())
  145. return {};
  146. unsigned Dims = getNumScatterDims(Schedule);
  147. isl::space ScatterSpace = Schedule.get_space().set_from_params();
  148. return ScatterSpace.add_dims(isl::dim::set, Dims);
  149. }
  150. isl::map polly::makeIdentityMap(const isl::set &Set, bool RestrictDomain) {
  151. isl::map Result = isl::map::identity(Set.get_space().map_from_set());
  152. if (RestrictDomain)
  153. Result = Result.intersect_domain(Set);
  154. return Result;
  155. }
  156. isl::union_map polly::makeIdentityMap(const isl::union_set &USet,
  157. bool RestrictDomain) {
  158. isl::union_map Result = isl::union_map::empty(USet.ctx());
  159. for (isl::set Set : USet.get_set_list()) {
  160. isl::map IdentityMap = makeIdentityMap(Set, RestrictDomain);
  161. Result = Result.unite(IdentityMap);
  162. }
  163. return Result;
  164. }
  165. isl::map polly::reverseDomain(isl::map Map) {
  166. isl::space DomSpace = Map.get_space().domain().unwrap();
  167. isl::space Space1 = DomSpace.domain();
  168. isl::space Space2 = DomSpace.range();
  169. isl::map Swap = makeTupleSwapMap(Space1, Space2);
  170. return Map.apply_domain(Swap);
  171. }
  172. isl::union_map polly::reverseDomain(const isl::union_map &UMap) {
  173. isl::union_map Result = isl::union_map::empty(UMap.ctx());
  174. for (isl::map Map : UMap.get_map_list()) {
  175. auto Reversed = reverseDomain(std::move(Map));
  176. Result = Result.unite(Reversed);
  177. }
  178. return Result;
  179. }
  180. isl::set polly::shiftDim(isl::set Set, int Pos, int Amount) {
  181. unsigned NumDims = unsignedFromIslSize(Set.tuple_dim());
  182. if (Pos < 0)
  183. Pos = NumDims + Pos;
  184. assert(unsigned(Pos) < NumDims && "Dimension index must be in range");
  185. isl::space Space = Set.get_space();
  186. Space = Space.map_from_domain_and_range(Space);
  187. isl::multi_aff Translator = makeShiftDimAff(Space, Pos, Amount);
  188. isl::map TranslatorMap = isl::map::from_multi_aff(Translator);
  189. return Set.apply(TranslatorMap);
  190. }
  191. isl::union_set polly::shiftDim(isl::union_set USet, int Pos, int Amount) {
  192. isl::union_set Result = isl::union_set::empty(USet.ctx());
  193. for (isl::set Set : USet.get_set_list()) {
  194. isl::set Shifted = shiftDim(Set, Pos, Amount);
  195. Result = Result.unite(Shifted);
  196. }
  197. return Result;
  198. }
  199. isl::map polly::shiftDim(isl::map Map, isl::dim Dim, int Pos, int Amount) {
  200. unsigned NumDims = unsignedFromIslSize(Map.dim(Dim));
  201. if (Pos < 0)
  202. Pos = NumDims + Pos;
  203. assert(unsigned(Pos) < NumDims && "Dimension index must be in range");
  204. isl::space Space = Map.get_space();
  205. switch (Dim) {
  206. case isl::dim::in:
  207. Space = Space.domain();
  208. break;
  209. case isl::dim::out:
  210. Space = Space.range();
  211. break;
  212. default:
  213. llvm_unreachable("Unsupported value for 'dim'");
  214. }
  215. Space = Space.map_from_domain_and_range(Space);
  216. isl::multi_aff Translator = makeShiftDimAff(Space, Pos, Amount);
  217. isl::map TranslatorMap = isl::map::from_multi_aff(Translator);
  218. switch (Dim) {
  219. case isl::dim::in:
  220. return Map.apply_domain(TranslatorMap);
  221. case isl::dim::out:
  222. return Map.apply_range(TranslatorMap);
  223. default:
  224. llvm_unreachable("Unsupported value for 'dim'");
  225. }
  226. }
  227. isl::val polly::getConstant(isl::map Map, isl::dim Dim, int Pos) {
  228. unsigned NumDims = unsignedFromIslSize(Map.dim(Dim));
  229. if (Pos < 0)
  230. Pos = NumDims + Pos;
  231. assert(unsigned(Pos) < NumDims && "Dimension index must be in range");
  232. // TODO: The isl_map_plain_get_val_if_fixed function is not robust, since its
  233. // result is different depending on the internal representation.
  234. // Replace it with a different implementation.
  235. return isl::manage(isl_map_plain_get_val_if_fixed(
  236. Map.get(), static_cast<enum isl_dim_type>(Dim), Pos));
  237. }
  238. isl::union_map polly::shiftDim(isl::union_map UMap, isl::dim Dim, int Pos,
  239. int Amount) {
  240. isl::union_map Result = isl::union_map::empty(UMap.ctx());
  241. for (isl::map Map : UMap.get_map_list()) {
  242. isl::map Shifted = shiftDim(Map, Dim, Pos, Amount);
  243. Result = Result.unite(Shifted);
  244. }
  245. return Result;
  246. }
  247. void polly::simplify(isl::set &Set) {
  248. Set = isl::manage(isl_set_compute_divs(Set.copy()));
  249. Set = Set.detect_equalities();
  250. Set = Set.coalesce();
  251. }
  252. void polly::simplify(isl::union_set &USet) {
  253. USet = isl::manage(isl_union_set_compute_divs(USet.copy()));
  254. USet = USet.detect_equalities();
  255. USet = USet.coalesce();
  256. }
  257. void polly::simplify(isl::map &Map) {
  258. Map = isl::manage(isl_map_compute_divs(Map.copy()));
  259. Map = Map.detect_equalities();
  260. Map = Map.coalesce();
  261. }
  262. void polly::simplify(isl::union_map &UMap) {
  263. UMap = isl::manage(isl_union_map_compute_divs(UMap.copy()));
  264. UMap = UMap.detect_equalities();
  265. UMap = UMap.coalesce();
  266. }
  267. isl::union_map polly::computeReachingWrite(isl::union_map Schedule,
  268. isl::union_map Writes, bool Reverse,
  269. bool InclPrevDef, bool InclNextDef) {
  270. // { Scatter[] }
  271. isl::space ScatterSpace = getScatterSpace(Schedule);
  272. // { ScatterRead[] -> ScatterWrite[] }
  273. isl::map Relation;
  274. if (Reverse)
  275. Relation = InclPrevDef ? isl::map::lex_lt(ScatterSpace)
  276. : isl::map::lex_le(ScatterSpace);
  277. else
  278. Relation = InclNextDef ? isl::map::lex_gt(ScatterSpace)
  279. : isl::map::lex_ge(ScatterSpace);
  280. // { ScatterWrite[] -> [ScatterRead[] -> ScatterWrite[]] }
  281. isl::map RelationMap = Relation.range_map().reverse();
  282. // { Element[] -> ScatterWrite[] }
  283. isl::union_map WriteAction = Schedule.apply_domain(Writes);
  284. // { ScatterWrite[] -> Element[] }
  285. isl::union_map WriteActionRev = WriteAction.reverse();
  286. // { Element[] -> [ScatterUse[] -> ScatterWrite[]] }
  287. isl::union_map DefSchedRelation =
  288. isl::union_map(RelationMap).apply_domain(WriteActionRev);
  289. // For each element, at every point in time, map to the times of previous
  290. // definitions. { [Element[] -> ScatterRead[]] -> ScatterWrite[] }
  291. isl::union_map ReachableWrites = DefSchedRelation.uncurry();
  292. if (Reverse)
  293. ReachableWrites = ReachableWrites.lexmin();
  294. else
  295. ReachableWrites = ReachableWrites.lexmax();
  296. // { [Element[] -> ScatterWrite[]] -> ScatterWrite[] }
  297. isl::union_map SelfUse = WriteAction.range_map();
  298. if (InclPrevDef && InclNextDef) {
  299. // Add the Def itself to the solution.
  300. ReachableWrites = ReachableWrites.unite(SelfUse).coalesce();
  301. } else if (!InclPrevDef && !InclNextDef) {
  302. // Remove Def itself from the solution.
  303. ReachableWrites = ReachableWrites.subtract(SelfUse);
  304. }
  305. // { [Element[] -> ScatterRead[]] -> Domain[] }
  306. return ReachableWrites.apply_range(Schedule.reverse());
  307. }
  308. isl::union_map
  309. polly::computeArrayUnused(isl::union_map Schedule, isl::union_map Writes,
  310. isl::union_map Reads, bool ReadEltInSameInst,
  311. bool IncludeLastRead, bool IncludeWrite) {
  312. // { Element[] -> Scatter[] }
  313. isl::union_map ReadActions = Schedule.apply_domain(Reads);
  314. isl::union_map WriteActions = Schedule.apply_domain(Writes);
  315. // { [Element[] -> DomainWrite[]] -> Scatter[] }
  316. isl::union_map EltDomWrites =
  317. Writes.reverse().range_map().apply_range(Schedule);
  318. // { [Element[] -> Scatter[]] -> DomainWrite[] }
  319. isl::union_map ReachingOverwrite = computeReachingWrite(
  320. Schedule, Writes, true, ReadEltInSameInst, !ReadEltInSameInst);
  321. // { [Element[] -> Scatter[]] -> DomainWrite[] }
  322. isl::union_map ReadsOverwritten =
  323. ReachingOverwrite.intersect_domain(ReadActions.wrap());
  324. // { [Element[] -> DomainWrite[]] -> Scatter[] }
  325. isl::union_map ReadsOverwrittenRotated =
  326. reverseDomain(ReadsOverwritten).curry().reverse();
  327. isl::union_map LastOverwrittenRead = ReadsOverwrittenRotated.lexmax();
  328. // { [Element[] -> DomainWrite[]] -> Scatter[] }
  329. isl::union_map BetweenLastReadOverwrite = betweenScatter(
  330. LastOverwrittenRead, EltDomWrites, IncludeLastRead, IncludeWrite);
  331. // { [Element[] -> Scatter[]] -> DomainWrite[] }
  332. isl::union_map ReachingOverwriteZone = computeReachingWrite(
  333. Schedule, Writes, true, IncludeLastRead, IncludeWrite);
  334. // { [Element[] -> DomainWrite[]] -> Scatter[] }
  335. isl::union_map ReachingOverwriteRotated =
  336. reverseDomain(ReachingOverwriteZone).curry().reverse();
  337. // { [Element[] -> DomainWrite[]] -> Scatter[] }
  338. isl::union_map WritesWithoutReads = ReachingOverwriteRotated.subtract_domain(
  339. ReadsOverwrittenRotated.domain());
  340. return BetweenLastReadOverwrite.unite(WritesWithoutReads)
  341. .domain_factor_domain();
  342. }
  343. isl::union_set polly::convertZoneToTimepoints(isl::union_set Zone,
  344. bool InclStart, bool InclEnd) {
  345. if (!InclStart && InclEnd)
  346. return Zone;
  347. auto ShiftedZone = shiftDim(Zone, -1, -1);
  348. if (InclStart && !InclEnd)
  349. return ShiftedZone;
  350. else if (!InclStart && !InclEnd)
  351. return Zone.intersect(ShiftedZone);
  352. assert(InclStart && InclEnd);
  353. return Zone.unite(ShiftedZone);
  354. }
  355. isl::union_map polly::convertZoneToTimepoints(isl::union_map Zone, isl::dim Dim,
  356. bool InclStart, bool InclEnd) {
  357. if (!InclStart && InclEnd)
  358. return Zone;
  359. auto ShiftedZone = shiftDim(Zone, Dim, -1, -1);
  360. if (InclStart && !InclEnd)
  361. return ShiftedZone;
  362. else if (!InclStart && !InclEnd)
  363. return Zone.intersect(ShiftedZone);
  364. assert(InclStart && InclEnd);
  365. return Zone.unite(ShiftedZone);
  366. }
  367. isl::map polly::convertZoneToTimepoints(isl::map Zone, isl::dim Dim,
  368. bool InclStart, bool InclEnd) {
  369. if (!InclStart && InclEnd)
  370. return Zone;
  371. auto ShiftedZone = shiftDim(Zone, Dim, -1, -1);
  372. if (InclStart && !InclEnd)
  373. return ShiftedZone;
  374. else if (!InclStart && !InclEnd)
  375. return Zone.intersect(ShiftedZone);
  376. assert(InclStart && InclEnd);
  377. return Zone.unite(ShiftedZone);
  378. }
  379. isl::map polly::distributeDomain(isl::map Map) {
  380. // Note that we cannot take Map apart into { Domain[] -> Range1[] } and {
  381. // Domain[] -> Range2[] } and combine again. We would loose any relation
  382. // between Range1[] and Range2[] that is not also a constraint to Domain[].
  383. isl::space Space = Map.get_space();
  384. isl::space DomainSpace = Space.domain();
  385. if (DomainSpace.is_null())
  386. return {};
  387. unsigned DomainDims = unsignedFromIslSize(DomainSpace.dim(isl::dim::set));
  388. isl::space RangeSpace = Space.range().unwrap();
  389. isl::space Range1Space = RangeSpace.domain();
  390. if (Range1Space.is_null())
  391. return {};
  392. unsigned Range1Dims = unsignedFromIslSize(Range1Space.dim(isl::dim::set));
  393. isl::space Range2Space = RangeSpace.range();
  394. if (Range2Space.is_null())
  395. return {};
  396. unsigned Range2Dims = unsignedFromIslSize(Range2Space.dim(isl::dim::set));
  397. isl::space OutputSpace =
  398. DomainSpace.map_from_domain_and_range(Range1Space)
  399. .wrap()
  400. .map_from_domain_and_range(
  401. DomainSpace.map_from_domain_and_range(Range2Space).wrap());
  402. isl::basic_map Translator = isl::basic_map::universe(
  403. Space.wrap().map_from_domain_and_range(OutputSpace.wrap()));
  404. for (unsigned i = 0; i < DomainDims; i += 1) {
  405. Translator = Translator.equate(isl::dim::in, i, isl::dim::out, i);
  406. Translator = Translator.equate(isl::dim::in, i, isl::dim::out,
  407. DomainDims + Range1Dims + i);
  408. }
  409. for (unsigned i = 0; i < Range1Dims; i += 1)
  410. Translator = Translator.equate(isl::dim::in, DomainDims + i, isl::dim::out,
  411. DomainDims + i);
  412. for (unsigned i = 0; i < Range2Dims; i += 1)
  413. Translator = Translator.equate(isl::dim::in, DomainDims + Range1Dims + i,
  414. isl::dim::out,
  415. DomainDims + Range1Dims + DomainDims + i);
  416. return Map.wrap().apply(Translator).unwrap();
  417. }
  418. isl::union_map polly::distributeDomain(isl::union_map UMap) {
  419. isl::union_map Result = isl::union_map::empty(UMap.ctx());
  420. for (isl::map Map : UMap.get_map_list()) {
  421. auto Distributed = distributeDomain(Map);
  422. Result = Result.unite(Distributed);
  423. }
  424. return Result;
  425. }
  426. isl::union_map polly::liftDomains(isl::union_map UMap, isl::union_set Factor) {
  427. // { Factor[] -> Factor[] }
  428. isl::union_map Factors = makeIdentityMap(Factor, true);
  429. return Factors.product(UMap);
  430. }
  431. isl::union_map polly::applyDomainRange(isl::union_map UMap,
  432. isl::union_map Func) {
  433. // This implementation creates unnecessary cross products of the
  434. // DomainDomain[] and Func. An alternative implementation could reverse
  435. // domain+uncurry,apply Func to what now is the domain, then undo the
  436. // preparing transformation. Another alternative implementation could create a
  437. // translator map for each piece.
  438. // { DomainDomain[] }
  439. isl::union_set DomainDomain = UMap.domain().unwrap().domain();
  440. // { [DomainDomain[] -> DomainRange[]] -> [DomainDomain[] -> NewDomainRange[]]
  441. // }
  442. isl::union_map LifetedFunc = liftDomains(std::move(Func), DomainDomain);
  443. return UMap.apply_domain(LifetedFunc);
  444. }
  445. isl::map polly::intersectRange(isl::map Map, isl::union_set Range) {
  446. isl::set RangeSet = Range.extract_set(Map.get_space().range());
  447. return Map.intersect_range(RangeSet);
  448. }
  449. isl::map polly::subtractParams(isl::map Map, isl::set Params) {
  450. auto MapSpace = Map.get_space();
  451. auto ParamsMap = isl::map::universe(MapSpace).intersect_params(Params);
  452. return Map.subtract(ParamsMap);
  453. }
  454. isl::set polly::subtractParams(isl::set Set, isl::set Params) {
  455. isl::space SetSpace = Set.get_space();
  456. isl::set ParamsSet = isl::set::universe(SetSpace).intersect_params(Params);
  457. return Set.subtract(ParamsSet);
  458. }
  459. isl::val polly::getConstant(isl::pw_aff PwAff, bool Max, bool Min) {
  460. assert(!Max || !Min); // Cannot return min and max at the same time.
  461. isl::val Result;
  462. isl::stat Stat = PwAff.foreach_piece(
  463. [=, &Result](isl::set Set, isl::aff Aff) -> isl::stat {
  464. if (!Result.is_null() && Result.is_nan())
  465. return isl::stat::ok();
  466. // TODO: If Min/Max, we can also determine a minimum/maximum value if
  467. // Set is constant-bounded.
  468. if (!Aff.is_cst()) {
  469. Result = isl::val::nan(Aff.ctx());
  470. return isl::stat::error();
  471. }
  472. isl::val ThisVal = Aff.get_constant_val();
  473. if (Result.is_null()) {
  474. Result = ThisVal;
  475. return isl::stat::ok();
  476. }
  477. if (Result.eq(ThisVal))
  478. return isl::stat::ok();
  479. if (Max && ThisVal.gt(Result)) {
  480. Result = ThisVal;
  481. return isl::stat::ok();
  482. }
  483. if (Min && ThisVal.lt(Result)) {
  484. Result = ThisVal;
  485. return isl::stat::ok();
  486. }
  487. // Not compatible
  488. Result = isl::val::nan(Aff.ctx());
  489. return isl::stat::error();
  490. });
  491. if (Stat.is_error())
  492. return {};
  493. return Result;
  494. }
  495. llvm::iota_range<unsigned> polly::rangeIslSize(unsigned Begin, isl::size End) {
  496. unsigned UEnd = unsignedFromIslSize(End);
  497. return llvm::seq<unsigned>(std::min(Begin, UEnd), UEnd);
  498. }
  499. #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
  500. static void foreachPoint(const isl::set &Set,
  501. const std::function<void(isl::point P)> &F) {
  502. Set.foreach_point([&](isl::point P) -> isl::stat {
  503. F(P);
  504. return isl::stat::ok();
  505. });
  506. }
  507. static void foreachPoint(isl::basic_set BSet,
  508. const std::function<void(isl::point P)> &F) {
  509. foreachPoint(isl::set(BSet), F);
  510. }
  511. /// Determine the sorting order of the sets @p A and @p B without considering
  512. /// the space structure.
  513. ///
  514. /// Ordering is based on the lower bounds of the set's dimensions. First
  515. /// dimensions are considered first.
  516. static int flatCompare(const isl::basic_set &A, const isl::basic_set &B) {
  517. // Quick bail-out on out-of-quota.
  518. if (A.is_null() || B.is_null())
  519. return 0;
  520. unsigned ALen = unsignedFromIslSize(A.dim(isl::dim::set));
  521. unsigned BLen = unsignedFromIslSize(B.dim(isl::dim::set));
  522. unsigned Len = std::min(ALen, BLen);
  523. for (unsigned i = 0; i < Len; i += 1) {
  524. isl::basic_set ADim =
  525. A.project_out(isl::dim::param, 0,
  526. unsignedFromIslSize(A.dim(isl::dim::param)))
  527. .project_out(isl::dim::set, i + 1, ALen - i - 1)
  528. .project_out(isl::dim::set, 0, i);
  529. isl::basic_set BDim =
  530. B.project_out(isl::dim::param, 0,
  531. unsignedFromIslSize(B.dim(isl::dim::param)))
  532. .project_out(isl::dim::set, i + 1, BLen - i - 1)
  533. .project_out(isl::dim::set, 0, i);
  534. isl::basic_set AHull = isl::set(ADim).convex_hull();
  535. isl::basic_set BHull = isl::set(BDim).convex_hull();
  536. bool ALowerBounded =
  537. bool(isl::set(AHull).dim_has_any_lower_bound(isl::dim::set, 0));
  538. bool BLowerBounded =
  539. bool(isl::set(BHull).dim_has_any_lower_bound(isl::dim::set, 0));
  540. int BoundedCompare = BLowerBounded - ALowerBounded;
  541. if (BoundedCompare != 0)
  542. return BoundedCompare;
  543. if (!ALowerBounded || !BLowerBounded)
  544. continue;
  545. isl::pw_aff AMin = isl::set(ADim).dim_min(0);
  546. isl::pw_aff BMin = isl::set(BDim).dim_min(0);
  547. isl::val AMinVal = polly::getConstant(AMin, false, true);
  548. isl::val BMinVal = polly::getConstant(BMin, false, true);
  549. int MinCompare = AMinVal.sub(BMinVal).sgn();
  550. if (MinCompare != 0)
  551. return MinCompare;
  552. }
  553. // If all the dimensions' lower bounds are equal or incomparable, sort based
  554. // on the number of dimensions.
  555. return ALen - BLen;
  556. }
  557. /// Compare the sets @p A and @p B according to their nested space structure.
  558. /// Returns 0 if the structure is considered equal.
  559. /// If @p ConsiderTupleLen is false, the number of dimensions in a tuple are
  560. /// ignored, i.e. a tuple with the same name but different number of dimensions
  561. /// are considered equal.
  562. static int structureCompare(const isl::space &ASpace, const isl::space &BSpace,
  563. bool ConsiderTupleLen) {
  564. int WrappingCompare = bool(ASpace.is_wrapping()) - bool(BSpace.is_wrapping());
  565. if (WrappingCompare != 0)
  566. return WrappingCompare;
  567. if (ASpace.is_wrapping() && BSpace.is_wrapping()) {
  568. isl::space AMap = ASpace.unwrap();
  569. isl::space BMap = BSpace.unwrap();
  570. int FirstResult =
  571. structureCompare(AMap.domain(), BMap.domain(), ConsiderTupleLen);
  572. if (FirstResult != 0)
  573. return FirstResult;
  574. return structureCompare(AMap.range(), BMap.range(), ConsiderTupleLen);
  575. }
  576. std::string AName;
  577. if (!ASpace.is_params() && ASpace.has_tuple_name(isl::dim::set))
  578. AName = ASpace.get_tuple_name(isl::dim::set);
  579. std::string BName;
  580. if (!BSpace.is_params() && BSpace.has_tuple_name(isl::dim::set))
  581. BName = BSpace.get_tuple_name(isl::dim::set);
  582. int NameCompare = AName.compare(BName);
  583. if (NameCompare != 0)
  584. return NameCompare;
  585. if (ConsiderTupleLen) {
  586. int LenCompare = (int)unsignedFromIslSize(BSpace.dim(isl::dim::set)) -
  587. (int)unsignedFromIslSize(ASpace.dim(isl::dim::set));
  588. if (LenCompare != 0)
  589. return LenCompare;
  590. }
  591. return 0;
  592. }
  593. /// Compare the sets @p A and @p B according to their nested space structure. If
  594. /// the structure is the same, sort using the dimension lower bounds.
  595. /// Returns an std::sort compatible bool.
  596. static bool orderComparer(const isl::basic_set &A, const isl::basic_set &B) {
  597. isl::space ASpace = A.get_space();
  598. isl::space BSpace = B.get_space();
  599. // Ignoring number of dimensions first ensures that structures with same tuple
  600. // names, but different number of dimensions are still sorted close together.
  601. int TupleNestingCompare = structureCompare(ASpace, BSpace, false);
  602. if (TupleNestingCompare != 0)
  603. return TupleNestingCompare < 0;
  604. int TupleCompare = structureCompare(ASpace, BSpace, true);
  605. if (TupleCompare != 0)
  606. return TupleCompare < 0;
  607. return flatCompare(A, B) < 0;
  608. }
  609. /// Print a string representation of @p USet to @p OS.
  610. ///
  611. /// The pieces of @p USet are printed in a sorted order. Spaces with equal or
  612. /// similar nesting structure are printed together. Compared to isl's own
  613. /// printing function the uses the structure itself as base of the sorting, not
  614. /// a hash of it. It ensures that e.g. maps spaces with same domain structure
  615. /// are printed together. Set pieces with same structure are printed in order of
  616. /// their lower bounds.
  617. ///
  618. /// @param USet Polyhedra to print.
  619. /// @param OS Target stream.
  620. /// @param Simplify Whether to simplify the polyhedron before printing.
  621. /// @param IsMap Whether @p USet is a wrapped map. If true, sets are
  622. /// unwrapped before printing to again appear as a map.
  623. static void printSortedPolyhedra(isl::union_set USet, llvm::raw_ostream &OS,
  624. bool Simplify, bool IsMap) {
  625. if (USet.is_null()) {
  626. OS << "<null>\n";
  627. return;
  628. }
  629. if (Simplify)
  630. simplify(USet);
  631. // Get all the polyhedra.
  632. std::vector<isl::basic_set> BSets;
  633. for (isl::set Set : USet.get_set_list()) {
  634. for (isl::basic_set BSet : Set.get_basic_set_list()) {
  635. BSets.push_back(BSet);
  636. }
  637. }
  638. if (BSets.empty()) {
  639. OS << "{\n}\n";
  640. return;
  641. }
  642. // Sort the polyhedra.
  643. llvm::sort(BSets, orderComparer);
  644. // Print the polyhedra.
  645. bool First = true;
  646. for (const isl::basic_set &BSet : BSets) {
  647. std::string Str;
  648. if (IsMap)
  649. Str = stringFromIslObj(isl::map(BSet.unwrap()));
  650. else
  651. Str = stringFromIslObj(isl::set(BSet));
  652. size_t OpenPos = Str.find_first_of('{');
  653. assert(OpenPos != std::string::npos);
  654. size_t ClosePos = Str.find_last_of('}');
  655. assert(ClosePos != std::string::npos);
  656. if (First)
  657. OS << llvm::StringRef(Str).substr(0, OpenPos + 1) << "\n ";
  658. else
  659. OS << ";\n ";
  660. OS << llvm::StringRef(Str).substr(OpenPos + 1, ClosePos - OpenPos - 2);
  661. First = false;
  662. }
  663. assert(!First);
  664. OS << "\n}\n";
  665. }
  666. static void recursiveExpand(isl::basic_set BSet, unsigned Dim,
  667. isl::set &Expanded) {
  668. unsigned Dims = unsignedFromIslSize(BSet.dim(isl::dim::set));
  669. if (Dim >= Dims) {
  670. Expanded = Expanded.unite(BSet);
  671. return;
  672. }
  673. isl::basic_set DimOnly =
  674. BSet.project_out(isl::dim::param, 0,
  675. unsignedFromIslSize(BSet.dim(isl::dim::param)))
  676. .project_out(isl::dim::set, Dim + 1, Dims - Dim - 1)
  677. .project_out(isl::dim::set, 0, Dim);
  678. if (!DimOnly.is_bounded()) {
  679. recursiveExpand(BSet, Dim + 1, Expanded);
  680. return;
  681. }
  682. foreachPoint(DimOnly, [&, Dim](isl::point P) {
  683. isl::val Val = P.get_coordinate_val(isl::dim::set, 0);
  684. isl::basic_set FixBSet = BSet.fix_val(isl::dim::set, Dim, Val);
  685. recursiveExpand(FixBSet, Dim + 1, Expanded);
  686. });
  687. }
  688. /// Make each point of a set explicit.
  689. ///
  690. /// "Expanding" makes each point a set contains explicit. That is, the result is
  691. /// a set of singleton polyhedra. Unbounded dimensions are not expanded.
  692. ///
  693. /// Example:
  694. /// { [i] : 0 <= i < 2 }
  695. /// is expanded to:
  696. /// { [0]; [1] }
  697. static isl::set expand(const isl::set &Set) {
  698. isl::set Expanded = isl::set::empty(Set.get_space());
  699. for (isl::basic_set BSet : Set.get_basic_set_list())
  700. recursiveExpand(BSet, 0, Expanded);
  701. return Expanded;
  702. }
  703. /// Expand all points of a union set explicit.
  704. ///
  705. /// @see expand(const isl::set)
  706. static isl::union_set expand(const isl::union_set &USet) {
  707. isl::union_set Expanded = isl::union_set::empty(USet.ctx());
  708. for (isl::set Set : USet.get_set_list()) {
  709. isl::set SetExpanded = expand(Set);
  710. Expanded = Expanded.unite(SetExpanded);
  711. }
  712. return Expanded;
  713. }
  714. LLVM_DUMP_METHOD void polly::dumpPw(const isl::set &Set) {
  715. printSortedPolyhedra(Set, llvm::errs(), true, false);
  716. }
  717. LLVM_DUMP_METHOD void polly::dumpPw(const isl::map &Map) {
  718. printSortedPolyhedra(Map.wrap(), llvm::errs(), true, true);
  719. }
  720. LLVM_DUMP_METHOD void polly::dumpPw(const isl::union_set &USet) {
  721. printSortedPolyhedra(USet, llvm::errs(), true, false);
  722. }
  723. LLVM_DUMP_METHOD void polly::dumpPw(const isl::union_map &UMap) {
  724. printSortedPolyhedra(UMap.wrap(), llvm::errs(), true, true);
  725. }
  726. LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_set *Set) {
  727. dumpPw(isl::manage_copy(Set));
  728. }
  729. LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_map *Map) {
  730. dumpPw(isl::manage_copy(Map));
  731. }
  732. LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_union_set *USet) {
  733. dumpPw(isl::manage_copy(USet));
  734. }
  735. LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_union_map *UMap) {
  736. dumpPw(isl::manage_copy(UMap));
  737. }
  738. LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::set &Set) {
  739. printSortedPolyhedra(expand(Set), llvm::errs(), false, false);
  740. }
  741. LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::map &Map) {
  742. printSortedPolyhedra(expand(Map.wrap()), llvm::errs(), false, true);
  743. }
  744. LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::union_set &USet) {
  745. printSortedPolyhedra(expand(USet), llvm::errs(), false, false);
  746. }
  747. LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::union_map &UMap) {
  748. printSortedPolyhedra(expand(UMap.wrap()), llvm::errs(), false, true);
  749. }
  750. LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_set *Set) {
  751. dumpExpanded(isl::manage_copy(Set));
  752. }
  753. LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_map *Map) {
  754. dumpExpanded(isl::manage_copy(Map));
  755. }
  756. LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_union_set *USet) {
  757. dumpExpanded(isl::manage_copy(USet));
  758. }
  759. LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_union_map *UMap) {
  760. dumpExpanded(isl::manage_copy(UMap));
  761. }
  762. #endif