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