From 0a9f92168645c0d3bbaf1bd3834e671b03db6618 Mon Sep 17 00:00:00 2001 From: "Duncan P. N. Exon Smith" Date: Tue, 20 Jan 2015 00:01:43 +0000 Subject: [PATCH] IR: Introduce GenericDwarfNode As part of PR22235, introduce `DwarfNode` and `GenericDwarfNode`. The former is a metadata node with a DWARF tag. The latter matches our current (generic) schema of a header with string (and stringified integer) data and an arbitrary number of operands. This doesn't move it into place yet; that change will require a large number of testcase updates. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@226529 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/Metadata.def | 2 + include/llvm/IR/Metadata.h | 104 ++++++++++++++++++++++++++- lib/IR/AsmWriter.cpp | 6 ++ lib/IR/LLVMContextImpl.cpp | 6 +- lib/IR/LLVMContextImpl.h | 61 +++++++++++++--- lib/IR/Metadata.cpp | 45 ++++++++++-- lib/Transforms/Utils/ValueMapper.cpp | 8 +++ unittests/IR/MetadataTest.cpp | 35 +++++++++ 8 files changed, 249 insertions(+), 18 deletions(-) diff --git a/include/llvm/IR/Metadata.def b/include/llvm/IR/Metadata.def index 11705dd3beb..a8cf28a95bb 100644 --- a/include/llvm/IR/Metadata.def +++ b/include/llvm/IR/Metadata.def @@ -49,6 +49,8 @@ HANDLE_METADATA_LEAF(LocalAsMetadata) HANDLE_MDNODE_BRANCH(MDNode) HANDLE_MDNODE_LEAF(MDTuple) HANDLE_MDNODE_LEAF(MDLocation) +HANDLE_MDNODE_BRANCH(DwarfNode) +HANDLE_MDNODE_LEAF(GenericDwarfNode) #undef HANDLE_METADATA #undef HANDLE_METADATA_LEAF diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h index 13f6e5ad5d7..09ef18eb2be 100644 --- a/include/llvm/IR/Metadata.h +++ b/include/llvm/IR/Metadata.h @@ -61,6 +61,7 @@ public: enum MetadataKind { MDTupleKind, MDLocationKind, + GenericDwarfNodeKind, ConstantAsMetadataKind, LocalAsMetadataKind, MDStringKind @@ -704,7 +705,7 @@ protected: } MDNode(LLVMContext &Context, unsigned ID, StorageType Storage, - ArrayRef MDs); + ArrayRef Ops1, ArrayRef Ops2 = None); ~MDNode() {} void dropAllReferences(); @@ -847,7 +848,8 @@ 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() == MDLocationKind || + MD->getMetadataID() == GenericDwarfNodeKind; } /// \brief Check whether MDNode is a vtable access. @@ -989,6 +991,104 @@ public: } }; +/// \brief Tagged dwarf node. +/// +/// A metadata node with a DWARF tag. +class DwarfNode : public MDNode { + friend class LLVMContextImpl; + friend class MDNode; + +protected: + DwarfNode(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag, + ArrayRef Ops1, ArrayRef Ops2 = None) + : MDNode(C, ID, Storage, Ops1, Ops2) { + assert(Tag < 1u << 16); + SubclassData16 = Tag; + } + ~DwarfNode() {} + +public: + unsigned getTag() const { return SubclassData16; } + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == GenericDwarfNodeKind; + } +}; + +/// \brief Generic tagged dwarf node. +/// +/// A generic metadata node with a DWARF tag that doesn't have special +/// handling. +class GenericDwarfNode : public DwarfNode { + friend class LLVMContextImpl; + friend class MDNode; + + GenericDwarfNode(LLVMContext &C, StorageType Storage, unsigned Hash, + unsigned Tag, ArrayRef Ops1, + ArrayRef Ops2) + : DwarfNode(C, GenericDwarfNodeKind, Storage, Tag, Ops1, Ops2) { + setHash(Hash); + } + ~GenericDwarfNode() { dropAllReferences(); } + + void setHash(unsigned Hash) { SubclassData32 = Hash; } + void recalculateHash(); + + static GenericDwarfNode *getImpl(LLVMContext &Context, unsigned Tag, + MDString *Header, + ArrayRef DwarfOps, + StorageType Storage, + bool ShouldCreate = true); + +public: + unsigned getHash() const { return SubclassData32; } + + static GenericDwarfNode *get(LLVMContext &Context, + unsigned Tag, + MDString *Header, + ArrayRef DwarfOps) { + return getImpl(Context, Tag, Header, DwarfOps, Uniqued); + } + static GenericDwarfNode *getIfExists(LLVMContext &Context, unsigned Tag, + MDString *Header, + ArrayRef DwarfOps) { + return getImpl(Context, Tag, Header, DwarfOps, Uniqued, + /* ShouldCreate */ false); + } + static GenericDwarfNode *getDistinct(LLVMContext &Context, unsigned Tag, + MDString *Header, + ArrayRef DwarfOps) { + return getImpl(Context, Tag, Header, DwarfOps, Distinct); + } + static TempGenericDwarfNode getTemporary(LLVMContext &Context, unsigned Tag, + MDString *Header, + ArrayRef DwarfOps) { + return TempGenericDwarfNode( + getImpl(Context, Tag, Header, DwarfOps, Temporary)); + } + + unsigned getTag() const { return SubclassData16; } + MDString *getHeader() const { return cast_or_null(getOperand(0)); } + + op_iterator dwarf_op_begin() const { return op_begin() + 1; } + op_iterator dwarf_op_end() const { return op_end(); } + op_range dwarf_operands() const { + return op_range(dwarf_op_begin(), dwarf_op_end()); + } + + unsigned getNumDwarfOperands() const { return getNumOperands() - 1; } + const MDOperand &getDwarfOperand(unsigned I) const { + return getOperand(I + 1); + } + void replaceDwarfOperandWith(unsigned I, Metadata *New) { + replaceOperandWith(I + 1, New); + } + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == GenericDwarfNodeKind; + } +}; + //===----------------------------------------------------------------------===// /// \brief A tuple of MDNodes. /// diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index d9165437ec7..56355cc913c 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -1286,6 +1286,12 @@ raw_ostream &operator<<(raw_ostream &OS, FieldSeparator &FS) { } } // end namespace +static void writeGenericDwarfNode(raw_ostream &, const GenericDwarfNode *, + TypePrinting *, SlotTracker *, + const Module *) { + llvm_unreachable("Unimplemented write"); +} + static void writeMDLocation(raw_ostream &Out, const MDLocation *DL, TypePrinting *TypePrinter, SlotTracker *Machine, const Module *Context) { diff --git a/lib/IR/LLVMContextImpl.cpp b/lib/IR/LLVMContextImpl.cpp index 0c50a120d5d..81ff9a96f49 100644 --- a/lib/IR/LLVMContextImpl.cpp +++ b/lib/IR/LLVMContextImpl.cpp @@ -180,11 +180,11 @@ namespace llvm { static const Metadata *get_hashable_data(const MDOperand &X) { return X.get(); } } -unsigned MDNodeOpsKey::calculateHash(MDNode *N) { - unsigned Hash = hash_combine_range(N->op_begin(), N->op_end()); +unsigned MDNodeOpsKey::calculateHash(MDNode *N, unsigned Offset) { + unsigned Hash = hash_combine_range(N->op_begin() + Offset, N->op_end()); #ifndef NDEBUG { - SmallVector MDs(N->op_begin(), N->op_end()); + SmallVector MDs(N->op_begin() + Offset, N->op_end()); unsigned RawHash = calculateHash(MDs); assert(Hash == RawHash && "Expected hash of MDOperand to equal hash of Metadata*"); diff --git a/lib/IR/LLVMContextImpl.h b/lib/IR/LLVMContextImpl.h index 092104f6d0e..4604d9babb5 100644 --- a/lib/IR/LLVMContextImpl.h +++ b/lib/IR/LLVMContextImpl.h @@ -179,25 +179,27 @@ protected: : RawOps(Ops), Hash(calculateHash(Ops)) {} template - MDNodeOpsKey(NodeTy *N) - : Ops(N->op_begin(), N->op_end()), Hash(N->getHash()) {} + MDNodeOpsKey(NodeTy *N, unsigned Offset = 0) + : Ops(N->op_begin() + Offset, N->op_end()), Hash(N->getHash()) {} - template bool compareOps(const NodeTy *RHS) const { + template + bool compareOps(const NodeTy *RHS, unsigned Offset = 0) const { if (getHash() != RHS->getHash()) return false; assert((RawOps.empty() || Ops.empty()) && "Two sets of operands?"); - return RawOps.empty() ? compareOps(Ops, RHS) : compareOps(RawOps, RHS); + return RawOps.empty() ? compareOps(Ops, RHS, Offset) + : compareOps(RawOps, RHS, Offset); } - static unsigned calculateHash(MDNode *N); + static unsigned calculateHash(MDNode *N, unsigned Offset = 0); private: template - static bool compareOps(ArrayRef Ops, const MDNode *RHS) { - if (Ops.size() != RHS->getNumOperands()) + static bool compareOps(ArrayRef Ops, const MDNode *RHS, unsigned Offset) { + if (Ops.size() != RHS->getNumOperands() - Offset) return false; - return std::equal(Ops.begin(), Ops.end(), RHS->op_begin()); + return std::equal(Ops.begin(), Ops.end(), RHS->op_begin() + Offset); } static unsigned calculateHash(ArrayRef Ops); @@ -283,6 +285,48 @@ struct MDLocationInfo { } }; +/// \brief DenseMapInfo for GenericDwarfNode. +struct GenericDwarfNodeInfo { + struct KeyTy : MDNodeOpsKey { + unsigned Tag; + MDString *Header; + KeyTy(unsigned Tag, MDString *Header, ArrayRef DwarfOps) + : MDNodeOpsKey(DwarfOps), Tag(Tag), Header(Header) {} + KeyTy(GenericDwarfNode *N) + : MDNodeOpsKey(N, 1), Tag(N->getTag()), Header(N->getHeader()) {} + + bool operator==(const GenericDwarfNode *RHS) const { + if (RHS == getEmptyKey() || RHS == getTombstoneKey()) + return false; + return Tag == RHS->getTag() && Header == RHS->getHeader() && + compareOps(RHS, 1); + } + + static unsigned calculateHash(GenericDwarfNode *N) { + return MDNodeOpsKey::calculateHash(N, 1); + } + }; + static inline GenericDwarfNode *getEmptyKey() { + return DenseMapInfo::getEmptyKey(); + } + static inline GenericDwarfNode *getTombstoneKey() { + return DenseMapInfo::getTombstoneKey(); + } + static unsigned getHashValue(const KeyTy &Key) { + return hash_combine(Key.getHash(), Key.Tag, Key.Header); + } + static unsigned getHashValue(const GenericDwarfNode *U) { + return hash_combine(U->getHash(), U->getTag(), U->getHeader()); + } + static bool isEqual(const KeyTy &LHS, const GenericDwarfNode *RHS) { + return LHS == RHS; + } + static bool isEqual(const GenericDwarfNode *LHS, + const GenericDwarfNode *RHS) { + return LHS == RHS; + } +}; + class LLVMContextImpl { public: /// OwnedModules - The set of modules instantiated in this context, and which @@ -315,6 +359,7 @@ public: DenseSet MDTuples; DenseSet MDLocations; + DenseSet GenericDwarfNodes; // 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 0ce704c7c3d..5f5708565d4 100644 --- a/lib/IR/Metadata.cpp +++ b/lib/IR/Metadata.cpp @@ -397,11 +397,14 @@ void MDNode::operator delete(void *Mem) { } MDNode::MDNode(LLVMContext &Context, unsigned ID, StorageType Storage, - ArrayRef MDs) - : Metadata(ID, Storage), NumOperands(MDs.size()), NumUnresolved(0), - Context(Context) { - for (unsigned I = 0, E = MDs.size(); I != E; ++I) - setOperand(I, MDs[I]); + ArrayRef Ops1, ArrayRef Ops2) + : Metadata(ID, Storage), NumOperands(Ops1.size() + Ops2.size()), + NumUnresolved(0), Context(Context) { + unsigned Op = 0; + for (Metadata *MD : Ops1) + setOperand(Op++, MD); + for (Metadata *MD : Ops2) + setOperand(Op++, MD); if (isDistinct()) return; @@ -527,6 +530,10 @@ void MDTuple::recalculateHash() { setHash(MDTupleInfo::KeyTy::calculateHash(this)); } +void GenericDwarfNode::recalculateHash() { + setHash(GenericDwarfNodeInfo::KeyTy::calculateHash(this)); +} + void MDNode::dropAllReferences() { for (unsigned I = 0, E = NumOperands; I != E; ++I) setOperand(I, nullptr); @@ -621,6 +628,9 @@ MDNode *MDNode::uniquify() { case MDTupleKind: cast(this)->recalculateHash(); break; + case GenericDwarfNodeKind: + cast(this)->recalculateHash(); + break; } // Try to insert into uniquing store. @@ -733,6 +743,29 @@ MDLocation *MDLocation::getImpl(LLVMContext &Context, unsigned Line, Storage, Context.pImpl->MDLocations); } +GenericDwarfNode *GenericDwarfNode::getImpl(LLVMContext &Context, unsigned Tag, + MDString *Header, + ArrayRef DwarfOps, + StorageType Storage, + bool ShouldCreate) { + unsigned Hash = 0; + if (Storage == Uniqued) { + GenericDwarfNodeInfo::KeyTy Key(Tag, Header, DwarfOps); + if (auto *N = getUniqued(Context.pImpl->GenericDwarfNodes, Key)) + return N; + if (!ShouldCreate) + return nullptr; + Hash = Key.getHash(); + } else { + assert(ShouldCreate && "Expected non-uniqued nodes to always be created"); + } + + Metadata *PreOps[] = {Header}; + return storeImpl(new (DwarfOps.size() + 1) GenericDwarfNode( + Context, Storage, Hash, Tag, PreOps, DwarfOps), + Storage, Context.pImpl->GenericDwarfNodes); +} + void MDNode::deleteTemporary(MDNode *N) { assert(N->isTemporary() && "Expected temporary node"); N->deleteAsSubclass(); @@ -743,6 +776,8 @@ void MDNode::storeDistinctInContext() { Storage = Distinct; if (auto *T = dyn_cast(this)) T->setHash(0); + else if (auto *G = dyn_cast(this)) + G->setHash(0); getContext().pImpl->DistinctMDNodes.insert(this); } diff --git a/lib/Transforms/Utils/ValueMapper.cpp b/lib/Transforms/Utils/ValueMapper.cpp index 20ce27823fb..cba4677a2b0 100644 --- a/lib/Transforms/Utils/ValueMapper.cpp +++ b/lib/Transforms/Utils/ValueMapper.cpp @@ -192,6 +192,14 @@ static TempMDLocation cloneMDLocation(const MDLocation *Node) { Node->getInlinedAt()); } +static TempGenericDwarfNode +cloneGenericDwarfNode(const GenericDwarfNode *Node) { + SmallVector DwarfOps; + DwarfOps.append(Node->dwarf_op_begin(), Node->dwarf_op_end()); + return GenericDwarfNode::getTemporary(Node->getContext(), Node->getTag(), + Node->getHeader(), DwarfOps); +} + static TempMDNode cloneMDNode(const MDNode *Node) { switch (Node->getMetadataID()) { default: diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp index 730e8e87943..f2140d62172 100644 --- a/unittests/IR/MetadataTest.cpp +++ b/unittests/IR/MetadataTest.cpp @@ -561,6 +561,41 @@ TEST_F(MDLocationTest, getTemporary) { EXPECT_FALSE(L->isResolved()); } +typedef MetadataTest GenericDwarfNodeTest; + +TEST_F(GenericDwarfNodeTest, get) { + auto *Header = MDString::get(Context, "header"); + auto *Empty = MDNode::get(Context, None); + Metadata *Ops1[] = {Empty}; + auto *N = GenericDwarfNode::get(Context, 15, Header, Ops1); + EXPECT_EQ(15u, N->getTag()); + EXPECT_EQ(2u, N->getNumOperands()); + EXPECT_EQ(Header, N->getHeader()); + EXPECT_EQ(Header, N->getOperand(0)); + EXPECT_EQ(1u, N->getNumDwarfOperands()); + EXPECT_EQ(Empty, N->getDwarfOperand(0)); + EXPECT_EQ(Empty, N->getOperand(1)); + ASSERT_TRUE(N->isUniqued()); + + EXPECT_EQ(N, GenericDwarfNode::get(Context, 15, Header, Ops1)); + + N->replaceOperandWith(1, nullptr); + EXPECT_EQ(15u, N->getTag()); + EXPECT_EQ(Header, N->getHeader()); + EXPECT_EQ(nullptr, N->getDwarfOperand(0)); + ASSERT_TRUE(N->isUniqued()); + + Metadata *Ops2[] = {nullptr}; + EXPECT_EQ(N, GenericDwarfNode::get(Context, 15, Header, Ops2)); + + N->replaceDwarfOperandWith(0, Empty); + EXPECT_EQ(15u, N->getTag()); + EXPECT_EQ(Header, N->getHeader()); + EXPECT_EQ(Empty, N->getDwarfOperand(0)); + ASSERT_TRUE(N->isUniqued()); + EXPECT_EQ(N, GenericDwarfNode::get(Context, 15, Header, Ops1)); +} + typedef MetadataTest MetadataAsValueTest; TEST_F(MetadataAsValueTest, MDNode) {