diff --git a/include/llvm/IR/Metadata.def b/include/llvm/IR/Metadata.def index 2d5d91eb12a..2098bb57eb5 100644 --- a/include/llvm/IR/Metadata.def +++ b/include/llvm/IR/Metadata.def @@ -50,6 +50,7 @@ HANDLE_METADATA_BRANCH(MDNode) HANDLE_METADATA_LEAF(MDNodeFwdDecl) HANDLE_UNIQUABLE_BRANCH(UniquableMDNode) HANDLE_UNIQUABLE_LEAF(MDTuple) +HANDLE_UNIQUABLE_LEAF(MDLocation) #undef HANDLE_METADATA #undef HANDLE_METADATA_LEAF diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h index da6521bbf3e..10fc99f7b11 100644 --- a/include/llvm/IR/Metadata.h +++ b/include/llvm/IR/Metadata.h @@ -57,6 +57,7 @@ protected: public: enum MetadataKind { MDTupleKind, + MDLocationKind, MDNodeFwdDeclKind, ConstantAsMetadataKind, LocalAsMetadataKind, @@ -670,6 +671,7 @@ public: /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const Metadata *MD) { return MD->getMetadataID() == MDTupleKind || + MD->getMetadataID() == MDLocationKind || MD->getMetadataID() == MDNodeFwdDeclKind; } @@ -726,7 +728,8 @@ protected: public: static bool classof(const Metadata *MD) { - return MD->getMetadataID() == MDTupleKind; + return MD->getMetadataID() == MDTupleKind || + MD->getMetadataID() == MDLocationKind; } /// \brief Check whether any operands are forward declarations. @@ -812,6 +815,60 @@ MDNode *MDNode::getDistinct(LLVMContext &Context, ArrayRef MDs) { return MDTuple::getDistinct(Context, MDs); } +/// \brief Debug location. +/// +/// A debug location in source code, used for debug info and otherwise. +class MDLocation : public UniquableMDNode { + friend class LLVMContextImpl; + friend class UniquableMDNode; + + MDLocation(LLVMContext &C, unsigned Line, unsigned Column, + ArrayRef MDs, bool AllowRAUW); + ~MDLocation() { dropAllReferences(); } + + static MDLocation *constructHelper(LLVMContext &Context, unsigned Line, + unsigned Column, Metadata *Scope, + Metadata *InlinedAt, bool AllowRAUW); + + static MDLocation *getImpl(LLVMContext &Context, unsigned Line, + unsigned Column, Metadata *Scope, + Metadata *InlinedAt, bool ShouldCreate); + + // Disallow replacing operands. + void replaceOperandWith(unsigned I, Metadata *New) LLVM_DELETED_FUNCTION; + +public: + static MDLocation *get(LLVMContext &Context, unsigned Line, unsigned Column, + Metadata *Scope, Metadata *InlinedAt = nullptr) { + return getImpl(Context, Line, Column, Scope, InlinedAt, + /* ShouldCreate */ true); + } + static MDLocation *getIfExists(LLVMContext &Context, unsigned Line, + unsigned Column, Metadata *Scope, + Metadata *InlinedAt = nullptr) { + return getImpl(Context, Line, Column, Scope, InlinedAt, + /* ShouldCreate */ false); + } + static MDLocation *getDistinct(LLVMContext &Context, unsigned Line, + unsigned Column, Metadata *Scope, + Metadata *InlinedAt = nullptr); + + unsigned getLine() const { return MDNodeSubclassData; } + unsigned getColumn() const { return SubclassData16; } + Metadata *getScope() const { return getOperand(0); } + Metadata *getInlinedAt() const { + return getNumOperands() == 2 ? getOperand(1) : nullptr; + } + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == MDLocationKind; + } + +private: + MDLocation *uniquifyImpl(); + void eraseFromStoreImpl(); +}; + /// \brief Forward declaration of metadata. /// /// Forward declaration of metadata, in the form of a basic tuple. Unlike \a diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index ea7e0aa5266..215332b8256 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -1272,6 +1272,39 @@ static void writeMDTuple(raw_ostream &Out, const MDTuple *Node, Out << "}"; } +namespace { +struct FieldSeparator { + bool Skip; + FieldSeparator() : Skip(true) {} +}; +raw_ostream &operator<<(raw_ostream &OS, FieldSeparator &FS) { + if (FS.Skip) { + FS.Skip = false; + return OS; + } + return OS << ", "; +} +} // end namespace + +static void writeMDLocation(raw_ostream &Out, const MDLocation *DL, + TypePrinting *TypePrinter, SlotTracker *Machine, + const Module *Context) { + Out << "!MDLocation("; + FieldSeparator FS; + if (DL->getLine()) + Out << FS << "line: " << DL->getLine(); + if (DL->getColumn()) + Out << FS << "column: " << DL->getColumn(); + Out << FS << "scope: "; + WriteAsOperandInternal(Out, DL->getScope(), TypePrinter, Machine, Context); + if (DL->getInlinedAt()) { + Out << FS << "inlinedAt: "; + WriteAsOperandInternal(Out, DL->getInlinedAt(), TypePrinter, Machine, + Context); + } + Out << ")"; +} + static void WriteMDNodeBodyInternal(raw_ostream &Out, const MDNode *Node, TypePrinting *TypePrinter, SlotTracker *Machine, diff --git a/lib/IR/LLVMContextImpl.cpp b/lib/IR/LLVMContextImpl.cpp index d47a0d332fb..1fa080b8133 100644 --- a/lib/IR/LLVMContextImpl.cpp +++ b/lib/IR/LLVMContextImpl.cpp @@ -140,11 +140,15 @@ LLVMContextImpl::~LLVMContextImpl() { I->dropAllReferences(); for (auto *I : MDTuples) I->dropAllReferences(); + for (auto *I : MDLocations) + I->dropAllReferences(); for (UniquableMDNode *I : DistinctMDNodes) I->deleteAsSubclass(); for (MDTuple *I : MDTuples) delete I; + for (MDLocation *I : MDLocations) + delete I; // Destroy MDStrings. MDStringCache.clear(); diff --git a/lib/IR/LLVMContextImpl.h b/lib/IR/LLVMContextImpl.h index 11b8d38f9af..6ebc567f808 100644 --- a/lib/IR/LLVMContextImpl.h +++ b/lib/IR/LLVMContextImpl.h @@ -215,6 +215,48 @@ struct MDTupleInfo { } }; +/// \brief DenseMapInfo for MDLocation. +struct MDLocationInfo { + struct KeyTy { + unsigned Line; + unsigned Column; + Metadata *Scope; + Metadata *InlinedAt; + + KeyTy(unsigned Line, unsigned Column, Metadata *Scope, Metadata *InlinedAt) + : Line(Line), Column(Column), Scope(Scope), InlinedAt(InlinedAt) {} + + KeyTy(const MDLocation *L) + : Line(L->getLine()), Column(L->getColumn()), Scope(L->getScope()), + InlinedAt(L->getInlinedAt()) {} + + bool operator==(const MDLocation *RHS) const { + if (RHS == getEmptyKey() || RHS == getTombstoneKey()) + return false; + return Line == RHS->getLine() && Column == RHS->getColumn() && + Scope == RHS->getScope() && InlinedAt == RHS->getInlinedAt(); + } + }; + static inline MDLocation *getEmptyKey() { + return DenseMapInfo::getEmptyKey(); + } + static inline MDLocation *getTombstoneKey() { + return DenseMapInfo::getTombstoneKey(); + } + static unsigned getHashValue(const KeyTy &Key) { + return hash_combine(Key.Line, Key.Column, Key.Scope, Key.InlinedAt); + } + static unsigned getHashValue(const MDLocation *U) { + return getHashValue(KeyTy(U)); + } + static bool isEqual(const KeyTy &LHS, const MDLocation *RHS) { + return LHS == RHS; + } + static bool isEqual(const MDLocation *LHS, const MDLocation *RHS) { + return LHS == RHS; + } +}; + class LLVMContextImpl { public: /// OwnedModules - The set of modules instantiated in this context, and which @@ -246,6 +288,7 @@ public: DenseMap MetadataAsValues; DenseSet MDTuples; + DenseSet MDLocations; // MDNodes may be uniqued or not uniqued. When they're not uniqued, they // aren't in the MDNodeSet, but they're still shared between objects, so no diff --git a/lib/IR/Metadata.cpp b/lib/IR/Metadata.cpp index 852f1dc2041..ab83252bfda 100644 --- a/lib/IR/Metadata.cpp +++ b/lib/IR/Metadata.cpp @@ -640,6 +640,93 @@ MDTuple *MDTuple::uniquifyImpl() { void MDTuple::eraseFromStoreImpl() { getContext().pImpl->MDTuples.erase(this); } +MDLocation::MDLocation(LLVMContext &C, unsigned Line, unsigned Column, + ArrayRef MDs, bool AllowRAUW) + : UniquableMDNode(C, MDLocationKind, MDs, AllowRAUW) { + assert((MDs.size() == 1 || MDs.size() == 2) && + "Expected a scope and optional inlined-at"); + + // Set line and column. + assert(Line < (1u << 24) && "Expected 24-bit line"); + assert(Column < (1u << 8) && "Expected 8-bit column"); + + MDNodeSubclassData = Line; + SubclassData16 = Column; +} + +MDLocation *MDLocation::constructHelper(LLVMContext &Context, unsigned Line, + unsigned Column, Metadata *Scope, + Metadata *InlinedAt, bool AllowRAUW) { + SmallVector Ops; + Ops.push_back(Scope); + if (InlinedAt) + Ops.push_back(InlinedAt); + return new (Ops.size()) MDLocation(Context, Line, Column, Ops, AllowRAUW); +} + +static void adjustLine(unsigned &Line) { + // Set to unknown on overflow. Still use 24 bits for now. + if (Line >= (1u << 24)) + Line = 0; +} + +static void adjustColumn(unsigned &Column) { + // Set to unknown on overflow. Still use 8 bits for now. + if (Column >= (1u << 8)) + Column = 0; +} + +MDLocation *MDLocation::getImpl(LLVMContext &Context, unsigned Line, + unsigned Column, Metadata *Scope, + Metadata *InlinedAt, bool ShouldCreate) { + // Fixup line/column. + adjustLine(Line); + adjustColumn(Column); + + MDLocationInfo::KeyTy Key(Line, Column, Scope, InlinedAt); + + auto &Store = Context.pImpl->MDLocations; + auto I = Store.find_as(Key); + if (I != Store.end()) + return *I; + if (!ShouldCreate) + return nullptr; + + auto *N = constructHelper(Context, Line, Column, Scope, InlinedAt, + /* AllowRAUW */ true); + Store.insert(N); + return N; +} + +MDLocation *MDLocation::getDistinct(LLVMContext &Context, unsigned Line, + unsigned Column, Metadata *Scope, + Metadata *InlinedAt) { + // Fixup line/column. + adjustLine(Line); + adjustColumn(Column); + + auto *N = constructHelper(Context, Line, Column, Scope, InlinedAt, + /* AllowRAUW */ false); + N->storeDistinctInContext(); + return N; +} + +MDLocation *MDLocation::uniquifyImpl() { + MDLocationInfo::KeyTy Key(this); + + auto &Store = getContext().pImpl->MDLocations; + auto I = Store.find_as(Key); + if (I == Store.end()) { + Store.insert(this); + return this; + } + return *I; +} + +void MDLocation::eraseFromStoreImpl() { + getContext().pImpl->MDLocations.erase(this); +} + MDNodeFwdDecl *MDNode::getTemporary(LLVMContext &Context, ArrayRef MDs) { return MDNodeFwdDecl::get(Context, MDs); @@ -650,9 +737,9 @@ void MDNode::deleteTemporary(MDNode *N) { delete cast(N); } void UniquableMDNode::storeDistinctInContext() { assert(!IsDistinctInContext && "Expected newly distinct metadata"); IsDistinctInContext = true; - auto *T = cast(this); - T->setHash(0); - getContext().pImpl->DistinctMDNodes.insert(T); + if (auto *T = dyn_cast(this)) + T->setHash(0); + getContext().pImpl->DistinctMDNodes.insert(this); } void MDNode::replaceOperandWith(unsigned I, Metadata *New) { diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp index 9f5d133943b..8c5c312a2f7 100644 --- a/unittests/IR/MetadataTest.cpp +++ b/unittests/IR/MetadataTest.cpp @@ -387,6 +387,43 @@ TEST_F(MDNodeTest, replaceResolvedOperand) { Temp->replaceAllUsesWith(nullptr); } +typedef MetadataTest MDLocationTest; + +TEST_F(MDLocationTest, Overflow) { + MDNode *N = MDNode::get(Context, None); + { + MDLocation *L = MDLocation::get(Context, 2, 7, N); + EXPECT_EQ(2u, L->getLine()); + EXPECT_EQ(7u, L->getColumn()); + } + unsigned U24 = 1u << 24; + unsigned U8 = 1u << 8; + { + MDLocation *L = MDLocation::get(Context, U24 - 1, U8 - 1, N); + EXPECT_EQ(U24 - 1, L->getLine()); + EXPECT_EQ(U8 - 1, L->getColumn()); + } + { + MDLocation *L = MDLocation::get(Context, U24, U8, N); + EXPECT_EQ(0u, L->getLine()); + EXPECT_EQ(0u, L->getColumn()); + } + { + MDLocation *L = MDLocation::get(Context, U24 + 1, U8 + 1, N); + EXPECT_EQ(0u, L->getLine()); + EXPECT_EQ(0u, L->getColumn()); + } +} + +TEST_F(MDLocationTest, getDistinct) { + MDNode *N = MDNode::get(Context, None); + MDLocation *L0 = MDLocation::getDistinct(Context, 2, 7, N); + EXPECT_TRUE(L0->isDistinct()); + MDLocation *L1 = MDLocation::get(Context, 2, 7, N); + EXPECT_FALSE(L1->isDistinct()); + EXPECT_EQ(L1, MDLocation::get(Context, 2, 7, N)); +} + typedef MetadataTest MetadataAsValueTest; TEST_F(MetadataAsValueTest, MDNode) {