Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 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 | 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. |
||
| 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: |
||
| 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(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. |
||
| 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 | |||
| 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. |
||
| 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) |
||
| 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. |
||
| 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 |