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
23namespace 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.
86inline isl::val valFromAPInt(isl_ctx *Ctx, const llvm::APInt Int,
87 bool IsSigned) {
88 return isl::manage(ptr: 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.
118llvm::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.
147inline llvm::APInt APIntFromVal(isl::val V) {
148 return APIntFromVal(Val: 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
164ISL_OBJECT_TO_STRING(aff)
165ISL_OBJECT_TO_STRING(ast_expr)
166ISL_OBJECT_TO_STRING(ast_node)
167ISL_OBJECT_TO_STRING(basic_map)
168ISL_OBJECT_TO_STRING(basic_set)
169ISL_OBJECT_TO_STRING(map)
170ISL_OBJECT_TO_STRING(set)
171ISL_OBJECT_TO_STRING(id)
172ISL_OBJECT_TO_STRING(multi_aff)
173ISL_OBJECT_TO_STRING(multi_pw_aff)
174ISL_OBJECT_TO_STRING(multi_union_pw_aff)
175ISL_OBJECT_TO_STRING(point)
176ISL_OBJECT_TO_STRING(pw_aff)
177ISL_OBJECT_TO_STRING(pw_multi_aff)
178ISL_OBJECT_TO_STRING(schedule)
179ISL_OBJECT_TO_STRING(schedule_node)
180ISL_OBJECT_TO_STRING(space)
181ISL_OBJECT_TO_STRING(union_access_info)
182ISL_OBJECT_TO_STRING(union_flow)
183ISL_OBJECT_TO_STRING(union_set)
184ISL_OBJECT_TO_STRING(union_map)
185ISL_OBJECT_TO_STRING(union_pw_aff)
186ISL_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
197ISL_DUMP_OBJECT(aff)
198ISL_DUMP_OBJECT(aff_list)
199ISL_DUMP_OBJECT(ast_expr)
200ISL_DUMP_OBJECT(ast_node)
201ISL_DUMP_OBJECT(ast_node_list)
202ISL_DUMP_OBJECT(basic_map)
203ISL_DUMP_OBJECT(basic_map_list)
204ISL_DUMP_OBJECT(basic_set)
205ISL_DUMP_OBJECT(basic_set_list)
206ISL_DUMP_OBJECT(constraint)
207ISL_DUMP_OBJECT(id)
208ISL_DUMP_OBJECT(id_list)
209ISL_DUMP_OBJECT(id_to_ast_expr)
210ISL_DUMP_OBJECT(local_space)
211ISL_DUMP_OBJECT(map)
212ISL_DUMP_OBJECT(map_list)
213ISL_DUMP_OBJECT(multi_aff)
214ISL_DUMP_OBJECT(multi_pw_aff)
215ISL_DUMP_OBJECT(multi_union_pw_aff)
216ISL_DUMP_OBJECT(multi_val)
217ISL_DUMP_OBJECT(point)
218ISL_DUMP_OBJECT(pw_aff)
219ISL_DUMP_OBJECT(pw_aff_list)
220ISL_DUMP_OBJECT(pw_multi_aff)
221ISL_DUMP_OBJECT(schedule)
222ISL_DUMP_OBJECT(schedule_constraints)
223ISL_DUMP_OBJECT(schedule_node)
224ISL_DUMP_OBJECT(set)
225ISL_DUMP_OBJECT(set_list)
226ISL_DUMP_OBJECT(space)
227ISL_DUMP_OBJECT(union_map)
228ISL_DUMP_OBJECT(union_pw_aff)
229ISL_DUMP_OBJECT(union_pw_aff_list)
230ISL_DUMP_OBJECT(union_pw_multi_aff)
231ISL_DUMP_OBJECT(union_set)
232ISL_DUMP_OBJECT(union_set_list)
233ISL_DUMP_OBJECT(val)
234ISL_DUMP_OBJECT(val_list)
235//@}
236
237/// Emit the equivaltent of the isl_*_dump output into a raw_ostream.
238/// @{
239void dumpIslObj(const isl::schedule_node &Node, llvm::raw_ostream &OS);
240void dumpIslObj(__isl_keep isl_schedule_node *node, llvm::raw_ostream &OS);
241/// @}
242#endif
243
244inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
245 __isl_keep isl_union_map *Map) {
246 OS << polly::stringFromIslObj(Obj: Map, DefaultValue: "null");
247 return OS;
248}
249
250inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
251 __isl_keep isl_map *Map) {
252 OS << polly::stringFromIslObj(Obj: Map, DefaultValue: "null");
253 return OS;
254}
255
256inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
257 __isl_keep isl_set *Set) {
258 OS << polly::stringFromIslObj(Obj: Set, DefaultValue: "null");
259 return OS;
260}
261
262inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
263 __isl_keep isl_pw_aff *Map) {
264 OS << polly::stringFromIslObj(Obj: Map, DefaultValue: "null");
265 return OS;
266}
267
268inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
269 __isl_keep isl_pw_multi_aff *PMA) {
270 OS << polly::stringFromIslObj(Obj: PMA, DefaultValue: "null");
271 return OS;
272}
273
274inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
275 __isl_keep isl_multi_aff *MA) {
276 OS << polly::stringFromIslObj(Obj: MA, DefaultValue: "null");
277 return OS;
278}
279
280inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
281 __isl_keep isl_union_pw_multi_aff *UPMA) {
282 OS << polly::stringFromIslObj(Obj: UPMA, DefaultValue: "null");
283 return OS;
284}
285
286inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
287 __isl_keep isl_schedule *Schedule) {
288 OS << polly::stringFromIslObj(Obj: Schedule, DefaultValue: "null");
289 return OS;
290}
291
292inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
293 __isl_keep isl_space *Space) {
294 OS << polly::stringFromIslObj(Obj: Space, DefaultValue: "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.
312std::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.
331std::string getIslCompatibleName(const std::string &Prefix,
332 const std::string &Middle, long Number,
333 const std::string &Suffix,
334 bool UseInstructionNames);
335
336std::string getIslCompatibleName(const std::string &Prefix,
337 const std::string &Middle,
338 const std::string &Suffix);
339
340inline llvm::DiagnosticInfoOptimizationBase &
341operator<<(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.
357class IslQuotaScope final {
358 isl_ctx *IslCtx;
359 int OldOnError;
360
361public:
362 IslQuotaScope() : IslCtx(nullptr) {}
363 IslQuotaScope(const IslQuotaScope &) = delete;
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(a&: this->IslCtx, b&: Other.IslCtx);
370 std::swap(a&: this->OldOnError, b&: Other.OldOnError);
371 return *this;
372 }
373
374 /// Enter a quota-aware scope.
375 ///
376 /// Should not be used directly. Use IslMaxOperationsGuard::enter() instead.
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(ctx: IslCtx);
387 isl_options_set_on_error(ctx: IslCtx, ISL_ON_ERROR_CONTINUE);
388 isl_ctx_reset_error(ctx: IslCtx);
389 isl_ctx_set_max_operations(ctx: IslCtx, max_operations: LocalMaxOps);
390 }
391
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(ctx: IslCtx, max_operations: 0);
400 isl_options_set_on_error(ctx: IslCtx, val: OldOnError);
401 }
402
403 /// Return whether the current quota has exceeded.
404 bool hasQuotaExceeded() const {
405 if (!IslCtx)
406 return false;
407
408 return isl_ctx_last_error(ctx: 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.
424class IslMaxOperationsGuard final {
425private:
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
438public:
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)
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(ctx: 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(ctx: IslCtx);
469 TopLevelScope = enter(AllowReturnNull: 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.
483 bool hasQuotaExceeded() const {
484 if (!IslCtx)
485 return false;
486
487 return isl_ctx_last_error(ctx: IslCtx) == isl_error_quota;
488 }
489};
490} // end namespace polly
491
492#endif
493

source code of polly/include/polly/Support/GICHelper.h