xref: /llvm-project/mlir/lib/IR/Location.cpp (revision 3b35b4c7f9141c59fbac415e335489494b7d507e)
1 //===- Location.cpp - MLIR Location Classes -------------------------------===//
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 #include "mlir/IR/Location.h"
10 #include "mlir/IR/AttributeSupport.h"
11 #include "mlir/IR/BuiltinAttributes.h"
12 #include "mlir/IR/BuiltinDialect.h"
13 #include "mlir/IR/MLIRContext.h"
14 #include "mlir/IR/Visitors.h"
15 #include "mlir/Support/LLVM.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/Hashing.h"
18 #include "llvm/ADT/PointerIntPair.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/SetVector.h"
21 #include "llvm/ADT/TypeSwitch.h"
22 #include "llvm/Support/Casting.h"
23 #include "llvm/Support/TrailingObjects.h"
24 #include <cassert>
25 #include <iterator>
26 #include <memory>
27 #include <optional>
28 #include <tuple>
29 #include <utility>
30 
31 using namespace mlir;
32 using namespace mlir::detail;
33 
34 namespace mlir::detail {
35 struct FileLineColRangeAttrStorage final
36     : public ::mlir::AttributeStorage,
37       public llvm::TrailingObjects<FileLineColRangeAttrStorage, unsigned> {
38   using PointerPair = llvm::PointerIntPair<StringAttr, 2>;
39   using KeyTy = std::tuple<StringAttr, ::llvm::ArrayRef<unsigned>>;
40 
41   FileLineColRangeAttrStorage(StringAttr filename, int numLocs)
42       : filenameAndTrailing(filename, numLocs) {}
43 
44   static FileLineColRangeAttrStorage *
45   construct(::mlir::AttributeStorageAllocator &allocator, KeyTy &&tblgenKey) {
46     auto numInArray = std::get<1>(tblgenKey).size();
47     // Note: Considered asserting that numInArray is at least 1, but this
48     // is not needed in memory or in printed form. This should very rarely be
49     // 0 here as that means a NamedLoc would have been more efficient. But this
50     // does allow for location with just a file, and also having the interface
51     // be more uniform.
52     auto locEnc = numInArray == 0 ? 1 : numInArray;
53     // Allocate a new storage instance.
54     auto byteSize =
55         FileLineColRangeAttrStorage::totalSizeToAlloc<unsigned>(locEnc - 1);
56     auto *rawMem =
57         allocator.allocate(byteSize, alignof(FileLineColRangeAttrStorage));
58     auto *result = ::new (rawMem) FileLineColRangeAttrStorage(
59         std::move(std::get<0>(tblgenKey)), locEnc - 1);
60     if (numInArray > 0) {
61       result->startLine = std::get<1>(tblgenKey)[0];
62       // Copy in the element types into the trailing storage.
63       std::uninitialized_copy(std::next(std::get<1>(tblgenKey).begin()),
64                               std::get<1>(tblgenKey).end(),
65                               result->getTrailingObjects<unsigned>());
66     }
67     return result;
68   }
69 
70   // Return the number of held types.
71   unsigned size() const { return filenameAndTrailing.getInt() + 1; }
72 
73   bool operator==(const KeyTy &tblgenKey) const {
74     return (filenameAndTrailing.getPointer() == std::get<0>(tblgenKey)) &&
75            (size() == std::get<1>(tblgenKey).size()) &&
76            (startLine == std::get<1>(tblgenKey)[0]) &&
77            (ArrayRef<unsigned>{getTrailingObjects<unsigned>(), size() - 1} ==
78             ArrayRef<unsigned>{std::get<1>(tblgenKey)}.drop_front());
79   }
80 
81   unsigned getLineCols(unsigned index) const {
82     return getTrailingObjects<unsigned>()[index - 1];
83   }
84 
85   unsigned getStartLine() const { return startLine; }
86   unsigned getStartColumn() const {
87     if (size() <= 1)
88       return 0;
89     return getLineCols(1);
90   }
91   unsigned getEndColumn() const {
92     if (size() <= 2)
93       return getStartColumn();
94     return getLineCols(2);
95   }
96   unsigned getEndLine() const {
97     if (size() <= 3)
98       return getStartLine();
99     return getLineCols(3);
100   }
101 
102   static ::llvm::hash_code hashKey(const KeyTy &tblgenKey) {
103     return ::llvm::hash_combine(std::get<0>(tblgenKey), std::get<1>(tblgenKey));
104   }
105 
106   // Supports
107   //  - 0 (file:line)
108   //  - 1 (file:line:col)
109   //  - 2 (file:line:start_col to file:line:end_col) and
110   //  - 3 (file:start_line:start_col to file:end_line:end_col)
111   llvm::PointerIntPair<StringAttr, 2> filenameAndTrailing;
112   unsigned startLine = 0;
113 };
114 } // namespace mlir::detail
115 
116 //===----------------------------------------------------------------------===//
117 /// Tablegen Attribute Definitions
118 //===----------------------------------------------------------------------===//
119 
120 #define GET_ATTRDEF_CLASSES
121 #include "mlir/IR/BuiltinLocationAttributes.cpp.inc"
122 
123 //===----------------------------------------------------------------------===//
124 // LocationAttr
125 //===----------------------------------------------------------------------===//
126 
127 WalkResult LocationAttr::walk(function_ref<WalkResult(Location)> walkFn) {
128   AttrTypeWalker walker;
129   // Walk locations, but skip any other attribute.
130   walker.addWalk([&](Attribute attr) {
131     if (auto loc = llvm::dyn_cast<LocationAttr>(attr))
132       return walkFn(loc);
133 
134     return WalkResult::skip();
135   });
136   return walker.walk<WalkOrder::PreOrder>(*this);
137 }
138 
139 /// Methods for support type inquiry through isa, cast, and dyn_cast.
140 bool LocationAttr::classof(Attribute attr) {
141   return attr.hasTrait<AttributeTrait::IsLocation>();
142 }
143 
144 //===----------------------------------------------------------------------===//
145 // CallSiteLoc
146 //===----------------------------------------------------------------------===//
147 
148 CallSiteLoc CallSiteLoc::get(Location name, ArrayRef<Location> frames) {
149   assert(!frames.empty() && "required at least 1 call frame");
150   Location caller = frames.back();
151   for (auto frame : llvm::reverse(frames.drop_back()))
152     caller = CallSiteLoc::get(frame, caller);
153   return CallSiteLoc::get(name, caller);
154 }
155 
156 //===----------------------------------------------------------------------===//
157 // FileLineColLoc
158 //===----------------------------------------------------------------------===//
159 
160 FileLineColLoc FileLineColLoc::get(StringAttr filename, unsigned line,
161                                    unsigned column) {
162   return llvm::cast<FileLineColLoc>(
163       FileLineColRange::get(filename, line, column));
164 }
165 
166 FileLineColLoc FileLineColLoc::get(MLIRContext *context, StringRef fileName,
167                                    unsigned line, unsigned column) {
168   return llvm::cast<FileLineColLoc>(
169       FileLineColRange::get(context, fileName, line, column));
170 }
171 
172 StringAttr FileLineColLoc::getFilename() const {
173   return FileLineColRange::getFilename();
174 }
175 
176 unsigned FileLineColLoc::getLine() const { return getStartLine(); }
177 
178 unsigned FileLineColLoc::getColumn() const { return getStartColumn(); }
179 
180 bool mlir::isStrictFileLineColLoc(Location loc) {
181   if (auto range = mlir::dyn_cast<FileLineColRange>(loc))
182     return range.getImpl()->size() == 2;
183   return false;
184 }
185 
186 //===----------------------------------------------------------------------===//
187 // FileLineColRange
188 //===----------------------------------------------------------------------===//
189 
190 StringAttr FileLineColRange::getFilename() const {
191   return getImpl()->filenameAndTrailing.getPointer();
192 }
193 
194 unsigned FileLineColRange::getStartLine() const {
195   return getImpl()->getStartLine();
196 }
197 unsigned FileLineColRange::getStartColumn() const {
198   return getImpl()->getStartColumn();
199 }
200 unsigned FileLineColRange::getEndColumn() const {
201   return getImpl()->getEndColumn();
202 }
203 unsigned FileLineColRange::getEndLine() const {
204   return getImpl()->getEndLine();
205 }
206 
207 //===----------------------------------------------------------------------===//
208 // FusedLoc
209 //===----------------------------------------------------------------------===//
210 
211 Location FusedLoc::get(ArrayRef<Location> locs, Attribute metadata,
212                        MLIRContext *context) {
213   // Unique the set of locations to be fused.
214   llvm::SmallSetVector<Location, 4> decomposedLocs;
215   for (auto loc : locs) {
216     // If the location is a fused location we decompose it if it has no
217     // metadata or the metadata is the same as the top level metadata.
218     if (auto fusedLoc = llvm::dyn_cast<FusedLoc>(loc)) {
219       if (fusedLoc.getMetadata() == metadata) {
220         // UnknownLoc's have already been removed from FusedLocs so we can
221         // simply add all of the internal locations.
222         decomposedLocs.insert(fusedLoc.getLocations().begin(),
223                               fusedLoc.getLocations().end());
224         continue;
225       }
226     }
227     // Otherwise, only add known locations to the set.
228     if (!llvm::isa<UnknownLoc>(loc))
229       decomposedLocs.insert(loc);
230   }
231   locs = decomposedLocs.getArrayRef();
232 
233   // Handle the simple cases of less than two locations. Ensure the metadata (if
234   // provided) is not dropped.
235   if (locs.empty()) {
236     if (!metadata)
237       return UnknownLoc::get(context);
238     // TODO: Investigate ASAN failure when using implicit conversion from
239     // Location to ArrayRef<Location> below.
240     return Base::get(context, ArrayRef<Location>{UnknownLoc::get(context)},
241                      metadata);
242   }
243   if (locs.size() == 1 && !metadata)
244     return locs.front();
245 
246   return Base::get(context, locs, metadata);
247 }
248 
249 //===----------------------------------------------------------------------===//
250 // BuiltinDialect
251 //===----------------------------------------------------------------------===//
252 
253 void BuiltinDialect::registerLocationAttributes() {
254   addAttributes<
255 #define GET_ATTRDEF_LIST
256 #include "mlir/IR/BuiltinLocationAttributes.cpp.inc"
257       >();
258 }
259