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