xref: /llvm-project/polly/include/polly/Support/GICHelper.h (revision bd93df937a6441db4aff67191ca0bb486554c34b)
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.
valFromAPInt(isl_ctx * Ctx,const llvm::APInt Int,bool IsSigned)86 inline isl::val valFromAPInt(isl_ctx *Ctx, const llvm::APInt Int,
87                              bool IsSigned) {
88   return isl::manage(isl_valFromAPInt(Ctx, Int, IsSigned));
89 }
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.
APIntFromVal(isl::val V)147 inline llvm::APInt APIntFromVal(isl::val V) {
148   return APIntFromVal(V.release());
149 }
150 
151 /// Get c++ string from Isl objects.
152 //@{
153 #define ISL_CPP_OBJECT_TO_STRING(name)                                         \
154   inline std::string stringFromIslObj(const name &Obj,                         \
155                                       std::string DefaultValue = "") {         \
156     return stringFromIslObj(Obj.get(), DefaultValue);                          \
157   }
158 
159 #define ISL_OBJECT_TO_STRING(name)                                             \
160   std::string stringFromIslObj(__isl_keep isl_##name *Obj,                     \
161                                std::string DefaultValue = "");                 \
162   ISL_CPP_OBJECT_TO_STRING(isl::name)
163 
164 ISL_OBJECT_TO_STRING(aff)
165 ISL_OBJECT_TO_STRING(ast_expr)
166 ISL_OBJECT_TO_STRING(ast_node)
167 ISL_OBJECT_TO_STRING(basic_map)
168 ISL_OBJECT_TO_STRING(basic_set)
169 ISL_OBJECT_TO_STRING(map)
170 ISL_OBJECT_TO_STRING(set)
171 ISL_OBJECT_TO_STRING(id)
172 ISL_OBJECT_TO_STRING(multi_aff)
173 ISL_OBJECT_TO_STRING(multi_pw_aff)
174 ISL_OBJECT_TO_STRING(multi_union_pw_aff)
175 ISL_OBJECT_TO_STRING(point)
176 ISL_OBJECT_TO_STRING(pw_aff)
177 ISL_OBJECT_TO_STRING(pw_multi_aff)
178 ISL_OBJECT_TO_STRING(schedule)
179 ISL_OBJECT_TO_STRING(schedule_node)
180 ISL_OBJECT_TO_STRING(space)
181 ISL_OBJECT_TO_STRING(union_access_info)
182 ISL_OBJECT_TO_STRING(union_flow)
183 ISL_OBJECT_TO_STRING(union_set)
184 ISL_OBJECT_TO_STRING(union_map)
185 ISL_OBJECT_TO_STRING(union_pw_aff)
186 ISL_OBJECT_TO_STRING(union_pw_multi_aff)
187 //@}
188 
189 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
190 /// C++ wrapper for isl_*_dump() functions.
191 //@{
192 
193 #define ISL_DUMP_OBJECT(name)                                                  \
194   void dumpIslObj(const isl::name &Obj);                                       \
195   void dumpIslObj(isl_##name *Obj);
196 
197 ISL_DUMP_OBJECT(aff)
198 ISL_DUMP_OBJECT(aff_list)
199 ISL_DUMP_OBJECT(ast_expr)
200 ISL_DUMP_OBJECT(ast_node)
201 ISL_DUMP_OBJECT(ast_node_list)
202 ISL_DUMP_OBJECT(basic_map)
203 ISL_DUMP_OBJECT(basic_map_list)
204 ISL_DUMP_OBJECT(basic_set)
205 ISL_DUMP_OBJECT(basic_set_list)
206 ISL_DUMP_OBJECT(constraint)
207 ISL_DUMP_OBJECT(id)
208 ISL_DUMP_OBJECT(id_list)
209 ISL_DUMP_OBJECT(id_to_ast_expr)
210 ISL_DUMP_OBJECT(local_space)
211 ISL_DUMP_OBJECT(map)
212 ISL_DUMP_OBJECT(map_list)
213 ISL_DUMP_OBJECT(multi_aff)
214 ISL_DUMP_OBJECT(multi_pw_aff)
215 ISL_DUMP_OBJECT(multi_union_pw_aff)
216 ISL_DUMP_OBJECT(multi_val)
217 ISL_DUMP_OBJECT(point)
218 ISL_DUMP_OBJECT(pw_aff)
219 ISL_DUMP_OBJECT(pw_aff_list)
220 ISL_DUMP_OBJECT(pw_multi_aff)
221 ISL_DUMP_OBJECT(schedule)
222 ISL_DUMP_OBJECT(schedule_constraints)
223 ISL_DUMP_OBJECT(schedule_node)
224 ISL_DUMP_OBJECT(set)
225 ISL_DUMP_OBJECT(set_list)
226 ISL_DUMP_OBJECT(space)
227 ISL_DUMP_OBJECT(union_map)
228 ISL_DUMP_OBJECT(union_pw_aff)
229 ISL_DUMP_OBJECT(union_pw_aff_list)
230 ISL_DUMP_OBJECT(union_pw_multi_aff)
231 ISL_DUMP_OBJECT(union_set)
232 ISL_DUMP_OBJECT(union_set_list)
233 ISL_DUMP_OBJECT(val)
234 ISL_DUMP_OBJECT(val_list)
235 //@}
236 
237 /// Emit the equivaltent of the isl_*_dump output into a raw_ostream.
238 /// @{
239 void dumpIslObj(const isl::schedule_node &Node, llvm::raw_ostream &OS);
240 void dumpIslObj(__isl_keep isl_schedule_node *node, llvm::raw_ostream &OS);
241 /// @}
242 #endif
243 
244 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
245                                      __isl_keep isl_union_map *Map) {
246   OS << polly::stringFromIslObj(Map, "null");
247   return OS;
248 }
249 
250 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
251                                      __isl_keep isl_map *Map) {
252   OS << polly::stringFromIslObj(Map, "null");
253   return OS;
254 }
255 
256 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
257                                      __isl_keep isl_set *Set) {
258   OS << polly::stringFromIslObj(Set, "null");
259   return OS;
260 }
261 
262 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
263                                      __isl_keep isl_pw_aff *Map) {
264   OS << polly::stringFromIslObj(Map, "null");
265   return OS;
266 }
267 
268 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
269                                      __isl_keep isl_pw_multi_aff *PMA) {
270   OS << polly::stringFromIslObj(PMA, "null");
271   return OS;
272 }
273 
274 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
275                                      __isl_keep isl_multi_aff *MA) {
276   OS << polly::stringFromIslObj(MA, "null");
277   return OS;
278 }
279 
280 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
281                                      __isl_keep isl_union_pw_multi_aff *UPMA) {
282   OS << polly::stringFromIslObj(UPMA, "null");
283   return OS;
284 }
285 
286 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
287                                      __isl_keep isl_schedule *Schedule) {
288   OS << polly::stringFromIslObj(Schedule, "null");
289   return OS;
290 }
291 
292 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
293                                      __isl_keep isl_space *Space) {
294   OS << polly::stringFromIslObj(Space, "null");
295   return OS;
296 }
297 
298 /// Combine Prefix, Val (or Number) and Suffix to an isl-compatible name.
299 ///
300 /// In case @p UseInstructionNames is set, this function returns:
301 ///
302 /// @p Prefix + "_" + @p Val->getName() + @p Suffix
303 ///
304 /// otherwise
305 ///
306 /// @p Prefix + to_string(Number) + @p Suffix
307 ///
308 /// We ignore the value names by default, as they may change between release
309 /// and debug mode and can consequently not be used when aiming for reproducible
310 /// builds. However, for debugging named statements are often helpful, hence
311 /// we allow their optional use.
312 std::string getIslCompatibleName(const std::string &Prefix,
313                                  const llvm::Value *Val, long Number,
314                                  const std::string &Suffix,
315                                  bool UseInstructionNames);
316 
317 /// Combine Prefix, Name (or Number) and Suffix to an isl-compatible name.
318 ///
319 /// In case @p UseInstructionNames is set, this function returns:
320 ///
321 /// @p Prefix + "_" + Name + @p Suffix
322 ///
323 /// otherwise
324 ///
325 /// @p Prefix + to_string(Number) + @p Suffix
326 ///
327 /// We ignore @p Name by default, as they may change between release
328 /// and debug mode and can consequently not be used when aiming for reproducible
329 /// builds. However, for debugging named statements are often helpful, hence
330 /// we allow their optional use.
331 std::string getIslCompatibleName(const std::string &Prefix,
332                                  const std::string &Middle, long Number,
333                                  const std::string &Suffix,
334                                  bool UseInstructionNames);
335 
336 std::string getIslCompatibleName(const std::string &Prefix,
337                                  const std::string &Middle,
338                                  const std::string &Suffix);
339 
340 inline llvm::DiagnosticInfoOptimizationBase &
341 operator<<(llvm::DiagnosticInfoOptimizationBase &OS,
342            const isl::union_map &Obj) {
343   OS << stringFromIslObj(Obj);
344   return OS;
345 }
346 
347 /// Scope guard for code that allows arbitrary isl function to return an error
348 /// if the max-operations quota exceeds.
349 ///
350 /// This allows to opt-in code sections that have known long executions times.
351 /// code not in a hot path can continue to assume that no unexpected error
352 /// occurs.
353 ///
354 /// This is typically used inside a nested IslMaxOperationsGuard scope. The
355 /// IslMaxOperationsGuard defines the number of allowed base operations for some
356 /// code, IslQuotaScope defines where it is allowed to return an error result.
357 class IslQuotaScope final {
358   isl_ctx *IslCtx;
359   int OldOnError;
360 
361 public:
IslQuotaScope()362   IslQuotaScope() : IslCtx(nullptr) {}
363   IslQuotaScope(const IslQuotaScope &) = delete;
IslQuotaScope(IslQuotaScope && Other)364   IslQuotaScope(IslQuotaScope &&Other)
365       : IslCtx(Other.IslCtx), OldOnError(Other.OldOnError) {
366     Other.IslCtx = nullptr;
367   }
368   const IslQuotaScope &operator=(IslQuotaScope &&Other) {
369     std::swap(this->IslCtx, Other.IslCtx);
370     std::swap(this->OldOnError, Other.OldOnError);
371     return *this;
372   }
373 
374   /// Enter a quota-aware scope.
375   ///
376   /// Should not be used directly. Use IslMaxOperationsGuard::enter() instead.
IslQuotaScope(isl_ctx * IslCtx,unsigned long LocalMaxOps)377   explicit IslQuotaScope(isl_ctx *IslCtx, unsigned long LocalMaxOps)
378       : IslCtx(IslCtx) {
379     assert(IslCtx);
380     assert(isl_ctx_get_max_operations(IslCtx) == 0 && "Incorrect nesting");
381     if (LocalMaxOps == 0) {
382       this->IslCtx = nullptr;
383       return;
384     }
385 
386     OldOnError = isl_options_get_on_error(IslCtx);
387     isl_options_set_on_error(IslCtx, ISL_ON_ERROR_CONTINUE);
388     isl_ctx_reset_error(IslCtx);
389     isl_ctx_set_max_operations(IslCtx, LocalMaxOps);
390   }
391 
~IslQuotaScope()392   ~IslQuotaScope() {
393     if (!IslCtx)
394       return;
395 
396     assert(isl_ctx_get_max_operations(IslCtx) > 0 && "Incorrect nesting");
397     assert(isl_options_get_on_error(IslCtx) == ISL_ON_ERROR_CONTINUE &&
398            "Incorrect nesting");
399     isl_ctx_set_max_operations(IslCtx, 0);
400     isl_options_set_on_error(IslCtx, OldOnError);
401   }
402 
403   /// Return whether the current quota has exceeded.
hasQuotaExceeded()404   bool hasQuotaExceeded() const {
405     if (!IslCtx)
406       return false;
407 
408     return isl_ctx_last_error(IslCtx) == isl_error_quota;
409   }
410 };
411 
412 /// Scoped limit of ISL operations.
413 ///
414 /// Limits the number of ISL operations during the lifetime of this object. The
415 /// idea is to use this as an RAII guard for the scope where the code is aware
416 /// that ISL can return errors even when all input is valid. After leaving the
417 /// scope, it will return to the error setting as it was before. That also means
418 /// that the error setting should not be changed while in that scope.
419 ///
420 /// Such scopes are not allowed to be nested because the previous operations
421 /// counter cannot be reset to the previous state, or one that adds the
422 /// operations while being in the nested scope. Use therefore is only allowed
423 /// while currently a no operations-limit is active.
424 class IslMaxOperationsGuard final {
425 private:
426   /// The ISL context to set the operations limit.
427   ///
428   /// If set to nullptr, there is no need for any action at the end of the
429   /// scope.
430   isl_ctx *IslCtx;
431 
432   /// Maximum number of operations for the scope.
433   unsigned long LocalMaxOps;
434 
435   /// When AutoEnter is enabled, holds the IslQuotaScope object.
436   IslQuotaScope TopLevelScope;
437 
438 public:
439   /// Enter a max operations scope.
440   ///
441   /// @param IslCtx      The ISL context to set the operations limit for.
442   /// @param LocalMaxOps Maximum number of operations allowed in the
443   ///                    scope. If set to zero, no operations limit is enforced.
444   /// @param AutoEnter   If true, automatically enters an IslQuotaScope such
445   ///                    that isl operations may return quota errors
446   ///                    immediately. If false, only starts the operations
447   ///                    counter, but isl does not return quota errors before
448   ///                    calling enter().
449   IslMaxOperationsGuard(isl_ctx *IslCtx, unsigned long LocalMaxOps,
450                         bool AutoEnter = true)
IslCtx(IslCtx)451       : IslCtx(IslCtx), LocalMaxOps(LocalMaxOps) {
452     assert(IslCtx);
453     assert(isl_ctx_get_max_operations(IslCtx) == 0 &&
454            "Nested max operations not supported");
455 
456     // Users of this guard may check whether the last error was isl_error_quota.
457     // Reset the last error such that a previous out-of-quota error is not
458     // mistaken to have occurred in the in this quota, even if the max number of
459     // operations is set to infinite (LocalMaxOps == 0).
460     isl_ctx_reset_error(IslCtx);
461 
462     if (LocalMaxOps == 0) {
463       // No limit on operations; also disable restoring on_error/max_operations.
464       this->IslCtx = nullptr;
465       return;
466     }
467 
468     isl_ctx_reset_operations(IslCtx);
469     TopLevelScope = enter(AutoEnter);
470   }
471 
472   /// Enter a scope that can handle out-of-quota errors.
473   ///
474   /// @param AllowReturnNull Whether the scoped code can handle out-of-quota
475   ///                        errors. If false, returns a dummy scope object that
476   ///                        does nothing.
477   IslQuotaScope enter(bool AllowReturnNull = true) {
478     return AllowReturnNull && IslCtx ? IslQuotaScope(IslCtx, LocalMaxOps)
479                                      : IslQuotaScope();
480   }
481 
482   /// Return whether the current quota has exceeded.
hasQuotaExceeded()483   bool hasQuotaExceeded() const {
484     if (!IslCtx)
485       return false;
486 
487     return isl_ctx_last_error(IslCtx) == isl_error_quota;
488   }
489 };
490 } // end namespace polly
491 
492 #endif
493