| 1 | //===- Location.h - MLIR Location Classes -----------------------*- C++ -*-===// |
| 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 | // These classes provide the ability to relate MLIR objects back to source |
| 10 | // location position information. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef MLIR_IR_LOCATION_H |
| 15 | #define MLIR_IR_LOCATION_H |
| 16 | |
| 17 | #include "mlir/IR/Attributes.h" |
| 18 | #include "llvm/Support/PointerLikeTypeTraits.h" |
| 19 | |
| 20 | namespace mlir { |
| 21 | |
| 22 | class Location; |
| 23 | class WalkResult; |
| 24 | class UnknownLoc; |
| 25 | |
| 26 | //===----------------------------------------------------------------------===// |
| 27 | // LocationAttr |
| 28 | //===----------------------------------------------------------------------===// |
| 29 | |
| 30 | /// Location objects represent source locations information in MLIR. |
| 31 | /// LocationAttr acts as the anchor for all Location based attributes. |
| 32 | class LocationAttr : public Attribute { |
| 33 | public: |
| 34 | using Attribute::Attribute; |
| 35 | |
| 36 | /// Walk all of the locations nested directly under, and including, the |
| 37 | /// current. This means that if a location is nested under a non-location |
| 38 | /// attribute, it will *not* be walked by this method. This walk is performed |
| 39 | /// in pre-order to get this behavior. |
| 40 | WalkResult walk(function_ref<WalkResult(Location)> walkFn); |
| 41 | |
| 42 | /// Return an instance of the given location type if one is nested under the |
| 43 | /// current location. Returns nullptr if one could not be found. |
| 44 | template <typename T> |
| 45 | T findInstanceOf() { |
| 46 | T result = {}; |
| 47 | walk(walkFn: [&](auto loc) { |
| 48 | if (auto typedLoc = llvm::dyn_cast<T>(loc)) { |
| 49 | result = typedLoc; |
| 50 | return WalkResult::interrupt(); |
| 51 | } |
| 52 | return WalkResult::advance(); |
| 53 | }); |
| 54 | return result; |
| 55 | } |
| 56 | |
| 57 | /// Return an instance of the given location type if one is nested under the |
| 58 | /// current location else return unknown location. |
| 59 | template <typename T, typename UnknownT = UnknownLoc> |
| 60 | LocationAttr findInstanceOfOrUnknown() { |
| 61 | if (T result = findInstanceOf<T>()) |
| 62 | return result; |
| 63 | return UnknownT::get(getContext()); |
| 64 | } |
| 65 | |
| 66 | /// Methods for support type inquiry through isa, cast, and dyn_cast. |
| 67 | static bool classof(Attribute attr); |
| 68 | }; |
| 69 | |
| 70 | //===----------------------------------------------------------------------===// |
| 71 | // Location |
| 72 | //===----------------------------------------------------------------------===// |
| 73 | |
| 74 | /// This class defines the main interface for locations in MLIR and acts as a |
| 75 | /// non-nullable wrapper around a LocationAttr. |
| 76 | class Location { |
| 77 | public: |
| 78 | Location(LocationAttr loc) : impl(loc) { |
| 79 | assert(loc && "location should never be null." ); |
| 80 | } |
| 81 | Location(const LocationAttr::ImplType *impl) : impl(impl) { |
| 82 | assert(impl && "location should never be null." ); |
| 83 | } |
| 84 | |
| 85 | /// Return the context this location is uniqued in. |
| 86 | MLIRContext *getContext() const { return impl.getContext(); } |
| 87 | |
| 88 | /// Access the impl location attribute. |
| 89 | operator LocationAttr() const { return impl; } |
| 90 | LocationAttr *operator->() const { return const_cast<LocationAttr *>(&impl); } |
| 91 | |
| 92 | /// Comparison operators. |
| 93 | bool operator==(Location rhs) const { return impl == rhs.impl; } |
| 94 | bool operator!=(Location rhs) const { return !(*this == rhs); } |
| 95 | |
| 96 | /// Print the location. |
| 97 | void print(raw_ostream &os) const { impl.print(os); } |
| 98 | void dump() const { impl.dump(); } |
| 99 | |
| 100 | friend ::llvm::hash_code hash_value(Location arg); |
| 101 | |
| 102 | /// Methods for supporting PointerLikeTypeTraits. |
| 103 | const void *getAsOpaquePointer() const { return impl.getAsOpaquePointer(); } |
| 104 | static Location getFromOpaquePointer(const void *pointer) { |
| 105 | return LocationAttr(reinterpret_cast<const AttributeStorage *>(pointer)); |
| 106 | } |
| 107 | |
| 108 | /// Support llvm style casting. |
| 109 | static bool classof(Attribute attr) { return llvm::isa<LocationAttr>(Val: attr); } |
| 110 | |
| 111 | protected: |
| 112 | /// The internal backing location attribute. |
| 113 | LocationAttr impl; |
| 114 | }; |
| 115 | |
| 116 | inline raw_ostream &operator<<(raw_ostream &os, const Location &loc) { |
| 117 | loc.print(os); |
| 118 | return os; |
| 119 | } |
| 120 | |
| 121 | // Make Location hashable. |
| 122 | inline ::llvm::hash_code hash_value(Location arg) { |
| 123 | return hash_value(arg: arg.impl); |
| 124 | } |
| 125 | |
| 126 | } // namespace mlir |
| 127 | |
| 128 | //===----------------------------------------------------------------------===// |
| 129 | // Tablegen Attribute Declarations |
| 130 | //===----------------------------------------------------------------------===// |
| 131 | |
| 132 | // Forward declaration for class created later. |
| 133 | namespace mlir::detail { |
| 134 | struct FileLineColRangeAttrStorage; |
| 135 | } // namespace mlir::detail |
| 136 | |
| 137 | #define GET_ATTRDEF_CLASSES |
| 138 | #include "mlir/IR/BuiltinLocationAttributes.h.inc" |
| 139 | |
| 140 | namespace mlir { |
| 141 | |
| 142 | //===----------------------------------------------------------------------===// |
| 143 | // FusedLoc |
| 144 | //===----------------------------------------------------------------------===// |
| 145 | |
| 146 | /// This class represents a fused location whose metadata is known to be an |
| 147 | /// instance of the given type. |
| 148 | template <typename MetadataT> |
| 149 | class FusedLocWith : public FusedLoc { |
| 150 | public: |
| 151 | using FusedLoc::FusedLoc; |
| 152 | |
| 153 | /// Return the metadata associated with this fused location. |
| 154 | MetadataT getMetadata() const { |
| 155 | return llvm::cast<MetadataT>(FusedLoc::getMetadata()); |
| 156 | } |
| 157 | |
| 158 | /// Support llvm style casting. |
| 159 | static bool classof(Attribute attr) { |
| 160 | auto fusedLoc = llvm::dyn_cast<FusedLoc>(attr); |
| 161 | return fusedLoc && mlir::isa_and_nonnull<MetadataT>(fusedLoc.getMetadata()); |
| 162 | } |
| 163 | }; |
| 164 | |
| 165 | //===----------------------------------------------------------------------===// |
| 166 | // FileLineColLoc |
| 167 | //===----------------------------------------------------------------------===// |
| 168 | |
| 169 | /// An instance of this location represents a tuple of file, line number, and |
| 170 | /// column number. This is similar to the type of location that you get from |
| 171 | /// most source languages. |
| 172 | /// |
| 173 | /// FileLineColLoc is a view to FileLineColRange with one line and column. |
| 174 | class FileLineColLoc : public FileLineColRange { |
| 175 | public: |
| 176 | using FileLineColRange::FileLineColRange; |
| 177 | |
| 178 | static FileLineColLoc get(StringAttr filename, unsigned line, |
| 179 | unsigned column); |
| 180 | static FileLineColLoc get(MLIRContext *context, StringRef fileName, |
| 181 | unsigned line, unsigned column); |
| 182 | |
| 183 | StringAttr getFilename() const; |
| 184 | unsigned getLine() const; |
| 185 | unsigned getColumn() const; |
| 186 | }; |
| 187 | |
| 188 | /// Returns true iff the given location is a FileLineColRange with exactly one |
| 189 | /// line and column. |
| 190 | bool isStrictFileLineColLoc(Location loc); |
| 191 | |
| 192 | //===----------------------------------------------------------------------===// |
| 193 | // OpaqueLoc |
| 194 | //===----------------------------------------------------------------------===// |
| 195 | |
| 196 | /// Returns an instance of opaque location which contains a given pointer to |
| 197 | /// an object. The corresponding MLIR location is set to UnknownLoc. |
| 198 | template <typename T> |
| 199 | inline OpaqueLoc OpaqueLoc::get(T underlyingLocation, MLIRContext *context) { |
| 200 | return get(reinterpret_cast<uintptr_t>(underlyingLocation), TypeID::get<T>(), |
| 201 | UnknownLoc::get(context)); |
| 202 | } |
| 203 | |
| 204 | //===----------------------------------------------------------------------===// |
| 205 | // SubElements |
| 206 | //===----------------------------------------------------------------------===// |
| 207 | |
| 208 | /// Enable locations to be introspected as sub-elements. |
| 209 | template <> |
| 210 | struct AttrTypeSubElementHandler<Location> { |
| 211 | static void walk(Location param, AttrTypeImmediateSubElementWalker &walker) { |
| 212 | walker.walk(param); |
| 213 | } |
| 214 | static Location replace(Location param, AttrSubElementReplacements &attrRepls, |
| 215 | TypeSubElementReplacements &typeRepls) { |
| 216 | return cast<LocationAttr>(attrRepls.take_front(1)[0]); |
| 217 | } |
| 218 | }; |
| 219 | |
| 220 | } // namespace mlir |
| 221 | |
| 222 | //===----------------------------------------------------------------------===// |
| 223 | // LLVM Utilities |
| 224 | //===----------------------------------------------------------------------===// |
| 225 | |
| 226 | namespace llvm { |
| 227 | |
| 228 | // Type hash just like pointers. |
| 229 | template <> |
| 230 | struct DenseMapInfo<mlir::Location> { |
| 231 | static mlir::Location getEmptyKey() { |
| 232 | auto *pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); |
| 233 | return mlir::Location::getFromOpaquePointer(pointer); |
| 234 | } |
| 235 | static mlir::Location getTombstoneKey() { |
| 236 | auto *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); |
| 237 | return mlir::Location::getFromOpaquePointer(pointer); |
| 238 | } |
| 239 | static unsigned getHashValue(mlir::Location val) { |
| 240 | return mlir::hash_value(arg: val); |
| 241 | } |
| 242 | static bool isEqual(mlir::Location LHS, mlir::Location RHS) { |
| 243 | return LHS == RHS; |
| 244 | } |
| 245 | }; |
| 246 | |
| 247 | /// We align LocationStorage by 8, so allow LLVM to steal the low bits. |
| 248 | template <> |
| 249 | struct PointerLikeTypeTraits<mlir::Location> { |
| 250 | public: |
| 251 | static inline void *getAsVoidPointer(mlir::Location I) { |
| 252 | return const_cast<void *>(I.getAsOpaquePointer()); |
| 253 | } |
| 254 | static inline mlir::Location getFromVoidPointer(void *P) { |
| 255 | return mlir::Location::getFromOpaquePointer(pointer: P); |
| 256 | } |
| 257 | static constexpr int NumLowBitsAvailable = |
| 258 | PointerLikeTypeTraits<mlir::Attribute>::NumLowBitsAvailable; |
| 259 | }; |
| 260 | |
| 261 | /// The constructors in mlir::Location ensure that the class is a non-nullable |
| 262 | /// wrapper around mlir::LocationAttr. Override default behavior and always |
| 263 | /// return true for isPresent(). |
| 264 | template <> |
| 265 | struct ValueIsPresent<mlir::Location> { |
| 266 | using UnwrappedType = mlir::Location; |
| 267 | static inline bool isPresent(const mlir::Location &location) { return true; } |
| 268 | }; |
| 269 | |
| 270 | /// Add support for llvm style casts. We provide a cast between To and From if |
| 271 | /// From is mlir::Location or derives from it. |
| 272 | template <typename To, typename From> |
| 273 | struct CastInfo<To, From, |
| 274 | std::enable_if_t< |
| 275 | std::is_same_v<mlir::Location, std::remove_const_t<From>> || |
| 276 | std::is_base_of_v<mlir::Location, From>>> |
| 277 | : DefaultDoCastIfPossible<To, From, CastInfo<To, From>> { |
| 278 | |
| 279 | static inline bool isPossible(mlir::Location location) { |
| 280 | /// Return a constant true instead of a dynamic true when casting to self or |
| 281 | /// up the hierarchy. Additionally, all casting info is deferred to the |
| 282 | /// wrapped mlir::LocationAttr instance stored in mlir::Location. |
| 283 | return std::is_same_v<To, std::remove_const_t<From>> || |
| 284 | isa<To>(static_cast<mlir::LocationAttr>(location)); |
| 285 | } |
| 286 | |
| 287 | static inline To castFailed() { return To(); } |
| 288 | |
| 289 | static inline To doCast(mlir::Location location) { |
| 290 | return To(location->getImpl()); |
| 291 | } |
| 292 | }; |
| 293 | |
| 294 | } // namespace llvm |
| 295 | |
| 296 | #endif |
| 297 | |