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