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 Attribute;
23 class MLIRContext;
24 class Identifier;
25 
26 namespace detail {
27 
28 struct CallSiteLocationStorage;
29 struct FileLineColLocationStorage;
30 struct FusedLocationStorage;
31 struct LocationStorage;
32 struct NameLocationStorage;
33 struct OpaqueLocationStorage;
34 struct UnknownLocationStorage;
35 
36 } // namespace detail
37 
38 /// Location objects represent source locations information in MLIR.
39 /// LocationAttr acts as the anchor for all Location based attributes.
40 class LocationAttr : public Attribute {
41 public:
42   using Attribute::Attribute;
43 
44   /// Methods for support type inquiry through isa, cast, and dyn_cast.
45   static bool classof(Attribute attr);
46 };
47 
48 /// This class defines the main interface for locations in MLIR and acts as a
49 /// non-nullable wrapper around a LocationAttr.
50 class Location {
51 public:
Location(LocationAttr loc)52   Location(LocationAttr loc) : impl(loc) {
53     assert(loc && "location should never be null.");
54   }
Location(const LocationAttr::ImplType * impl)55   Location(const LocationAttr::ImplType *impl) : impl(impl) {
56     assert(impl && "location should never be null.");
57   }
58 
59   /// Return the context this location is uniqued in.
getContext()60   MLIRContext *getContext() const { return impl.getContext(); }
61 
62   /// Access the impl location attribute.
LocationAttr()63   operator LocationAttr() const { return impl; }
64   LocationAttr *operator->() const { return const_cast<LocationAttr *>(&impl); }
65 
66   /// Type casting utilities on the underlying location.
isa()67   template <typename U> bool isa() const { return impl.isa<U>(); }
dyn_cast()68   template <typename U> U dyn_cast() const { return impl.dyn_cast<U>(); }
cast()69   template <typename U> U cast() const { return impl.cast<U>(); }
70 
71   /// Comparison operators.
72   bool operator==(Location rhs) const { return impl == rhs.impl; }
73   bool operator!=(Location rhs) const { return !(*this == rhs); }
74 
75   /// Print the location.
print(raw_ostream & os)76   void print(raw_ostream &os) const { impl.print(os); }
dump()77   void dump() const { impl.dump(); }
78 
79   friend ::llvm::hash_code hash_value(Location arg);
80 
81   /// Methods for supporting PointerLikeTypeTraits.
getAsOpaquePointer()82   const void *getAsOpaquePointer() const { return impl.getAsOpaquePointer(); }
getFromOpaquePointer(const void * pointer)83   static Location getFromOpaquePointer(const void *pointer) {
84     return LocationAttr(reinterpret_cast<const AttributeStorage *>(pointer));
85   }
86 
87 protected:
88   /// The internal backing location attribute.
89   LocationAttr impl;
90 };
91 
92 inline raw_ostream &operator<<(raw_ostream &os, const Location &loc) {
93   loc.print(os);
94   return os;
95 }
96 
97 /// Represents a location as call site. "callee" is the concrete location
98 /// (Unknown/NameLocation/FileLineColLoc/OpaqueLoc) and "caller" points to the
99 /// caller's location (another CallLocation or a concrete location). Multiple
100 /// CallSiteLocs can be chained to form a call stack.
101 class CallSiteLoc
102     : public Attribute::AttrBase<CallSiteLoc, LocationAttr,
103                                  detail::CallSiteLocationStorage> {
104 public:
105   using Base::Base;
106 
107   /// Return a uniqued call location object.
108   static Location get(Location callee, Location caller);
109 
110   /// Return a call site location which represents a name reference in one line
111   /// or a stack of frames. The input frames are ordered from innermost to
112   /// outermost.
113   static Location get(Location name, ArrayRef<Location> frames);
114 
115   /// The concrete location information this object presents.
116   Location getCallee() const;
117 
118   /// The caller's location.
119   Location getCaller() const;
120 };
121 
122 /// Represents a location derived from a file/line/column location.  The column
123 /// and line may be zero to represent unknown column and/or unknown line/column
124 /// information.
125 class FileLineColLoc
126     : public Attribute::AttrBase<FileLineColLoc, LocationAttr,
127                                  detail::FileLineColLocationStorage> {
128 public:
129   using Base::Base;
130 
131   /// Return a uniqued FileLineCol location object.
132   static Location get(Identifier filename, unsigned line, unsigned column,
133                       MLIRContext *context);
134   static Location get(StringRef filename, unsigned line, unsigned column,
135                       MLIRContext *context);
136 
137   StringRef getFilename() const;
138 
139   unsigned getLine() const;
140   unsigned getColumn() const;
141 };
142 
143 /// Represents a value composed of multiple source constructs, with an optional
144 /// metadata attribute.
145 class FusedLoc : public Attribute::AttrBase<FusedLoc, LocationAttr,
146                                             detail::FusedLocationStorage> {
147 public:
148   using Base::Base;
149 
150   /// Return a uniqued Fused Location object. The first location in the list
151   /// will get precedence during diagnostic emission, with the rest being
152   /// displayed as supplementary "fused from here" style notes.
153   static Location get(ArrayRef<Location> locs, Attribute metadata,
154                       MLIRContext *context);
get(ArrayRef<Location> locs,MLIRContext * context)155   static Location get(ArrayRef<Location> locs, MLIRContext *context) {
156     return get(locs, Attribute(), context);
157   }
158 
159   ArrayRef<Location> getLocations() const;
160 
161   /// Returns the optional metadata attached to this fused location. Given that
162   /// it is optional, the return value may be a null node.
163   Attribute getMetadata() const;
164 };
165 
166 /// Represents an identity name attached to a child location.
167 class NameLoc : public Attribute::AttrBase<NameLoc, LocationAttr,
168                                            detail::NameLocationStorage> {
169 public:
170   using Base::Base;
171 
172   /// Return a uniqued name location object. The child location must not be
173   /// another NameLoc.
174   static Location get(Identifier name, Location child);
175 
176   /// Return a uniqued name location object with an unknown child.
177   static Location get(Identifier name, MLIRContext *context);
178 
179   /// Return the name identifier.
180   Identifier getName() const;
181 
182   /// Return the child location.
183   Location getChildLoc() const;
184 };
185 
186 /// Represents an unknown location.  This is always a singleton for a given
187 /// MLIRContext.
188 class UnknownLoc
189     : public Attribute::AttrBase<UnknownLoc, LocationAttr, AttributeStorage> {
190 public:
191   using Base::Base;
192 
193   /// Get an instance of the UnknownLoc.
194   static Location get(MLIRContext *context);
195 };
196 
197 /// Represents a location that is external to MLIR. Contains a pointer to some
198 /// data structure and an optional location that can be used if the first one is
199 /// not suitable. Since it contains an external structure, only optional
200 /// location is used during serialization.
201 /// The class also provides a number of methods for making type-safe casts
202 /// between a pointer to an object and opaque location.
203 class OpaqueLoc : public Attribute::AttrBase<OpaqueLoc, LocationAttr,
204                                              detail::OpaqueLocationStorage> {
205 public:
206   using Base::Base;
207 
208   /// Returns an instance of opaque location which contains a given pointer to
209   /// an object. The corresponding MLIR location is set to UnknownLoc.
210   template <typename T>
get(T underlyingLocation,MLIRContext * context)211   static Location get(T underlyingLocation, MLIRContext *context) {
212     return get(reinterpret_cast<uintptr_t>(underlyingLocation),
213                TypeID::get<T>(), UnknownLoc::get(context));
214   }
215 
216   /// Returns an instance of opaque location which contains a given pointer to
217   /// an object and an additional MLIR location.
218   template <typename T>
get(T underlyingLocation,Location fallbackLocation)219   static Location get(T underlyingLocation, Location fallbackLocation) {
220     return get(reinterpret_cast<uintptr_t>(underlyingLocation),
221                TypeID::get<T>(), fallbackLocation);
222   }
223 
224   /// Returns a pointer to some data structure that opaque location stores.
getUnderlyingLocation(Location location)225   template <typename T> static T getUnderlyingLocation(Location location) {
226     assert(isa<T>(location));
227     return reinterpret_cast<T>(
228         location.cast<mlir::OpaqueLoc>().getUnderlyingLocation());
229   }
230 
231   /// Returns a pointer to some data structure that opaque location stores.
232   /// Returns nullptr if provided location is not opaque location or if it
233   /// contains a pointer of different type.
234   template <typename T>
getUnderlyingLocationOrNull(Location location)235   static T getUnderlyingLocationOrNull(Location location) {
236     return isa<T>(location)
237                ? reinterpret_cast<T>(
238                      location.cast<mlir::OpaqueLoc>().getUnderlyingLocation())
239                : T(nullptr);
240   }
241 
242   /// Checks whether provided location is opaque location and contains a pointer
243   /// to an object of particular type.
isa(Location location)244   template <typename T> static bool isa(Location location) {
245     auto opaque_loc = location.dyn_cast<OpaqueLoc>();
246     return opaque_loc && opaque_loc.getUnderlyingTypeID() == TypeID::get<T>();
247   }
248 
249   /// Returns a pointer to the corresponding object.
250   uintptr_t getUnderlyingLocation() const;
251 
252   /// Returns a TypeID that represents the underlying objects c++ type.
253   TypeID getUnderlyingTypeID() const;
254 
255   /// Returns a fallback location.
256   Location getFallbackLocation() const;
257 
258 private:
259   static Location get(uintptr_t underlyingLocation, TypeID typeID,
260                       Location fallbackLocation);
261 };
262 
263 // Make Location hashable.
hash_value(Location arg)264 inline ::llvm::hash_code hash_value(Location arg) {
265   return hash_value(arg.impl);
266 }
267 
268 } // end namespace mlir
269 
270 namespace llvm {
271 
272 // Type hash just like pointers.
273 template <> struct DenseMapInfo<mlir::Location> {
274   static mlir::Location getEmptyKey() {
275     auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
276     return mlir::Location::getFromOpaquePointer(pointer);
277   }
278   static mlir::Location getTombstoneKey() {
279     auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
280     return mlir::Location::getFromOpaquePointer(pointer);
281   }
282   static unsigned getHashValue(mlir::Location val) {
283     return mlir::hash_value(val);
284   }
285   static bool isEqual(mlir::Location LHS, mlir::Location RHS) {
286     return LHS == RHS;
287   }
288 };
289 
290 /// We align LocationStorage by 8, so allow LLVM to steal the low bits.
291 template <> struct PointerLikeTypeTraits<mlir::Location> {
292 public:
293   static inline void *getAsVoidPointer(mlir::Location I) {
294     return const_cast<void *>(I.getAsOpaquePointer());
295   }
296   static inline mlir::Location getFromVoidPointer(void *P) {
297     return mlir::Location::getFromOpaquePointer(P);
298   }
299   static constexpr int NumLowBitsAvailable =
300       PointerLikeTypeTraits<mlir::Attribute>::NumLowBitsAvailable;
301 };
302 
303 } // namespace llvm
304 
305 #endif
306