ISLTools.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  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::union_map polly::shiftDim(isl::union_map UMap, isl::dim Dim, int Pos,
  228. int Amount) {
  229. isl::union_map Result = isl::union_map::empty(UMap.ctx());
  230. for (isl::map Map : UMap.get_map_list()) {
  231. isl::map Shifted = shiftDim(Map, Dim, Pos, Amount);
  232. Result = Result.unite(Shifted);
  233. }
  234. return Result;
  235. }
  236. void polly::simplify(isl::set &Set) {
  237. Set = isl::manage(isl_set_compute_divs(Set.copy()));
  238. Set = Set.detect_equalities();
  239. Set = Set.coalesce();
  240. }
  241. void polly::simplify(isl::union_set &USet) {
  242. USet = isl::manage(isl_union_set_compute_divs(USet.copy()));
  243. USet = USet.detect_equalities();
  244. USet = USet.coalesce();
  245. }
  246. void polly::simplify(isl::map &Map) {
  247. Map = isl::manage(isl_map_compute_divs(Map.copy()));
  248. Map = Map.detect_equalities();
  249. Map = Map.coalesce();
  250. }
  251. void polly::simplify(isl::union_map &UMap) {
  252. UMap = isl::manage(isl_union_map_compute_divs(UMap.copy()));
  253. UMap = UMap.detect_equalities();
  254. UMap = UMap.coalesce();
  255. }
  256. isl::union_map polly::computeReachingWrite(isl::union_map Schedule,
  257. isl::union_map Writes, bool Reverse,
  258. bool InclPrevDef, bool InclNextDef) {
  259. // { Scatter[] }
  260. isl::space ScatterSpace = getScatterSpace(Schedule);
  261. // { ScatterRead[] -> ScatterWrite[] }
  262. isl::map Relation;
  263. if (Reverse)
  264. Relation = InclPrevDef ? isl::map::lex_lt(ScatterSpace)
  265. : isl::map::lex_le(ScatterSpace);
  266. else
  267. Relation = InclNextDef ? isl::map::lex_gt(ScatterSpace)
  268. : isl::map::lex_ge(ScatterSpace);
  269. // { ScatterWrite[] -> [ScatterRead[] -> ScatterWrite[]] }
  270. isl::map RelationMap = Relation.range_map().reverse();
  271. // { Element[] -> ScatterWrite[] }
  272. isl::union_map WriteAction = Schedule.apply_domain(Writes);
  273. // { ScatterWrite[] -> Element[] }
  274. isl::union_map WriteActionRev = WriteAction.reverse();
  275. // { Element[] -> [ScatterUse[] -> ScatterWrite[]] }
  276. isl::union_map DefSchedRelation =
  277. isl::union_map(RelationMap).apply_domain(WriteActionRev);
  278. // For each element, at every point in time, map to the times of previous
  279. // definitions. { [Element[] -> ScatterRead[]] -> ScatterWrite[] }
  280. isl::union_map ReachableWrites = DefSchedRelation.uncurry();
  281. if (Reverse)
  282. ReachableWrites = ReachableWrites.lexmin();
  283. else
  284. ReachableWrites = ReachableWrites.lexmax();
  285. // { [Element[] -> ScatterWrite[]] -> ScatterWrite[] }
  286. isl::union_map SelfUse = WriteAction.range_map();
  287. if (InclPrevDef && InclNextDef) {
  288. // Add the Def itself to the solution.
  289. ReachableWrites = ReachableWrites.unite(SelfUse).coalesce();
  290. } else if (!InclPrevDef && !InclNextDef) {
  291. // Remove Def itself from the solution.
  292. ReachableWrites = ReachableWrites.subtract(SelfUse);
  293. }
  294. // { [Element[] -> ScatterRead[]] -> Domain[] }
  295. return ReachableWrites.apply_range(Schedule.reverse());
  296. }
  297. isl::union_map
  298. polly::computeArrayUnused(isl::union_map Schedule, isl::union_map Writes,
  299. isl::union_map Reads, bool ReadEltInSameInst,
  300. bool IncludeLastRead, bool IncludeWrite) {
  301. // { Element[] -> Scatter[] }
  302. isl::union_map ReadActions = Schedule.apply_domain(Reads);
  303. isl::union_map WriteActions = Schedule.apply_domain(Writes);
  304. // { [Element[] -> DomainWrite[]] -> Scatter[] }
  305. isl::union_map EltDomWrites =
  306. Writes.reverse().range_map().apply_range(Schedule);
  307. // { [Element[] -> Scatter[]] -> DomainWrite[] }
  308. isl::union_map ReachingOverwrite = computeReachingWrite(
  309. Schedule, Writes, true, ReadEltInSameInst, !ReadEltInSameInst);
  310. // { [Element[] -> Scatter[]] -> DomainWrite[] }
  311. isl::union_map ReadsOverwritten =
  312. ReachingOverwrite.intersect_domain(ReadActions.wrap());
  313. // { [Element[] -> DomainWrite[]] -> Scatter[] }
  314. isl::union_map ReadsOverwrittenRotated =
  315. reverseDomain(ReadsOverwritten).curry().reverse();
  316. isl::union_map LastOverwrittenRead = ReadsOverwrittenRotated.lexmax();
  317. // { [Element[] -> DomainWrite[]] -> Scatter[] }
  318. isl::union_map BetweenLastReadOverwrite = betweenScatter(
  319. LastOverwrittenRead, EltDomWrites, IncludeLastRead, IncludeWrite);
  320. // { [Element[] -> Scatter[]] -> DomainWrite[] }
  321. isl::union_map ReachingOverwriteZone = computeReachingWrite(
  322. Schedule, Writes, true, IncludeLastRead, IncludeWrite);
  323. // { [Element[] -> DomainWrite[]] -> Scatter[] }
  324. isl::union_map ReachingOverwriteRotated =
  325. reverseDomain(ReachingOverwriteZone).curry().reverse();
  326. // { [Element[] -> DomainWrite[]] -> Scatter[] }
  327. isl::union_map WritesWithoutReads = ReachingOverwriteRotated.subtract_domain(
  328. ReadsOverwrittenRotated.domain());
  329. return BetweenLastReadOverwrite.unite(WritesWithoutReads)
  330. .domain_factor_domain();
  331. }
  332. isl::union_set polly::convertZoneToTimepoints(isl::union_set Zone,
  333. bool InclStart, bool InclEnd) {
  334. if (!InclStart && InclEnd)
  335. return Zone;
  336. auto ShiftedZone = shiftDim(Zone, -1, -1);
  337. if (InclStart && !InclEnd)
  338. return ShiftedZone;
  339. else if (!InclStart && !InclEnd)
  340. return Zone.intersect(ShiftedZone);
  341. assert(InclStart && InclEnd);
  342. return Zone.unite(ShiftedZone);
  343. }
  344. isl::union_map polly::convertZoneToTimepoints(isl::union_map Zone, isl::dim Dim,
  345. bool InclStart, bool InclEnd) {
  346. if (!InclStart && InclEnd)
  347. return Zone;
  348. auto ShiftedZone = shiftDim(Zone, Dim, -1, -1);
  349. if (InclStart && !InclEnd)
  350. return ShiftedZone;
  351. else if (!InclStart && !InclEnd)
  352. return Zone.intersect(ShiftedZone);
  353. assert(InclStart && InclEnd);
  354. return Zone.unite(ShiftedZone);
  355. }
  356. isl::map polly::convertZoneToTimepoints(isl::map Zone, isl::dim Dim,
  357. bool InclStart, bool InclEnd) {
  358. if (!InclStart && InclEnd)
  359. return Zone;
  360. auto ShiftedZone = shiftDim(Zone, Dim, -1, -1);
  361. if (InclStart && !InclEnd)
  362. return ShiftedZone;
  363. else if (!InclStart && !InclEnd)
  364. return Zone.intersect(ShiftedZone);
  365. assert(InclStart && InclEnd);
  366. return Zone.unite(ShiftedZone);
  367. }
  368. isl::map polly::distributeDomain(isl::map Map) {
  369. // Note that we cannot take Map apart into { Domain[] -> Range1[] } and {
  370. // Domain[] -> Range2[] } and combine again. We would loose any relation
  371. // between Range1[] and Range2[] that is not also a constraint to Domain[].
  372. isl::space Space = Map.get_space();
  373. isl::space DomainSpace = Space.domain();
  374. if (DomainSpace.is_null())
  375. return {};
  376. unsigned DomainDims = unsignedFromIslSize(DomainSpace.dim(isl::dim::set));
  377. isl::space RangeSpace = Space.range().unwrap();
  378. isl::space Range1Space = RangeSpace.domain();
  379. if (Range1Space.is_null())
  380. return {};
  381. unsigned Range1Dims = unsignedFromIslSize(Range1Space.dim(isl::dim::set));
  382. isl::space Range2Space = RangeSpace.range();
  383. if (Range2Space.is_null())
  384. return {};
  385. unsigned Range2Dims = unsignedFromIslSize(Range2Space.dim(isl::dim::set));
  386. isl::space OutputSpace =
  387. DomainSpace.map_from_domain_and_range(Range1Space)
  388. .wrap()
  389. .map_from_domain_and_range(
  390. DomainSpace.map_from_domain_and_range(Range2Space).wrap());
  391. isl::basic_map Translator = isl::basic_map::universe(
  392. Space.wrap().map_from_domain_and_range(OutputSpace.wrap()));
  393. for (unsigned i = 0; i < DomainDims; i += 1) {
  394. Translator = Translator.equate(isl::dim::in, i, isl::dim::out, i);
  395. Translator = Translator.equate(isl::dim::in, i, isl::dim::out,
  396. DomainDims + Range1Dims + i);
  397. }
  398. for (unsigned i = 0; i < Range1Dims; i += 1)
  399. Translator = Translator.equate(isl::dim::in, DomainDims + i, isl::dim::out,
  400. DomainDims + i);
  401. for (unsigned i = 0; i < Range2Dims; i += 1)
  402. Translator = Translator.equate(isl::dim::in, DomainDims + Range1Dims + i,
  403. isl::dim::out,
  404. DomainDims + Range1Dims + DomainDims + i);
  405. return Map.wrap().apply(Translator).unwrap();
  406. }
  407. isl::union_map polly::distributeDomain(isl::union_map UMap) {
  408. isl::union_map Result = isl::union_map::empty(UMap.ctx());
  409. for (isl::map Map : UMap.get_map_list()) {
  410. auto Distributed = distributeDomain(Map);
  411. Result = Result.unite(Distributed);
  412. }
  413. return Result;
  414. }
  415. isl::union_map polly::liftDomains(isl::union_map UMap, isl::union_set Factor) {
  416. // { Factor[] -> Factor[] }
  417. isl::union_map Factors = makeIdentityMap(Factor, true);
  418. return Factors.product(UMap);
  419. }
  420. isl::union_map polly::applyDomainRange(isl::union_map UMap,
  421. isl::union_map Func) {
  422. // This implementation creates unnecessary cross products of the
  423. // DomainDomain[] and Func. An alternative implementation could reverse
  424. // domain+uncurry,apply Func to what now is the domain, then undo the
  425. // preparing transformation. Another alternative implementation could create a
  426. // translator map for each piece.
  427. // { DomainDomain[] }
  428. isl::union_set DomainDomain = UMap.domain().unwrap().domain();
  429. // { [DomainDomain[] -> DomainRange[]] -> [DomainDomain[] -> NewDomainRange[]]
  430. // }
  431. isl::union_map LifetedFunc = liftDomains(std::move(Func), DomainDomain);
  432. return UMap.apply_domain(LifetedFunc);
  433. }
  434. isl::map polly::intersectRange(isl::map Map, isl::union_set Range) {
  435. isl::set RangeSet = Range.extract_set(Map.get_space().range());
  436. return Map.intersect_range(RangeSet);
  437. }
  438. isl::map polly::subtractParams(isl::map Map, isl::set Params) {
  439. auto MapSpace = Map.get_space();
  440. auto ParamsMap = isl::map::universe(MapSpace).intersect_params(Params);
  441. return Map.subtract(ParamsMap);
  442. }
  443. isl::set polly::subtractParams(isl::set Set, isl::set Params) {
  444. isl::space SetSpace = Set.get_space();
  445. isl::set ParamsSet = isl::set::universe(SetSpace).intersect_params(Params);
  446. return Set.subtract(ParamsSet);
  447. }
  448. isl::val polly::getConstant(isl::pw_aff PwAff, bool Max, bool Min) {
  449. assert(!Max || !Min); // Cannot return min and max at the same time.
  450. isl::val Result;
  451. isl::stat Stat = PwAff.foreach_piece(
  452. [=, &Result](isl::set Set, isl::aff Aff) -> isl::stat {
  453. if (!Result.is_null() && Result.is_nan())
  454. return isl::stat::ok();
  455. // TODO: If Min/Max, we can also determine a minimum/maximum value if
  456. // Set is constant-bounded.
  457. if (!Aff.is_cst()) {
  458. Result = isl::val::nan(Aff.ctx());
  459. return isl::stat::error();
  460. }
  461. isl::val ThisVal = Aff.get_constant_val();
  462. if (Result.is_null()) {
  463. Result = ThisVal;
  464. return isl::stat::ok();
  465. }
  466. if (Result.eq(ThisVal))
  467. return isl::stat::ok();
  468. if (Max && ThisVal.gt(Result)) {
  469. Result = ThisVal;
  470. return isl::stat::ok();
  471. }
  472. if (Min && ThisVal.lt(Result)) {
  473. Result = ThisVal;
  474. return isl::stat::ok();
  475. }
  476. // Not compatible
  477. Result = isl::val::nan(Aff.ctx());
  478. return isl::stat::error();
  479. });
  480. if (Stat.is_error())
  481. return {};
  482. return Result;
  483. }
  484. llvm::iota_range<unsigned> polly::rangeIslSize(unsigned Begin, isl::size End) {
  485. unsigned UEnd = unsignedFromIslSize(End);
  486. return llvm::seq<unsigned>(std::min(Begin, UEnd), UEnd);
  487. }
  488. #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
  489. static void foreachPoint(const isl::set &Set,
  490. const std::function<void(isl::point P)> &F) {
  491. Set.foreach_point([&](isl::point P) -> isl::stat {
  492. F(P);
  493. return isl::stat::ok();
  494. });
  495. }
  496. static void foreachPoint(isl::basic_set BSet,
  497. const std::function<void(isl::point P)> &F) {
  498. foreachPoint(isl::set(BSet), F);
  499. }
  500. /// Determine the sorting order of the sets @p A and @p B without considering
  501. /// the space structure.
  502. ///
  503. /// Ordering is based on the lower bounds of the set's dimensions. First
  504. /// dimensions are considered first.
  505. static int flatCompare(const isl::basic_set &A, const isl::basic_set &B) {
  506. // Quick bail-out on out-of-quota.
  507. if (A.is_null() || B.is_null())
  508. return 0;
  509. unsigned ALen = unsignedFromIslSize(A.dim(isl::dim::set));
  510. unsigned BLen = unsignedFromIslSize(B.dim(isl::dim::set));
  511. unsigned Len = std::min(ALen, BLen);
  512. for (unsigned i = 0; i < Len; i += 1) {
  513. isl::basic_set ADim =
  514. A.project_out(isl::dim::param, 0,
  515. unsignedFromIslSize(A.dim(isl::dim::param)))
  516. .project_out(isl::dim::set, i + 1, ALen - i - 1)
  517. .project_out(isl::dim::set, 0, i);
  518. isl::basic_set BDim =
  519. B.project_out(isl::dim::param, 0,
  520. unsignedFromIslSize(B.dim(isl::dim::param)))
  521. .project_out(isl::dim::set, i + 1, BLen - i - 1)
  522. .project_out(isl::dim::set, 0, i);
  523. isl::basic_set AHull = isl::set(ADim).convex_hull();
  524. isl::basic_set BHull = isl::set(BDim).convex_hull();
  525. bool ALowerBounded =
  526. bool(isl::set(AHull).dim_has_any_lower_bound(isl::dim::set, 0));
  527. bool BLowerBounded =
  528. bool(isl::set(BHull).dim_has_any_lower_bound(isl::dim::set, 0));
  529. int BoundedCompare = BLowerBounded - ALowerBounded;
  530. if (BoundedCompare != 0)
  531. return BoundedCompare;
  532. if (!ALowerBounded || !BLowerBounded)
  533. continue;
  534. isl::pw_aff AMin = isl::set(ADim).dim_min(0);
  535. isl::pw_aff BMin = isl::set(BDim).dim_min(0);
  536. isl::val AMinVal = polly::getConstant(AMin, false, true);
  537. isl::val BMinVal = polly::getConstant(BMin, false, true);
  538. int MinCompare = AMinVal.sub(BMinVal).sgn();
  539. if (MinCompare != 0)
  540. return MinCompare;
  541. }
  542. // If all the dimensions' lower bounds are equal or incomparable, sort based
  543. // on the number of dimensions.
  544. return ALen - BLen;
  545. }
  546. /// Compare the sets @p A and @p B according to their nested space structure.
  547. /// Returns 0 if the structure is considered equal.
  548. /// If @p ConsiderTupleLen is false, the number of dimensions in a tuple are
  549. /// ignored, i.e. a tuple with the same name but different number of dimensions
  550. /// are considered equal.
  551. static int structureCompare(const isl::space &ASpace, const isl::space &BSpace,
  552. bool ConsiderTupleLen) {
  553. int WrappingCompare = bool(ASpace.is_wrapping()) - bool(BSpace.is_wrapping());
  554. if (WrappingCompare != 0)
  555. return WrappingCompare;
  556. if (ASpace.is_wrapping() && BSpace.is_wrapping()) {
  557. isl::space AMap = ASpace.unwrap();
  558. isl::space BMap = BSpace.unwrap();
  559. int FirstResult =
  560. structureCompare(AMap.domain(), BMap.domain(), ConsiderTupleLen);
  561. if (FirstResult != 0)
  562. return FirstResult;
  563. return structureCompare(AMap.range(), BMap.range(), ConsiderTupleLen);
  564. }
  565. std::string AName;
  566. if (!ASpace.is_params() && ASpace.has_tuple_name(isl::dim::set))
  567. AName = ASpace.get_tuple_name(isl::dim::set);
  568. std::string BName;
  569. if (!BSpace.is_params() && BSpace.has_tuple_name(isl::dim::set))
  570. BName = BSpace.get_tuple_name(isl::dim::set);
  571. int NameCompare = AName.compare(BName);
  572. if (NameCompare != 0)
  573. return NameCompare;
  574. if (ConsiderTupleLen) {
  575. int LenCompare = (int)unsignedFromIslSize(BSpace.dim(isl::dim::set)) -
  576. (int)unsignedFromIslSize(ASpace.dim(isl::dim::set));
  577. if (LenCompare != 0)
  578. return LenCompare;
  579. }
  580. return 0;
  581. }
  582. /// Compare the sets @p A and @p B according to their nested space structure. If
  583. /// the structure is the same, sort using the dimension lower bounds.
  584. /// Returns an std::sort compatible bool.
  585. static bool orderComparer(const isl::basic_set &A, const isl::basic_set &B) {
  586. isl::space ASpace = A.get_space();
  587. isl::space BSpace = B.get_space();
  588. // Ignoring number of dimensions first ensures that structures with same tuple
  589. // names, but different number of dimensions are still sorted close together.
  590. int TupleNestingCompare = structureCompare(ASpace, BSpace, false);
  591. if (TupleNestingCompare != 0)
  592. return TupleNestingCompare < 0;
  593. int TupleCompare = structureCompare(ASpace, BSpace, true);
  594. if (TupleCompare != 0)
  595. return TupleCompare < 0;
  596. return flatCompare(A, B) < 0;
  597. }
  598. /// Print a string representation of @p USet to @p OS.
  599. ///
  600. /// The pieces of @p USet are printed in a sorted order. Spaces with equal or
  601. /// similar nesting structure are printed together. Compared to isl's own
  602. /// printing function the uses the structure itself as base of the sorting, not
  603. /// a hash of it. It ensures that e.g. maps spaces with same domain structure
  604. /// are printed together. Set pieces with same structure are printed in order of
  605. /// their lower bounds.
  606. ///
  607. /// @param USet Polyhedra to print.
  608. /// @param OS Target stream.
  609. /// @param Simplify Whether to simplify the polyhedron before printing.
  610. /// @param IsMap Whether @p USet is a wrapped map. If true, sets are
  611. /// unwrapped before printing to again appear as a map.
  612. static void printSortedPolyhedra(isl::union_set USet, llvm::raw_ostream &OS,
  613. bool Simplify, bool IsMap) {
  614. if (USet.is_null()) {
  615. OS << "<null>\n";
  616. return;
  617. }
  618. if (Simplify)
  619. simplify(USet);
  620. // Get all the polyhedra.
  621. std::vector<isl::basic_set> BSets;
  622. for (isl::set Set : USet.get_set_list()) {
  623. for (isl::basic_set BSet : Set.get_basic_set_list()) {
  624. BSets.push_back(BSet);
  625. }
  626. }
  627. if (BSets.empty()) {
  628. OS << "{\n}\n";
  629. return;
  630. }
  631. // Sort the polyhedra.
  632. llvm::sort(BSets, orderComparer);
  633. // Print the polyhedra.
  634. bool First = true;
  635. for (const isl::basic_set &BSet : BSets) {
  636. std::string Str;
  637. if (IsMap)
  638. Str = stringFromIslObj(isl::map(BSet.unwrap()));
  639. else
  640. Str = stringFromIslObj(isl::set(BSet));
  641. size_t OpenPos = Str.find_first_of('{');
  642. assert(OpenPos != std::string::npos);
  643. size_t ClosePos = Str.find_last_of('}');
  644. assert(ClosePos != std::string::npos);
  645. if (First)
  646. OS << llvm::StringRef(Str).substr(0, OpenPos + 1) << "\n ";
  647. else
  648. OS << ";\n ";
  649. OS << llvm::StringRef(Str).substr(OpenPos + 1, ClosePos - OpenPos - 2);
  650. First = false;
  651. }
  652. assert(!First);
  653. OS << "\n}\n";
  654. }
  655. static void recursiveExpand(isl::basic_set BSet, unsigned Dim,
  656. isl::set &Expanded) {
  657. unsigned Dims = unsignedFromIslSize(BSet.dim(isl::dim::set));
  658. if (Dim >= Dims) {
  659. Expanded = Expanded.unite(BSet);
  660. return;
  661. }
  662. isl::basic_set DimOnly =
  663. BSet.project_out(isl::dim::param, 0,
  664. unsignedFromIslSize(BSet.dim(isl::dim::param)))
  665. .project_out(isl::dim::set, Dim + 1, Dims - Dim - 1)
  666. .project_out(isl::dim::set, 0, Dim);
  667. if (!DimOnly.is_bounded()) {
  668. recursiveExpand(BSet, Dim + 1, Expanded);
  669. return;
  670. }
  671. foreachPoint(DimOnly, [&, Dim](isl::point P) {
  672. isl::val Val = P.get_coordinate_val(isl::dim::set, 0);
  673. isl::basic_set FixBSet = BSet.fix_val(isl::dim::set, Dim, Val);
  674. recursiveExpand(FixBSet, Dim + 1, Expanded);
  675. });
  676. }
  677. /// Make each point of a set explicit.
  678. ///
  679. /// "Expanding" makes each point a set contains explicit. That is, the result is
  680. /// a set of singleton polyhedra. Unbounded dimensions are not expanded.
  681. ///
  682. /// Example:
  683. /// { [i] : 0 <= i < 2 }
  684. /// is expanded to:
  685. /// { [0]; [1] }
  686. static isl::set expand(const isl::set &Set) {
  687. isl::set Expanded = isl::set::empty(Set.get_space());
  688. for (isl::basic_set BSet : Set.get_basic_set_list())
  689. recursiveExpand(BSet, 0, Expanded);
  690. return Expanded;
  691. }
  692. /// Expand all points of a union set explicit.
  693. ///
  694. /// @see expand(const isl::set)
  695. static isl::union_set expand(const isl::union_set &USet) {
  696. isl::union_set Expanded = isl::union_set::empty(USet.ctx());
  697. for (isl::set Set : USet.get_set_list()) {
  698. isl::set SetExpanded = expand(Set);
  699. Expanded = Expanded.unite(SetExpanded);
  700. }
  701. return Expanded;
  702. }
  703. LLVM_DUMP_METHOD void polly::dumpPw(const isl::set &Set) {
  704. printSortedPolyhedra(Set, llvm::errs(), true, false);
  705. }
  706. LLVM_DUMP_METHOD void polly::dumpPw(const isl::map &Map) {
  707. printSortedPolyhedra(Map.wrap(), llvm::errs(), true, true);
  708. }
  709. LLVM_DUMP_METHOD void polly::dumpPw(const isl::union_set &USet) {
  710. printSortedPolyhedra(USet, llvm::errs(), true, false);
  711. }
  712. LLVM_DUMP_METHOD void polly::dumpPw(const isl::union_map &UMap) {
  713. printSortedPolyhedra(UMap.wrap(), llvm::errs(), true, true);
  714. }
  715. LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_set *Set) {
  716. dumpPw(isl::manage_copy(Set));
  717. }
  718. LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_map *Map) {
  719. dumpPw(isl::manage_copy(Map));
  720. }
  721. LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_union_set *USet) {
  722. dumpPw(isl::manage_copy(USet));
  723. }
  724. LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_union_map *UMap) {
  725. dumpPw(isl::manage_copy(UMap));
  726. }
  727. LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::set &Set) {
  728. printSortedPolyhedra(expand(Set), llvm::errs(), false, false);
  729. }
  730. LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::map &Map) {
  731. printSortedPolyhedra(expand(Map.wrap()), llvm::errs(), false, true);
  732. }
  733. LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::union_set &USet) {
  734. printSortedPolyhedra(expand(USet), llvm::errs(), false, false);
  735. }
  736. LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::union_map &UMap) {
  737. printSortedPolyhedra(expand(UMap.wrap()), llvm::errs(), false, true);
  738. }
  739. LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_set *Set) {
  740. dumpExpanded(isl::manage_copy(Set));
  741. }
  742. LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_map *Map) {
  743. dumpExpanded(isl::manage_copy(Map));
  744. }
  745. LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_union_set *USet) {
  746. dumpExpanded(isl::manage_copy(USet));
  747. }
  748. LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_union_map *UMap) {
  749. dumpExpanded(isl::manage_copy(UMap));
  750. }
  751. #endif