xref: /llvm-project/mlir/lib/IR/Location.cpp (revision 3b35b4c7f9141c59fbac415e335489494b7d507e)
12fa4bc9fSRiver Riddle //===- Location.cpp - MLIR Location Classes -------------------------------===//
22fa4bc9fSRiver Riddle //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62fa4bc9fSRiver Riddle //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
82fa4bc9fSRiver Riddle 
92fa4bc9fSRiver Riddle #include "mlir/IR/Location.h"
1001e75646SJacques Pienaar #include "mlir/IR/AttributeSupport.h"
1101e75646SJacques Pienaar #include "mlir/IR/BuiltinAttributes.h"
1231bb8efdSRiver Riddle #include "mlir/IR/BuiltinDialect.h"
1301e75646SJacques Pienaar #include "mlir/IR/MLIRContext.h"
14706c9c5cSRiver Riddle #include "mlir/IR/Visitors.h"
1501e75646SJacques Pienaar #include "mlir/Support/LLVM.h"
1601e75646SJacques Pienaar #include "llvm/ADT/ArrayRef.h"
1701e75646SJacques Pienaar #include "llvm/ADT/Hashing.h"
1801e75646SJacques Pienaar #include "llvm/ADT/PointerIntPair.h"
1901e75646SJacques Pienaar #include "llvm/ADT/STLExtras.h"
2036b7c2daSRiver Riddle #include "llvm/ADT/SetVector.h"
21706c9c5cSRiver Riddle #include "llvm/ADT/TypeSwitch.h"
2201e75646SJacques Pienaar #include "llvm/Support/Casting.h"
2301e75646SJacques Pienaar #include "llvm/Support/TrailingObjects.h"
2401e75646SJacques Pienaar #include <cassert>
2501e75646SJacques Pienaar #include <iterator>
2601e75646SJacques Pienaar #include <memory>
2701e75646SJacques Pienaar #include <optional>
2801e75646SJacques Pienaar #include <tuple>
2901e75646SJacques Pienaar #include <utility>
302fa4bc9fSRiver Riddle 
312fa4bc9fSRiver Riddle using namespace mlir;
322fa4bc9fSRiver Riddle using namespace mlir::detail;
332fa4bc9fSRiver Riddle 
3401e75646SJacques Pienaar namespace mlir::detail {
3501e75646SJacques Pienaar struct FileLineColRangeAttrStorage final
3601e75646SJacques Pienaar     : public ::mlir::AttributeStorage,
3701e75646SJacques Pienaar       public llvm::TrailingObjects<FileLineColRangeAttrStorage, unsigned> {
3801e75646SJacques Pienaar   using PointerPair = llvm::PointerIntPair<StringAttr, 2>;
3901e75646SJacques Pienaar   using KeyTy = std::tuple<StringAttr, ::llvm::ArrayRef<unsigned>>;
4001e75646SJacques Pienaar 
4101e75646SJacques Pienaar   FileLineColRangeAttrStorage(StringAttr filename, int numLocs)
4201e75646SJacques Pienaar       : filenameAndTrailing(filename, numLocs) {}
4301e75646SJacques Pienaar 
4401e75646SJacques Pienaar   static FileLineColRangeAttrStorage *
4501e75646SJacques Pienaar   construct(::mlir::AttributeStorageAllocator &allocator, KeyTy &&tblgenKey) {
4601e75646SJacques Pienaar     auto numInArray = std::get<1>(tblgenKey).size();
4701e75646SJacques Pienaar     // Note: Considered asserting that numInArray is at least 1, but this
4801e75646SJacques Pienaar     // is not needed in memory or in printed form. This should very rarely be
4901e75646SJacques Pienaar     // 0 here as that means a NamedLoc would have been more efficient. But this
5001e75646SJacques Pienaar     // does allow for location with just a file, and also having the interface
5101e75646SJacques Pienaar     // be more uniform.
5201e75646SJacques Pienaar     auto locEnc = numInArray == 0 ? 1 : numInArray;
5301e75646SJacques Pienaar     // Allocate a new storage instance.
5401e75646SJacques Pienaar     auto byteSize =
5501e75646SJacques Pienaar         FileLineColRangeAttrStorage::totalSizeToAlloc<unsigned>(locEnc - 1);
5601e75646SJacques Pienaar     auto *rawMem =
5701e75646SJacques Pienaar         allocator.allocate(byteSize, alignof(FileLineColRangeAttrStorage));
5801e75646SJacques Pienaar     auto *result = ::new (rawMem) FileLineColRangeAttrStorage(
5901e75646SJacques Pienaar         std::move(std::get<0>(tblgenKey)), locEnc - 1);
6001e75646SJacques Pienaar     if (numInArray > 0) {
6101e75646SJacques Pienaar       result->startLine = std::get<1>(tblgenKey)[0];
6201e75646SJacques Pienaar       // Copy in the element types into the trailing storage.
6301e75646SJacques Pienaar       std::uninitialized_copy(std::next(std::get<1>(tblgenKey).begin()),
6401e75646SJacques Pienaar                               std::get<1>(tblgenKey).end(),
6501e75646SJacques Pienaar                               result->getTrailingObjects<unsigned>());
6601e75646SJacques Pienaar     }
6701e75646SJacques Pienaar     return result;
6801e75646SJacques Pienaar   }
6901e75646SJacques Pienaar 
7001e75646SJacques Pienaar   // Return the number of held types.
7101e75646SJacques Pienaar   unsigned size() const { return filenameAndTrailing.getInt() + 1; }
7201e75646SJacques Pienaar 
7301e75646SJacques Pienaar   bool operator==(const KeyTy &tblgenKey) const {
7401e75646SJacques Pienaar     return (filenameAndTrailing.getPointer() == std::get<0>(tblgenKey)) &&
7501e75646SJacques Pienaar            (size() == std::get<1>(tblgenKey).size()) &&
7601e75646SJacques Pienaar            (startLine == std::get<1>(tblgenKey)[0]) &&
7701e75646SJacques Pienaar            (ArrayRef<unsigned>{getTrailingObjects<unsigned>(), size() - 1} ==
7801e75646SJacques Pienaar             ArrayRef<unsigned>{std::get<1>(tblgenKey)}.drop_front());
7901e75646SJacques Pienaar   }
8001e75646SJacques Pienaar 
8101e75646SJacques Pienaar   unsigned getLineCols(unsigned index) const {
8201e75646SJacques Pienaar     return getTrailingObjects<unsigned>()[index - 1];
8301e75646SJacques Pienaar   }
8401e75646SJacques Pienaar 
8501e75646SJacques Pienaar   unsigned getStartLine() const { return startLine; }
8601e75646SJacques Pienaar   unsigned getStartColumn() const {
8701e75646SJacques Pienaar     if (size() <= 1)
8801e75646SJacques Pienaar       return 0;
8901e75646SJacques Pienaar     return getLineCols(1);
9001e75646SJacques Pienaar   }
9101e75646SJacques Pienaar   unsigned getEndColumn() const {
9201e75646SJacques Pienaar     if (size() <= 2)
9301e75646SJacques Pienaar       return getStartColumn();
9401e75646SJacques Pienaar     return getLineCols(2);
9501e75646SJacques Pienaar   }
9601e75646SJacques Pienaar   unsigned getEndLine() const {
9701e75646SJacques Pienaar     if (size() <= 3)
9801e75646SJacques Pienaar       return getStartLine();
9901e75646SJacques Pienaar     return getLineCols(3);
10001e75646SJacques Pienaar   }
10101e75646SJacques Pienaar 
10201e75646SJacques Pienaar   static ::llvm::hash_code hashKey(const KeyTy &tblgenKey) {
10301e75646SJacques Pienaar     return ::llvm::hash_combine(std::get<0>(tblgenKey), std::get<1>(tblgenKey));
10401e75646SJacques Pienaar   }
10501e75646SJacques Pienaar 
10601e75646SJacques Pienaar   // Supports
10701e75646SJacques Pienaar   //  - 0 (file:line)
10801e75646SJacques Pienaar   //  - 1 (file:line:col)
10901e75646SJacques Pienaar   //  - 2 (file:line:start_col to file:line:end_col) and
11001e75646SJacques Pienaar   //  - 3 (file:start_line:start_col to file:end_line:end_col)
11101e75646SJacques Pienaar   llvm::PointerIntPair<StringAttr, 2> filenameAndTrailing;
11201e75646SJacques Pienaar   unsigned startLine = 0;
11301e75646SJacques Pienaar };
11401e75646SJacques Pienaar } // namespace mlir::detail
11501e75646SJacques Pienaar 
116e18a55f1SRiver Riddle //===----------------------------------------------------------------------===//
117a4bb667dSRiver Riddle /// Tablegen Attribute Definitions
118a4bb667dSRiver Riddle //===----------------------------------------------------------------------===//
119a4bb667dSRiver Riddle 
120a4bb667dSRiver Riddle #define GET_ATTRDEF_CLASSES
121a4bb667dSRiver Riddle #include "mlir/IR/BuiltinLocationAttributes.cpp.inc"
122a4bb667dSRiver Riddle 
123a4bb667dSRiver Riddle //===----------------------------------------------------------------------===//
124fff39b62SRiver Riddle // LocationAttr
125fff39b62SRiver Riddle //===----------------------------------------------------------------------===//
126fff39b62SRiver Riddle 
127706c9c5cSRiver Riddle WalkResult LocationAttr::walk(function_ref<WalkResult(Location)> walkFn) {
128759a7b59SAman LaChapelle   AttrTypeWalker walker;
129759a7b59SAman LaChapelle   // Walk locations, but skip any other attribute.
130759a7b59SAman LaChapelle   walker.addWalk([&](Attribute attr) {
131759a7b59SAman LaChapelle     if (auto loc = llvm::dyn_cast<LocationAttr>(attr))
132759a7b59SAman LaChapelle       return walkFn(loc);
133706c9c5cSRiver Riddle 
134759a7b59SAman LaChapelle     return WalkResult::skip();
135759a7b59SAman LaChapelle   });
136759a7b59SAman LaChapelle   return walker.walk<WalkOrder::PreOrder>(*this);
137706c9c5cSRiver Riddle }
138706c9c5cSRiver Riddle 
139fff39b62SRiver Riddle /// Methods for support type inquiry through isa, cast, and dyn_cast.
140fff39b62SRiver Riddle bool LocationAttr::classof(Attribute attr) {
141759a7b59SAman LaChapelle   return attr.hasTrait<AttributeTrait::IsLocation>();
142fff39b62SRiver Riddle }
143fff39b62SRiver Riddle 
144fff39b62SRiver Riddle //===----------------------------------------------------------------------===//
145e18a55f1SRiver Riddle // CallSiteLoc
146e18a55f1SRiver Riddle //===----------------------------------------------------------------------===//
147e18a55f1SRiver Riddle 
148a4bb667dSRiver Riddle CallSiteLoc CallSiteLoc::get(Location name, ArrayRef<Location> frames) {
14923251f9fSRiver Riddle   assert(!frames.empty() && "required at least 1 call frame");
150e18a55f1SRiver Riddle   Location caller = frames.back();
151e18a55f1SRiver Riddle   for (auto frame : llvm::reverse(frames.drop_back()))
15223251f9fSRiver Riddle     caller = CallSiteLoc::get(frame, caller);
15323251f9fSRiver Riddle   return CallSiteLoc::get(name, caller);
154e18a55f1SRiver Riddle }
15563068da4SFeng Liu 
156e18a55f1SRiver Riddle //===----------------------------------------------------------------------===//
15701e75646SJacques Pienaar // FileLineColLoc
15801e75646SJacques Pienaar //===----------------------------------------------------------------------===//
15901e75646SJacques Pienaar 
16001e75646SJacques Pienaar FileLineColLoc FileLineColLoc::get(StringAttr filename, unsigned line,
16101e75646SJacques Pienaar                                    unsigned column) {
16201e75646SJacques Pienaar   return llvm::cast<FileLineColLoc>(
16301e75646SJacques Pienaar       FileLineColRange::get(filename, line, column));
16401e75646SJacques Pienaar }
16501e75646SJacques Pienaar 
16601e75646SJacques Pienaar FileLineColLoc FileLineColLoc::get(MLIRContext *context, StringRef fileName,
16701e75646SJacques Pienaar                                    unsigned line, unsigned column) {
16801e75646SJacques Pienaar   return llvm::cast<FileLineColLoc>(
16901e75646SJacques Pienaar       FileLineColRange::get(context, fileName, line, column));
17001e75646SJacques Pienaar }
17101e75646SJacques Pienaar 
17201e75646SJacques Pienaar StringAttr FileLineColLoc::getFilename() const {
17301e75646SJacques Pienaar   return FileLineColRange::getFilename();
17401e75646SJacques Pienaar }
17501e75646SJacques Pienaar 
17601e75646SJacques Pienaar unsigned FileLineColLoc::getLine() const { return getStartLine(); }
17701e75646SJacques Pienaar 
17801e75646SJacques Pienaar unsigned FileLineColLoc::getColumn() const { return getStartColumn(); }
17901e75646SJacques Pienaar 
180*3b35b4c7SJacques Pienaar bool mlir::isStrictFileLineColLoc(Location loc) {
181*3b35b4c7SJacques Pienaar   if (auto range = mlir::dyn_cast<FileLineColRange>(loc))
18201e75646SJacques Pienaar     return range.getImpl()->size() == 2;
18301e75646SJacques Pienaar   return false;
18401e75646SJacques Pienaar }
18501e75646SJacques Pienaar 
18601e75646SJacques Pienaar //===----------------------------------------------------------------------===//
18701e75646SJacques Pienaar // FileLineColRange
18801e75646SJacques Pienaar //===----------------------------------------------------------------------===//
18901e75646SJacques Pienaar 
19001e75646SJacques Pienaar StringAttr FileLineColRange::getFilename() const {
19101e75646SJacques Pienaar   return getImpl()->filenameAndTrailing.getPointer();
19201e75646SJacques Pienaar }
19301e75646SJacques Pienaar 
19401e75646SJacques Pienaar unsigned FileLineColRange::getStartLine() const {
19501e75646SJacques Pienaar   return getImpl()->getStartLine();
19601e75646SJacques Pienaar }
19701e75646SJacques Pienaar unsigned FileLineColRange::getStartColumn() const {
19801e75646SJacques Pienaar   return getImpl()->getStartColumn();
19901e75646SJacques Pienaar }
20001e75646SJacques Pienaar unsigned FileLineColRange::getEndColumn() const {
20101e75646SJacques Pienaar   return getImpl()->getEndColumn();
20201e75646SJacques Pienaar }
20301e75646SJacques Pienaar unsigned FileLineColRange::getEndLine() const {
20401e75646SJacques Pienaar   return getImpl()->getEndLine();
20501e75646SJacques Pienaar }
20601e75646SJacques Pienaar 
20701e75646SJacques Pienaar //===----------------------------------------------------------------------===//
208e18a55f1SRiver Riddle // FusedLoc
209e18a55f1SRiver Riddle //===----------------------------------------------------------------------===//
210e18a55f1SRiver Riddle 
21149162524SRiver Riddle Location FusedLoc::get(ArrayRef<Location> locs, Attribute metadata,
21236b7c2daSRiver Riddle                        MLIRContext *context) {
21336b7c2daSRiver Riddle   // Unique the set of locations to be fused.
21436b7c2daSRiver Riddle   llvm::SmallSetVector<Location, 4> decomposedLocs;
21536b7c2daSRiver Riddle   for (auto loc : locs) {
21636b7c2daSRiver Riddle     // If the location is a fused location we decompose it if it has no
21736b7c2daSRiver Riddle     // metadata or the metadata is the same as the top level metadata.
21818066b52SNick Kreeger     if (auto fusedLoc = llvm::dyn_cast<FusedLoc>(loc)) {
21936b7c2daSRiver Riddle       if (fusedLoc.getMetadata() == metadata) {
22036b7c2daSRiver Riddle         // UnknownLoc's have already been removed from FusedLocs so we can
22136b7c2daSRiver Riddle         // simply add all of the internal locations.
22236b7c2daSRiver Riddle         decomposedLocs.insert(fusedLoc.getLocations().begin(),
22336b7c2daSRiver Riddle                               fusedLoc.getLocations().end());
22436b7c2daSRiver Riddle         continue;
22536b7c2daSRiver Riddle       }
22636b7c2daSRiver Riddle     }
22736b7c2daSRiver Riddle     // Otherwise, only add known locations to the set.
228c1fa60b4STres Popp     if (!llvm::isa<UnknownLoc>(loc))
22936b7c2daSRiver Riddle       decomposedLocs.insert(loc);
23036b7c2daSRiver Riddle   }
23136b7c2daSRiver Riddle   locs = decomposedLocs.getArrayRef();
23236b7c2daSRiver Riddle 
2339e365fe3SJacques Pienaar   // Handle the simple cases of less than two locations. Ensure the metadata (if
2349e365fe3SJacques Pienaar   // provided) is not dropped.
2359e365fe3SJacques Pienaar   if (locs.empty()) {
2369e365fe3SJacques Pienaar     if (!metadata)
23736b7c2daSRiver Riddle       return UnknownLoc::get(context);
2389e365fe3SJacques Pienaar     // TODO: Investigate ASAN failure when using implicit conversion from
2399e365fe3SJacques Pienaar     // Location to ArrayRef<Location> below.
2409e365fe3SJacques Pienaar     return Base::get(context, ArrayRef<Location>{UnknownLoc::get(context)},
2419e365fe3SJacques Pienaar                      metadata);
2429e365fe3SJacques Pienaar   }
2439e365fe3SJacques Pienaar   if (locs.size() == 1 && !metadata)
24436b7c2daSRiver Riddle     return locs.front();
2459e365fe3SJacques Pienaar 
246250f43d3SRiver Riddle   return Base::get(context, locs, metadata);
247e18a55f1SRiver Riddle }
24801e75646SJacques Pienaar 
24901e75646SJacques Pienaar //===----------------------------------------------------------------------===//
25001e75646SJacques Pienaar // BuiltinDialect
25101e75646SJacques Pienaar //===----------------------------------------------------------------------===//
25201e75646SJacques Pienaar 
25301e75646SJacques Pienaar void BuiltinDialect::registerLocationAttributes() {
25401e75646SJacques Pienaar   addAttributes<
25501e75646SJacques Pienaar #define GET_ATTRDEF_LIST
25601e75646SJacques Pienaar #include "mlir/IR/BuiltinLocationAttributes.cpp.inc"
25701e75646SJacques Pienaar       >();
25801e75646SJacques Pienaar }
259