/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/include/polly/Support/GICHelper.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===- Support/GICHelper.h -- Helper functions for ISL --------------------===// |
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 | | // Helper functions for isl objects. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | // |
13 | | #ifndef POLLY_SUPPORT_GIC_HELPER_H |
14 | | #define POLLY_SUPPORT_GIC_HELPER_H |
15 | | |
16 | | #include "llvm/ADT/APInt.h" |
17 | | #include "llvm/IR/DiagnosticInfo.h" |
18 | | #include "llvm/Support/raw_ostream.h" |
19 | | #include "isl/ctx.h" |
20 | | #include "isl/isl-noexceptions.h" |
21 | | #include "isl/options.h" |
22 | | |
23 | | namespace polly { |
24 | | |
25 | | /// Translate an llvm::APInt to an isl_val. |
26 | | /// |
27 | | /// Translate the bitsequence without sign information as provided by APInt into |
28 | | /// a signed isl_val type. Depending on the value of @p IsSigned @p Int is |
29 | | /// interpreted as unsigned value or as signed value in two's complement |
30 | | /// representation. |
31 | | /// |
32 | | /// Input IsSigned Output |
33 | | /// |
34 | | /// 0 0 -> 0 |
35 | | /// 1 0 -> 1 |
36 | | /// 00 0 -> 0 |
37 | | /// 01 0 -> 1 |
38 | | /// 10 0 -> 2 |
39 | | /// 11 0 -> 3 |
40 | | /// |
41 | | /// 0 1 -> 0 |
42 | | /// 1 1 -> -1 |
43 | | /// 00 1 -> 0 |
44 | | /// 01 1 -> 1 |
45 | | /// 10 1 -> -2 |
46 | | /// 11 1 -> -1 |
47 | | /// |
48 | | /// @param Ctx The isl_ctx to create the isl_val in. |
49 | | /// @param Int The integer value to translate. |
50 | | /// @param IsSigned If the APInt should be interpreted as signed or unsigned |
51 | | /// value. |
52 | | /// |
53 | | /// @return The isl_val corresponding to @p Int. |
54 | | __isl_give isl_val *isl_valFromAPInt(isl_ctx *Ctx, const llvm::APInt Int, |
55 | | bool IsSigned); |
56 | | |
57 | | /// Translate an llvm::APInt to an isl::val. |
58 | | /// |
59 | | /// Translate the bitsequence without sign information as provided by APInt into |
60 | | /// a signed isl::val type. Depending on the value of @p IsSigned @p Int is |
61 | | /// interpreted as unsigned value or as signed value in two's complement |
62 | | /// representation. |
63 | | /// |
64 | | /// Input IsSigned Output |
65 | | /// |
66 | | /// 0 0 -> 0 |
67 | | /// 1 0 -> 1 |
68 | | /// 00 0 -> 0 |
69 | | /// 01 0 -> 1 |
70 | | /// 10 0 -> 2 |
71 | | /// 11 0 -> 3 |
72 | | /// |
73 | | /// 0 1 -> 0 |
74 | | /// 1 1 -> -1 |
75 | | /// 00 1 -> 0 |
76 | | /// 01 1 -> 1 |
77 | | /// 10 1 -> -2 |
78 | | /// 11 1 -> -1 |
79 | | /// |
80 | | /// @param Ctx The isl_ctx to create the isl::val in. |
81 | | /// @param Int The integer value to translate. |
82 | | /// @param IsSigned If the APInt should be interpreted as signed or unsigned |
83 | | /// value. |
84 | | /// |
85 | | /// @return The isl::val corresponding to @p Int. |
86 | | inline isl::val valFromAPInt(isl_ctx *Ctx, const llvm::APInt Int, |
87 | 2.48k | bool IsSigned) { |
88 | 2.48k | return isl::manage(isl_valFromAPInt(Ctx, Int, IsSigned)); |
89 | 2.48k | } |
90 | | |
91 | | /// Translate isl_val to llvm::APInt. |
92 | | /// |
93 | | /// This function can only be called on isl_val values which are integers. |
94 | | /// Calling this function with a non-integral rational, NaN or infinity value |
95 | | /// is not allowed. |
96 | | /// |
97 | | /// As the input isl_val may be negative, the APInt that this function returns |
98 | | /// must always be interpreted as signed two's complement value. The bitwidth of |
99 | | /// the generated APInt is always the minimal bitwidth necessary to model the |
100 | | /// provided integer when interpreting the bit pattern as signed value. |
101 | | /// |
102 | | /// Some example conversions are: |
103 | | /// |
104 | | /// Input Bits Signed Bitwidth |
105 | | /// 0 -> 0 0 1 |
106 | | /// -1 -> 1 -1 1 |
107 | | /// 1 -> 01 1 2 |
108 | | /// -2 -> 10 -2 2 |
109 | | /// 2 -> 010 2 3 |
110 | | /// -3 -> 101 -3 3 |
111 | | /// 3 -> 011 3 3 |
112 | | /// -4 -> 100 -4 3 |
113 | | /// 4 -> 0100 4 4 |
114 | | /// |
115 | | /// @param Val The isl val to translate. |
116 | | /// |
117 | | /// @return The APInt value corresponding to @p Val. |
118 | | llvm::APInt APIntFromVal(__isl_take isl_val *Val); |
119 | | |
120 | | /// Translate isl::val to llvm::APInt. |
121 | | /// |
122 | | /// This function can only be called on isl::val values which are integers. |
123 | | /// Calling this function with a non-integral rational, NaN or infinity value |
124 | | /// is not allowed. |
125 | | /// |
126 | | /// As the input isl::val may be negative, the APInt that this function returns |
127 | | /// must always be interpreted as signed two's complement value. The bitwidth of |
128 | | /// the generated APInt is always the minimal bitwidth necessary to model the |
129 | | /// provided integer when interpreting the bit pattern as signed value. |
130 | | /// |
131 | | /// Some example conversions are: |
132 | | /// |
133 | | /// Input Bits Signed Bitwidth |
134 | | /// 0 -> 0 0 1 |
135 | | /// -1 -> 1 -1 1 |
136 | | /// 1 -> 01 1 2 |
137 | | /// -2 -> 10 -2 2 |
138 | | /// 2 -> 010 2 3 |
139 | | /// -3 -> 101 -3 3 |
140 | | /// 3 -> 011 3 3 |
141 | | /// -4 -> 100 -4 3 |
142 | | /// 4 -> 0100 4 4 |
143 | | /// |
144 | | /// @param Val The isl val to translate. |
145 | | /// |
146 | | /// @return The APInt value corresponding to @p Val. |
147 | 946 | inline llvm::APInt APIntFromVal(isl::val V) { |
148 | 946 | return APIntFromVal(V.release()); |
149 | 946 | } |
150 | | |
151 | | /// Get c++ string from Isl objects. |
152 | | //@{ |
153 | | std::string stringFromIslObj(__isl_keep isl_map *map); |
154 | | std::string stringFromIslObj(__isl_keep isl_union_map *umap); |
155 | | std::string stringFromIslObj(__isl_keep isl_set *set); |
156 | | std::string stringFromIslObj(__isl_keep isl_union_set *uset); |
157 | | std::string stringFromIslObj(__isl_keep isl_schedule *schedule); |
158 | | std::string stringFromIslObj(__isl_keep isl_multi_aff *maff); |
159 | | std::string stringFromIslObj(__isl_keep isl_pw_multi_aff *pma); |
160 | | std::string stringFromIslObj(__isl_keep isl_multi_pw_aff *mpa); |
161 | | std::string stringFromIslObj(__isl_keep isl_union_pw_multi_aff *upma); |
162 | | std::string stringFromIslObj(__isl_keep isl_aff *aff); |
163 | | std::string stringFromIslObj(__isl_keep isl_pw_aff *pwaff); |
164 | | std::string stringFromIslObj(__isl_keep isl_space *space); |
165 | | //@} |
166 | | |
167 | | inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
168 | 261 | __isl_keep isl_union_map *Map) { |
169 | 261 | OS << polly::stringFromIslObj(Map); |
170 | 261 | return OS; |
171 | 261 | } |
172 | | |
173 | | inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
174 | 0 | __isl_keep isl_map *Map) { |
175 | 0 | OS << polly::stringFromIslObj(Map); |
176 | 0 | return OS; |
177 | 0 | } |
178 | | |
179 | | inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
180 | 0 | __isl_keep isl_set *Set) { |
181 | 0 | OS << polly::stringFromIslObj(Set); |
182 | 0 | return OS; |
183 | 0 | } |
184 | | |
185 | | inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
186 | 0 | __isl_keep isl_pw_aff *Map) { |
187 | 0 | OS << polly::stringFromIslObj(Map); |
188 | 0 | return OS; |
189 | 0 | } |
190 | | |
191 | | inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
192 | 0 | __isl_keep isl_pw_multi_aff *PMA) { |
193 | 0 | OS << polly::stringFromIslObj(PMA); |
194 | 0 | return OS; |
195 | 0 | } |
196 | | |
197 | | inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
198 | 0 | __isl_keep isl_multi_aff *MA) { |
199 | 0 | OS << polly::stringFromIslObj(MA); |
200 | 0 | return OS; |
201 | 0 | } |
202 | | |
203 | | inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
204 | 0 | __isl_keep isl_union_pw_multi_aff *UPMA) { |
205 | 0 | OS << polly::stringFromIslObj(UPMA); |
206 | 0 | return OS; |
207 | 0 | } |
208 | | |
209 | | inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
210 | 0 | __isl_keep isl_schedule *Schedule) { |
211 | 0 | OS << polly::stringFromIslObj(Schedule); |
212 | 0 | return OS; |
213 | 0 | } |
214 | | |
215 | | inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
216 | 0 | __isl_keep isl_space *Space) { |
217 | 0 | OS << polly::stringFromIslObj(Space); |
218 | 0 | return OS; |
219 | 0 | } |
220 | | |
221 | | /// Combine Prefix, Val (or Number) and Suffix to an isl-compatible name. |
222 | | /// |
223 | | /// In case @p UseInstructionNames is set, this function returns: |
224 | | /// |
225 | | /// @p Prefix + "_" + @p Val->getName() + @p Suffix |
226 | | /// |
227 | | /// otherwise |
228 | | /// |
229 | | /// @p Prefix + to_string(Number) + @p Suffix |
230 | | /// |
231 | | /// We ignore the value names by default, as they may change between release |
232 | | /// and debug mode and can consequently not be used when aiming for reproducible |
233 | | /// builds. However, for debugging named statements are often helpful, hence |
234 | | /// we allow their optional use. |
235 | | std::string getIslCompatibleName(const std::string &Prefix, |
236 | | const llvm::Value *Val, long Number, |
237 | | const std::string &Suffix, |
238 | | bool UseInstructionNames); |
239 | | |
240 | | /// Combine Prefix, Name (or Number) and Suffix to an isl-compatible name. |
241 | | /// |
242 | | /// In case @p UseInstructionNames is set, this function returns: |
243 | | /// |
244 | | /// @p Prefix + "_" + Name + @p Suffix |
245 | | /// |
246 | | /// otherwise |
247 | | /// |
248 | | /// @p Prefix + to_string(Number) + @p Suffix |
249 | | /// |
250 | | /// We ignore @p Name by default, as they may change between release |
251 | | /// and debug mode and can consequently not be used when aiming for reproducible |
252 | | /// builds. However, for debugging named statements are often helpful, hence |
253 | | /// we allow their optional use. |
254 | | std::string getIslCompatibleName(const std::string &Prefix, |
255 | | const std::string &Middle, long Number, |
256 | | const std::string &Suffix, |
257 | | bool UseInstructionNames); |
258 | | |
259 | | std::string getIslCompatibleName(const std::string &Prefix, |
260 | | const std::string &Middle, |
261 | | const std::string &Suffix); |
262 | | |
263 | | inline llvm::DiagnosticInfoOptimizationBase & |
264 | | operator<<(llvm::DiagnosticInfoOptimizationBase &OS, |
265 | 6 | const isl::union_map &Obj) { |
266 | 6 | OS << Obj.to_str(); |
267 | 6 | return OS; |
268 | 6 | } |
269 | | |
270 | | /// Scope guard for code that allows arbitrary isl function to return an error |
271 | | /// if the max-operations quota exceeds. |
272 | | /// |
273 | | /// This allows to opt-in code sections that have known long executions times. |
274 | | /// code not in a hot path can continue to assume that no unexpected error |
275 | | /// occurs. |
276 | | /// |
277 | | /// This is typically used inside a nested IslMaxOperationsGuard scope. The |
278 | | /// IslMaxOperationsGuard defines the number of allowed base operations for some |
279 | | /// code, IslQuotaScope defines where it is allowed to return an error result. |
280 | | class IslQuotaScope { |
281 | | isl_ctx *IslCtx; |
282 | | int OldOnError; |
283 | | |
284 | | public: |
285 | 1.13k | IslQuotaScope() : IslCtx(nullptr) {} |
286 | | IslQuotaScope(const IslQuotaScope &) = delete; |
287 | | IslQuotaScope(IslQuotaScope &&Other) |
288 | 0 | : IslCtx(Other.IslCtx), OldOnError(Other.OldOnError) { |
289 | 0 | Other.IslCtx = nullptr; |
290 | 0 | } |
291 | 1.07k | const IslQuotaScope &operator=(IslQuotaScope &&Other) { |
292 | 1.07k | std::swap(this->IslCtx, Other.IslCtx); |
293 | 1.07k | std::swap(this->OldOnError, Other.OldOnError); |
294 | 1.07k | return *this; |
295 | 1.07k | } |
296 | | |
297 | | /// Enter a quota-aware scope. |
298 | | /// |
299 | | /// Should not be used directly. Use IslMaxOperationsGuard::enter() instead. |
300 | | explicit IslQuotaScope(isl_ctx *IslCtx, unsigned long LocalMaxOps) |
301 | 1.11k | : IslCtx(IslCtx) { |
302 | 1.11k | assert(IslCtx); |
303 | 1.11k | assert(isl_ctx_get_max_operations(IslCtx) == 0 && "Incorrect nesting"); |
304 | 1.11k | if (LocalMaxOps == 0) { |
305 | 0 | this->IslCtx = nullptr; |
306 | 0 | return; |
307 | 0 | } |
308 | 1.11k | |
309 | 1.11k | OldOnError = isl_options_get_on_error(IslCtx); |
310 | 1.11k | isl_options_set_on_error(IslCtx, ISL_ON_ERROR_CONTINUE); |
311 | 1.11k | isl_ctx_reset_error(IslCtx); |
312 | 1.11k | isl_ctx_set_max_operations(IslCtx, LocalMaxOps); |
313 | 1.11k | } |
314 | | |
315 | 2.25k | ~IslQuotaScope() { |
316 | 2.25k | if (!IslCtx) |
317 | 1.13k | return; |
318 | 1.11k | |
319 | 1.11k | assert(isl_ctx_get_max_operations(IslCtx) > 0 && "Incorrect nesting"); |
320 | 1.11k | assert(isl_options_get_on_error(IslCtx) == ISL_ON_ERROR_CONTINUE && |
321 | 1.11k | "Incorrect nesting"); |
322 | 1.11k | isl_ctx_set_max_operations(IslCtx, 0); |
323 | 1.11k | isl_options_set_on_error(IslCtx, OldOnError); |
324 | 1.11k | } |
325 | | |
326 | | /// Return whether the current quota has exceeded. |
327 | 0 | bool hasQuotaExceeded() const { |
328 | 0 | if (!IslCtx) |
329 | 0 | return false; |
330 | 0 |
|
331 | 0 | return isl_ctx_last_error(IslCtx) == isl_error_quota; |
332 | 0 | } |
333 | | }; |
334 | | |
335 | | /// Scoped limit of ISL operations. |
336 | | /// |
337 | | /// Limits the number of ISL operations during the lifetime of this object. The |
338 | | /// idea is to use this as an RAII guard for the scope where the code is aware |
339 | | /// that ISL can return errors even when all input is valid. After leaving the |
340 | | /// scope, it will return to the error setting as it was before. That also means |
341 | | /// that the error setting should not be changed while in that scope. |
342 | | /// |
343 | | /// Such scopes are not allowed to be nested because the previous operations |
344 | | /// counter cannot be reset to the previous state, or one that adds the |
345 | | /// operations while being in the nested scope. Use therefore is only allowed |
346 | | /// while currently a no operations-limit is active. |
347 | | class IslMaxOperationsGuard { |
348 | | private: |
349 | | /// The ISL context to set the operations limit. |
350 | | /// |
351 | | /// If set to nullptr, there is no need for any action at the end of the |
352 | | /// scope. |
353 | | isl_ctx *IslCtx; |
354 | | |
355 | | /// Maximum number of operations for the scope. |
356 | | unsigned long LocalMaxOps; |
357 | | |
358 | | /// When AutoEnter is enabled, holds the IslQuotaScope object. |
359 | | IslQuotaScope TopLevelScope; |
360 | | |
361 | | public: |
362 | | /// Enter a max operations scope. |
363 | | /// |
364 | | /// @param IslCtx The ISL context to set the operations limit for. |
365 | | /// @param LocalMaxOps Maximum number of operations allowed in the |
366 | | /// scope. If set to zero, no operations limit is enforced. |
367 | | /// @param AutoEnter If true, automatically enters an IslQuotaScope such |
368 | | /// that isl operations may return quota errors |
369 | | /// immediately. If false, only starts the operations |
370 | | /// counter, but isl does not return quota errors before |
371 | | /// calling enter(). |
372 | | IslMaxOperationsGuard(isl_ctx *IslCtx, unsigned long LocalMaxOps, |
373 | | bool AutoEnter = true) |
374 | 1.07k | : IslCtx(IslCtx), LocalMaxOps(LocalMaxOps) { |
375 | 1.07k | assert(IslCtx); |
376 | 1.07k | assert(isl_ctx_get_max_operations(IslCtx) == 0 && |
377 | 1.07k | "Nested max operations not supported"); |
378 | 1.07k | |
379 | 1.07k | // Users of this guard may check whether the last error was isl_error_quota. |
380 | 1.07k | // Reset the last error such that a previous out-of-quota error is not |
381 | 1.07k | // mistaken to have occurred in the in this quota, even if the max number of |
382 | 1.07k | // operations is set to infinite (LocalMaxOps == 0). |
383 | 1.07k | isl_ctx_reset_error(IslCtx); |
384 | 1.07k | |
385 | 1.07k | if (LocalMaxOps == 0) { |
386 | 1 | // No limit on operations; also disable restoring on_error/max_operations. |
387 | 1 | this->IslCtx = nullptr; |
388 | 1 | return; |
389 | 1 | } |
390 | 1.07k | |
391 | 1.07k | isl_ctx_reset_operations(IslCtx); |
392 | 1.07k | TopLevelScope = enter(AutoEnter); |
393 | 1.07k | } |
394 | | |
395 | | /// Enter a scope that can handle out-of-quota errors. |
396 | | /// |
397 | | /// @param AllowReturnNull Whether the scoped code can handle out-of-quota |
398 | | /// errors. If false, returns a dummy scope object that |
399 | | /// does nothing. |
400 | 1.17k | IslQuotaScope enter(bool AllowReturnNull = true) { |
401 | 1.17k | return AllowReturnNull && IslCtx1.11k ? IslQuotaScope(IslCtx, LocalMaxOps)1.11k |
402 | 1.17k | : IslQuotaScope()62 ; |
403 | 1.17k | } |
404 | | |
405 | | /// Return whether the current quota has exceeded. |
406 | 124 | bool hasQuotaExceeded() const { |
407 | 124 | if (!IslCtx) |
408 | 0 | return false; |
409 | 124 | |
410 | 124 | return isl_ctx_last_error(IslCtx) == isl_error_quota; |
411 | 124 | } |
412 | | }; |
413 | | } // end namespace polly |
414 | | |
415 | | #endif |