Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:48:20

0001 //===- Support/GICHelper.h -- Helper functions for ISL --------------------===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Helper functions for isl objects.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 //
0013 #ifndef POLLY_SUPPORT_GIC_HELPER_H
0014 #define POLLY_SUPPORT_GIC_HELPER_H
0015 
0016 #include "llvm/ADT/APInt.h"
0017 #include "llvm/IR/DiagnosticInfo.h"
0018 #include "llvm/Support/raw_ostream.h"
0019 #include "isl/ctx.h"
0020 #include "isl/isl-noexceptions.h"
0021 #include "isl/options.h"
0022 
0023 namespace polly {
0024 
0025 /// Translate an llvm::APInt to an isl_val.
0026 ///
0027 /// Translate the bitsequence without sign information as provided by APInt into
0028 /// a signed isl_val type. Depending on the value of @p IsSigned @p Int is
0029 /// interpreted as unsigned value or as signed value in two's complement
0030 /// representation.
0031 ///
0032 /// Input IsSigned                 Output
0033 ///
0034 ///     0        0           ->    0
0035 ///     1        0           ->    1
0036 ///    00        0           ->    0
0037 ///    01        0           ->    1
0038 ///    10        0           ->    2
0039 ///    11        0           ->    3
0040 ///
0041 ///     0        1           ->    0
0042 ///     1        1           ->   -1
0043 ///    00        1           ->    0
0044 ///    01        1           ->    1
0045 ///    10        1           ->   -2
0046 ///    11        1           ->   -1
0047 ///
0048 /// @param Ctx      The isl_ctx to create the isl_val in.
0049 /// @param Int      The integer value to translate.
0050 /// @param IsSigned If the APInt should be interpreted as signed or unsigned
0051 ///                 value.
0052 ///
0053 /// @return The isl_val corresponding to @p Int.
0054 __isl_give isl_val *isl_valFromAPInt(isl_ctx *Ctx, const llvm::APInt Int,
0055                                      bool IsSigned);
0056 
0057 /// Translate an llvm::APInt to an isl::val.
0058 ///
0059 /// Translate the bitsequence without sign information as provided by APInt into
0060 /// a signed isl::val type. Depending on the value of @p IsSigned @p Int is
0061 /// interpreted as unsigned value or as signed value in two's complement
0062 /// representation.
0063 ///
0064 /// Input IsSigned                 Output
0065 ///
0066 ///     0        0           ->    0
0067 ///     1        0           ->    1
0068 ///    00        0           ->    0
0069 ///    01        0           ->    1
0070 ///    10        0           ->    2
0071 ///    11        0           ->    3
0072 ///
0073 ///     0        1           ->    0
0074 ///     1        1           ->   -1
0075 ///    00        1           ->    0
0076 ///    01        1           ->    1
0077 ///    10        1           ->   -2
0078 ///    11        1           ->   -1
0079 ///
0080 /// @param Ctx      The isl_ctx to create the isl::val in.
0081 /// @param Int      The integer value to translate.
0082 /// @param IsSigned If the APInt should be interpreted as signed or unsigned
0083 ///                 value.
0084 ///
0085 /// @return The isl::val corresponding to @p Int.
0086 inline isl::val valFromAPInt(isl_ctx *Ctx, const llvm::APInt Int,
0087                              bool IsSigned) {
0088   return isl::manage(isl_valFromAPInt(Ctx, Int, IsSigned));
0089 }
0090 
0091 /// Translate isl_val to llvm::APInt.
0092 ///
0093 /// This function can only be called on isl_val values which are integers.
0094 /// Calling this function with a non-integral rational, NaN or infinity value
0095 /// is not allowed.
0096 ///
0097 /// As the input isl_val may be negative, the APInt that this function returns
0098 /// must always be interpreted as signed two's complement value. The bitwidth of
0099 /// the generated APInt is always the minimal bitwidth necessary to model the
0100 /// provided integer when interpreting the bit pattern as signed value.
0101 ///
0102 /// Some example conversions are:
0103 ///
0104 ///   Input      Bits    Signed  Bitwidth
0105 ///       0 ->      0         0         1
0106 ///      -1 ->      1        -1         1
0107 ///       1 ->     01         1         2
0108 ///      -2 ->     10        -2         2
0109 ///       2 ->    010         2         3
0110 ///      -3 ->    101        -3         3
0111 ///       3 ->    011         3         3
0112 ///      -4 ->    100        -4         3
0113 ///       4 ->   0100         4         4
0114 ///
0115 /// @param Val The isl val to translate.
0116 ///
0117 /// @return The APInt value corresponding to @p Val.
0118 llvm::APInt APIntFromVal(__isl_take isl_val *Val);
0119 
0120 /// Translate isl::val to llvm::APInt.
0121 ///
0122 /// This function can only be called on isl::val values which are integers.
0123 /// Calling this function with a non-integral rational, NaN or infinity value
0124 /// is not allowed.
0125 ///
0126 /// As the input isl::val may be negative, the APInt that this function returns
0127 /// must always be interpreted as signed two's complement value. The bitwidth of
0128 /// the generated APInt is always the minimal bitwidth necessary to model the
0129 /// provided integer when interpreting the bit pattern as signed value.
0130 ///
0131 /// Some example conversions are:
0132 ///
0133 ///   Input      Bits    Signed  Bitwidth
0134 ///       0 ->      0         0         1
0135 ///      -1 ->      1        -1         1
0136 ///       1 ->     01         1         2
0137 ///      -2 ->     10        -2         2
0138 ///       2 ->    010         2         3
0139 ///      -3 ->    101        -3         3
0140 ///       3 ->    011         3         3
0141 ///      -4 ->    100        -4         3
0142 ///       4 ->   0100         4         4
0143 ///
0144 /// @param Val The isl val to translate.
0145 ///
0146 /// @return The APInt value corresponding to @p Val.
0147 inline llvm::APInt APIntFromVal(isl::val V) {
0148   return APIntFromVal(V.release());
0149 }
0150 
0151 /// Get c++ string from Isl objects.
0152 //@{
0153 #define ISL_CPP_OBJECT_TO_STRING(name)                                         \
0154   inline std::string stringFromIslObj(const name &Obj,                         \
0155                                       std::string DefaultValue = "") {         \
0156     return stringFromIslObj(Obj.get(), DefaultValue);                          \
0157   }
0158 
0159 #define ISL_OBJECT_TO_STRING(name)                                             \
0160   std::string stringFromIslObj(__isl_keep isl_##name *Obj,                     \
0161                                std::string DefaultValue = "");                 \
0162   ISL_CPP_OBJECT_TO_STRING(isl::name)
0163 
0164 ISL_OBJECT_TO_STRING(aff)
0165 ISL_OBJECT_TO_STRING(ast_expr)
0166 ISL_OBJECT_TO_STRING(ast_node)
0167 ISL_OBJECT_TO_STRING(basic_map)
0168 ISL_OBJECT_TO_STRING(basic_set)
0169 ISL_OBJECT_TO_STRING(map)
0170 ISL_OBJECT_TO_STRING(set)
0171 ISL_OBJECT_TO_STRING(id)
0172 ISL_OBJECT_TO_STRING(multi_aff)
0173 ISL_OBJECT_TO_STRING(multi_pw_aff)
0174 ISL_OBJECT_TO_STRING(multi_union_pw_aff)
0175 ISL_OBJECT_TO_STRING(point)
0176 ISL_OBJECT_TO_STRING(pw_aff)
0177 ISL_OBJECT_TO_STRING(pw_multi_aff)
0178 ISL_OBJECT_TO_STRING(schedule)
0179 ISL_OBJECT_TO_STRING(schedule_node)
0180 ISL_OBJECT_TO_STRING(space)
0181 ISL_OBJECT_TO_STRING(union_access_info)
0182 ISL_OBJECT_TO_STRING(union_flow)
0183 ISL_OBJECT_TO_STRING(union_set)
0184 ISL_OBJECT_TO_STRING(union_map)
0185 ISL_OBJECT_TO_STRING(union_pw_aff)
0186 ISL_OBJECT_TO_STRING(union_pw_multi_aff)
0187 //@}
0188 
0189 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
0190 /// C++ wrapper for isl_*_dump() functions.
0191 //@{
0192 
0193 #define ISL_DUMP_OBJECT(name)                                                  \
0194   void dumpIslObj(const isl::name &Obj);                                       \
0195   void dumpIslObj(isl_##name *Obj);
0196 
0197 ISL_DUMP_OBJECT(aff)
0198 ISL_DUMP_OBJECT(aff_list)
0199 ISL_DUMP_OBJECT(ast_expr)
0200 ISL_DUMP_OBJECT(ast_node)
0201 ISL_DUMP_OBJECT(ast_node_list)
0202 ISL_DUMP_OBJECT(basic_map)
0203 ISL_DUMP_OBJECT(basic_map_list)
0204 ISL_DUMP_OBJECT(basic_set)
0205 ISL_DUMP_OBJECT(basic_set_list)
0206 ISL_DUMP_OBJECT(constraint)
0207 ISL_DUMP_OBJECT(id)
0208 ISL_DUMP_OBJECT(id_list)
0209 ISL_DUMP_OBJECT(id_to_ast_expr)
0210 ISL_DUMP_OBJECT(local_space)
0211 ISL_DUMP_OBJECT(map)
0212 ISL_DUMP_OBJECT(map_list)
0213 ISL_DUMP_OBJECT(multi_aff)
0214 ISL_DUMP_OBJECT(multi_pw_aff)
0215 ISL_DUMP_OBJECT(multi_union_pw_aff)
0216 ISL_DUMP_OBJECT(multi_val)
0217 ISL_DUMP_OBJECT(point)
0218 ISL_DUMP_OBJECT(pw_aff)
0219 ISL_DUMP_OBJECT(pw_aff_list)
0220 ISL_DUMP_OBJECT(pw_multi_aff)
0221 ISL_DUMP_OBJECT(schedule)
0222 ISL_DUMP_OBJECT(schedule_constraints)
0223 ISL_DUMP_OBJECT(schedule_node)
0224 ISL_DUMP_OBJECT(set)
0225 ISL_DUMP_OBJECT(set_list)
0226 ISL_DUMP_OBJECT(space)
0227 ISL_DUMP_OBJECT(union_map)
0228 ISL_DUMP_OBJECT(union_pw_aff)
0229 ISL_DUMP_OBJECT(union_pw_aff_list)
0230 ISL_DUMP_OBJECT(union_pw_multi_aff)
0231 ISL_DUMP_OBJECT(union_set)
0232 ISL_DUMP_OBJECT(union_set_list)
0233 ISL_DUMP_OBJECT(val)
0234 ISL_DUMP_OBJECT(val_list)
0235 //@}
0236 
0237 /// Emit the equivaltent of the isl_*_dump output into a raw_ostream.
0238 /// @{
0239 void dumpIslObj(const isl::schedule_node &Node, llvm::raw_ostream &OS);
0240 void dumpIslObj(__isl_keep isl_schedule_node *node, llvm::raw_ostream &OS);
0241 /// @}
0242 #endif
0243 
0244 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
0245                                      __isl_keep isl_union_map *Map) {
0246   OS << polly::stringFromIslObj(Map, "null");
0247   return OS;
0248 }
0249 
0250 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
0251                                      __isl_keep isl_map *Map) {
0252   OS << polly::stringFromIslObj(Map, "null");
0253   return OS;
0254 }
0255 
0256 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
0257                                      __isl_keep isl_set *Set) {
0258   OS << polly::stringFromIslObj(Set, "null");
0259   return OS;
0260 }
0261 
0262 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
0263                                      __isl_keep isl_pw_aff *Map) {
0264   OS << polly::stringFromIslObj(Map, "null");
0265   return OS;
0266 }
0267 
0268 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
0269                                      __isl_keep isl_pw_multi_aff *PMA) {
0270   OS << polly::stringFromIslObj(PMA, "null");
0271   return OS;
0272 }
0273 
0274 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
0275                                      __isl_keep isl_multi_aff *MA) {
0276   OS << polly::stringFromIslObj(MA, "null");
0277   return OS;
0278 }
0279 
0280 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
0281                                      __isl_keep isl_union_pw_multi_aff *UPMA) {
0282   OS << polly::stringFromIslObj(UPMA, "null");
0283   return OS;
0284 }
0285 
0286 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
0287                                      __isl_keep isl_schedule *Schedule) {
0288   OS << polly::stringFromIslObj(Schedule, "null");
0289   return OS;
0290 }
0291 
0292 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
0293                                      __isl_keep isl_space *Space) {
0294   OS << polly::stringFromIslObj(Space, "null");
0295   return OS;
0296 }
0297 
0298 /// Combine Prefix, Val (or Number) and Suffix to an isl-compatible name.
0299 ///
0300 /// In case @p UseInstructionNames is set, this function returns:
0301 ///
0302 /// @p Prefix + "_" + @p Val->getName() + @p Suffix
0303 ///
0304 /// otherwise
0305 ///
0306 /// @p Prefix + to_string(Number) + @p Suffix
0307 ///
0308 /// We ignore the value names by default, as they may change between release
0309 /// and debug mode and can consequently not be used when aiming for reproducible
0310 /// builds. However, for debugging named statements are often helpful, hence
0311 /// we allow their optional use.
0312 std::string getIslCompatibleName(const std::string &Prefix,
0313                                  const llvm::Value *Val, long Number,
0314                                  const std::string &Suffix,
0315                                  bool UseInstructionNames);
0316 
0317 /// Combine Prefix, Name (or Number) and Suffix to an isl-compatible name.
0318 ///
0319 /// In case @p UseInstructionNames is set, this function returns:
0320 ///
0321 /// @p Prefix + "_" + Name + @p Suffix
0322 ///
0323 /// otherwise
0324 ///
0325 /// @p Prefix + to_string(Number) + @p Suffix
0326 ///
0327 /// We ignore @p Name by default, as they may change between release
0328 /// and debug mode and can consequently not be used when aiming for reproducible
0329 /// builds. However, for debugging named statements are often helpful, hence
0330 /// we allow their optional use.
0331 std::string getIslCompatibleName(const std::string &Prefix,
0332                                  const std::string &Middle, long Number,
0333                                  const std::string &Suffix,
0334                                  bool UseInstructionNames);
0335 
0336 std::string getIslCompatibleName(const std::string &Prefix,
0337                                  const std::string &Middle,
0338                                  const std::string &Suffix);
0339 
0340 inline llvm::DiagnosticInfoOptimizationBase &
0341 operator<<(llvm::DiagnosticInfoOptimizationBase &OS,
0342            const isl::union_map &Obj) {
0343   OS << stringFromIslObj(Obj);
0344   return OS;
0345 }
0346 
0347 /// Scope guard for code that allows arbitrary isl function to return an error
0348 /// if the max-operations quota exceeds.
0349 ///
0350 /// This allows to opt-in code sections that have known long executions times.
0351 /// code not in a hot path can continue to assume that no unexpected error
0352 /// occurs.
0353 ///
0354 /// This is typically used inside a nested IslMaxOperationsGuard scope. The
0355 /// IslMaxOperationsGuard defines the number of allowed base operations for some
0356 /// code, IslQuotaScope defines where it is allowed to return an error result.
0357 class IslQuotaScope final {
0358   isl_ctx *IslCtx;
0359   int OldOnError;
0360 
0361 public:
0362   IslQuotaScope() : IslCtx(nullptr) {}
0363   IslQuotaScope(const IslQuotaScope &) = delete;
0364   IslQuotaScope(IslQuotaScope &&Other)
0365       : IslCtx(Other.IslCtx), OldOnError(Other.OldOnError) {
0366     Other.IslCtx = nullptr;
0367   }
0368   const IslQuotaScope &operator=(IslQuotaScope &&Other) {
0369     std::swap(this->IslCtx, Other.IslCtx);
0370     std::swap(this->OldOnError, Other.OldOnError);
0371     return *this;
0372   }
0373 
0374   /// Enter a quota-aware scope.
0375   ///
0376   /// Should not be used directly. Use IslMaxOperationsGuard::enter() instead.
0377   explicit IslQuotaScope(isl_ctx *IslCtx, unsigned long LocalMaxOps)
0378       : IslCtx(IslCtx) {
0379     assert(IslCtx);
0380     assert(isl_ctx_get_max_operations(IslCtx) == 0 && "Incorrect nesting");
0381     if (LocalMaxOps == 0) {
0382       this->IslCtx = nullptr;
0383       return;
0384     }
0385 
0386     OldOnError = isl_options_get_on_error(IslCtx);
0387     isl_options_set_on_error(IslCtx, ISL_ON_ERROR_CONTINUE);
0388     isl_ctx_reset_error(IslCtx);
0389     isl_ctx_set_max_operations(IslCtx, LocalMaxOps);
0390   }
0391 
0392   ~IslQuotaScope() {
0393     if (!IslCtx)
0394       return;
0395 
0396     assert(isl_ctx_get_max_operations(IslCtx) > 0 && "Incorrect nesting");
0397     assert(isl_options_get_on_error(IslCtx) == ISL_ON_ERROR_CONTINUE &&
0398            "Incorrect nesting");
0399     isl_ctx_set_max_operations(IslCtx, 0);
0400     isl_options_set_on_error(IslCtx, OldOnError);
0401   }
0402 
0403   /// Return whether the current quota has exceeded.
0404   bool hasQuotaExceeded() const {
0405     if (!IslCtx)
0406       return false;
0407 
0408     return isl_ctx_last_error(IslCtx) == isl_error_quota;
0409   }
0410 };
0411 
0412 /// Scoped limit of ISL operations.
0413 ///
0414 /// Limits the number of ISL operations during the lifetime of this object. The
0415 /// idea is to use this as an RAII guard for the scope where the code is aware
0416 /// that ISL can return errors even when all input is valid. After leaving the
0417 /// scope, it will return to the error setting as it was before. That also means
0418 /// that the error setting should not be changed while in that scope.
0419 ///
0420 /// Such scopes are not allowed to be nested because the previous operations
0421 /// counter cannot be reset to the previous state, or one that adds the
0422 /// operations while being in the nested scope. Use therefore is only allowed
0423 /// while currently a no operations-limit is active.
0424 class IslMaxOperationsGuard final {
0425 private:
0426   /// The ISL context to set the operations limit.
0427   ///
0428   /// If set to nullptr, there is no need for any action at the end of the
0429   /// scope.
0430   isl_ctx *IslCtx;
0431 
0432   /// Maximum number of operations for the scope.
0433   unsigned long LocalMaxOps;
0434 
0435   /// When AutoEnter is enabled, holds the IslQuotaScope object.
0436   IslQuotaScope TopLevelScope;
0437 
0438 public:
0439   /// Enter a max operations scope.
0440   ///
0441   /// @param IslCtx      The ISL context to set the operations limit for.
0442   /// @param LocalMaxOps Maximum number of operations allowed in the
0443   ///                    scope. If set to zero, no operations limit is enforced.
0444   /// @param AutoEnter   If true, automatically enters an IslQuotaScope such
0445   ///                    that isl operations may return quota errors
0446   ///                    immediately. If false, only starts the operations
0447   ///                    counter, but isl does not return quota errors before
0448   ///                    calling enter().
0449   IslMaxOperationsGuard(isl_ctx *IslCtx, unsigned long LocalMaxOps,
0450                         bool AutoEnter = true)
0451       : IslCtx(IslCtx), LocalMaxOps(LocalMaxOps) {
0452     assert(IslCtx);
0453     assert(isl_ctx_get_max_operations(IslCtx) == 0 &&
0454            "Nested max operations not supported");
0455 
0456     // Users of this guard may check whether the last error was isl_error_quota.
0457     // Reset the last error such that a previous out-of-quota error is not
0458     // mistaken to have occurred in the in this quota, even if the max number of
0459     // operations is set to infinite (LocalMaxOps == 0).
0460     isl_ctx_reset_error(IslCtx);
0461 
0462     if (LocalMaxOps == 0) {
0463       // No limit on operations; also disable restoring on_error/max_operations.
0464       this->IslCtx = nullptr;
0465       return;
0466     }
0467 
0468     isl_ctx_reset_operations(IslCtx);
0469     TopLevelScope = enter(AutoEnter);
0470   }
0471 
0472   /// Enter a scope that can handle out-of-quota errors.
0473   ///
0474   /// @param AllowReturnNull Whether the scoped code can handle out-of-quota
0475   ///                        errors. If false, returns a dummy scope object that
0476   ///                        does nothing.
0477   IslQuotaScope enter(bool AllowReturnNull = true) {
0478     return AllowReturnNull && IslCtx ? IslQuotaScope(IslCtx, LocalMaxOps)
0479                                      : IslQuotaScope();
0480   }
0481 
0482   /// Return whether the current quota has exceeded.
0483   bool hasQuotaExceeded() const {
0484     if (!IslCtx)
0485       return false;
0486 
0487     return isl_ctx_last_error(IslCtx) == isl_error_quota;
0488   }
0489 };
0490 } // end namespace polly
0491 
0492 #endif