IR: Introduce GenericDwarfNode
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>
Tue, 20 Jan 2015 00:01:43 +0000 (00:01 +0000)
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>
Tue, 20 Jan 2015 00:01:43 +0000 (00:01 +0000)
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
include/llvm/IR/Metadata.h
lib/IR/AsmWriter.cpp
lib/IR/LLVMContextImpl.cpp
lib/IR/LLVMContextImpl.h
lib/IR/Metadata.cpp
lib/Transforms/Utils/ValueMapper.cpp
unittests/IR/MetadataTest.cpp

index 11705dd3beb75bc2ceebaa8641e9e0297200b013..a8cf28a95bb73b493a6c3471f58cf5b1c5964a22 100644 (file)
@@ -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
index 13f6e5ad5d7bf4ec76b73f36e15ca3a5402114ec..09ef18eb2bef6bdadc2a579635f0edb5a5779f65 100644 (file)
@@ -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<Metadata *> MDs);
+         ArrayRef<Metadata *> Ops1, ArrayRef<Metadata *> 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<Metadata *> Ops1, ArrayRef<Metadata *> 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<Metadata *> Ops1,
+                   ArrayRef<Metadata *> 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<Metadata *> DwarfOps,
+                                   StorageType Storage,
+                                   bool ShouldCreate = true);
+
+public:
+  unsigned getHash() const { return SubclassData32; }
+
+  static GenericDwarfNode *get(LLVMContext &Context,
+                               unsigned Tag,
+                               MDString *Header,
+                               ArrayRef<Metadata *> DwarfOps) {
+    return getImpl(Context, Tag, Header, DwarfOps, Uniqued);
+  }
+  static GenericDwarfNode *getIfExists(LLVMContext &Context, unsigned Tag,
+                                       MDString *Header,
+                                       ArrayRef<Metadata *> DwarfOps) {
+    return getImpl(Context, Tag, Header, DwarfOps, Uniqued,
+                   /* ShouldCreate */ false);
+  }
+  static GenericDwarfNode *getDistinct(LLVMContext &Context, unsigned Tag,
+                                       MDString *Header,
+                                       ArrayRef<Metadata *> DwarfOps) {
+    return getImpl(Context, Tag, Header, DwarfOps, Distinct);
+  }
+  static TempGenericDwarfNode getTemporary(LLVMContext &Context, unsigned Tag,
+                                           MDString *Header,
+                                           ArrayRef<Metadata *> DwarfOps) {
+    return TempGenericDwarfNode(
+        getImpl(Context, Tag, Header, DwarfOps, Temporary));
+  }
+
+  unsigned getTag() const { return SubclassData16; }
+  MDString *getHeader() const { return cast_or_null<MDString>(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.
 ///
index d9165437ec718de483c4f46bc3968973ae47b234..56355cc913c09b447b7a96a8f143a8faa53a5c8f 100644 (file)
@@ -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) {
index 0c50a120d5dd4fddc1602325afb4e7413c2ffbff..81ff9a96f49d7fcca2a4bfa14b0ca6d20f3fd9d2 100644 (file)
@@ -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<Metadata *, 8> MDs(N->op_begin(), N->op_end());
+    SmallVector<Metadata *, 8> MDs(N->op_begin() + Offset, N->op_end());
     unsigned RawHash = calculateHash(MDs);
     assert(Hash == RawHash &&
            "Expected hash of MDOperand to equal hash of Metadata*");
index 092104f6d0ece2770388805c8528a058e7498a7c..4604d9babb54024a324cd5ef41b8e7a86e13ecf2 100644 (file)
@@ -179,25 +179,27 @@ protected:
       : RawOps(Ops), Hash(calculateHash(Ops)) {}
 
   template <class NodeTy>
-  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 <class NodeTy> bool compareOps(const NodeTy *RHS) const {
+  template <class NodeTy>
+  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 <class T>
-  static bool compareOps(ArrayRef<T> Ops, const MDNode *RHS) {
-    if (Ops.size() != RHS->getNumOperands())
+  static bool compareOps(ArrayRef<T> 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<Metadata *> 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<Metadata *> 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<GenericDwarfNode *>::getEmptyKey();
+  }
+  static inline GenericDwarfNode *getTombstoneKey() {
+    return DenseMapInfo<GenericDwarfNode *>::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<MDTuple *, MDTupleInfo> MDTuples;
   DenseSet<MDLocation *, MDLocationInfo> MDLocations;
+  DenseSet<GenericDwarfNode *, GenericDwarfNodeInfo> 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
index 0ce704c7c3d0c3a5a8b13b5e4d43a09e1b0295aa..5f5708565d443c2ae990052b4dfacca99c7dfd4e 100644 (file)
@@ -397,11 +397,14 @@ void MDNode::operator delete(void *Mem) {
 }
 
 MDNode::MDNode(LLVMContext &Context, unsigned ID, StorageType Storage,
-               ArrayRef<Metadata *> 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<Metadata *> Ops1, ArrayRef<Metadata *> 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<MDTuple>(this)->recalculateHash();
     break;
+  case GenericDwarfNodeKind:
+    cast<GenericDwarfNode>(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<Metadata *> 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<MDTuple>(this))
     T->setHash(0);
+  else if (auto *G = dyn_cast<GenericDwarfNode>(this))
+    G->setHash(0);
   getContext().pImpl->DistinctMDNodes.insert(this);
 }
 
index 20ce27823fb17d1fda81c3b1bc4bf357ff15be9a..cba4677a2b09d3fc5759a6bb228974ff348c0b52 100644 (file)
@@ -192,6 +192,14 @@ static TempMDLocation cloneMDLocation(const MDLocation *Node) {
                                   Node->getInlinedAt());
 }
 
+static TempGenericDwarfNode
+cloneGenericDwarfNode(const GenericDwarfNode *Node) {
+  SmallVector<Metadata *, 4> 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:
index 730e8e879433fd929b49b55497be11fa56152632..f2140d621723fd0e22fcf79663563d0e4109b94c 100644 (file)
@@ -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) {