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