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