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

source code of mlir/lib/IR/Location.cpp