DI: Add Function::getSubprogram()
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>
Fri, 28 Aug 2015 21:55:35 +0000 (21:55 +0000)
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>
Fri, 28 Aug 2015 21:55:35 +0000 (21:55 +0000)
Add `Function::setSubprogram()` and `Function::getSubprogram()`,
convenience methods to forward to `setMetadata()` and `getMetadata()`,
respectively, and deal in `DISubprogram` instead of `MDNode`.

Also add a verifier check to enforce that `!dbg` attachments are always
subprograms.

Originally (when I had the llvm-dev discussion back in April) I thought
I'd store a pointer directly on `llvm::Function` for these attachments
-- we frequently have debug info, and that's much cheaper than using map
in the context if there are no other function-level attachments -- but
for now I'm just using the generic infrastructure.  Let's add the extra
complexity only if this shows up in a profile.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@246339 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/IR/Function.h
lib/IR/Metadata.cpp
lib/IR/Verifier.cpp
test/Verifier/metadata-function-dbg.ll [new file with mode: 0644]
unittests/IR/MetadataTest.cpp

index ef7274b4bc66b8ec69095171ecb2597a6c4626cc..69c622cc9a828eda2c09747c6e5c8b5837ca7e16 100644 (file)
@@ -32,6 +32,7 @@ namespace llvm {
 
 class FunctionType;
 class LLVMContext;
 
 class FunctionType;
 class LLVMContext;
+class DISubprogram;
 
 template<> struct ilist_traits<Argument>
   : public SymbolTableListTraits<Argument, Function> {
 
 template<> struct ilist_traits<Argument>
   : public SymbolTableListTraits<Argument, Function> {
@@ -606,6 +607,17 @@ public:
   /// Drop all metadata from \c this not included in \c KnownIDs.
   void dropUnknownMetadata(ArrayRef<unsigned> KnownIDs);
 
   /// Drop all metadata from \c this not included in \c KnownIDs.
   void dropUnknownMetadata(ArrayRef<unsigned> KnownIDs);
 
+  /// \brief Set the attached subprogram.
+  ///
+  /// Calls \a setMetadata() with \a LLVMContext::MD_dbg.
+  void setSubprogram(DISubprogram *SP);
+
+  /// \brief Get the attached subprogram.
+  ///
+  /// Calls \a getMetadata() with \a LLVMContext::MD_dbg and casts the result
+  /// to \a DISubprogram.
+  DISubprogram *getSubprogram() const;
+
 private:
   // Shadow Value::setValueSubclassData with a private forwarding method so that
   // subclasses cannot accidentally use it.
 private:
   // Shadow Value::setValueSubclassData with a private forwarding method so that
   // subclasses cannot accidentally use it.
index 431fee1b7b7d556ff47bd3379abcbfb4eac1fc2a..7d8c352374316d47fe56956e4f18e6aee71b83da 100644 (file)
@@ -1259,3 +1259,11 @@ void Function::clearMetadata() {
   getContext().pImpl->FunctionMetadata.erase(this);
   setHasMetadataHashEntry(false);
 }
   getContext().pImpl->FunctionMetadata.erase(this);
   setHasMetadataHashEntry(false);
 }
+
+void Function::setSubprogram(DISubprogram *SP) {
+  setMetadata(LLVMContext::MD_dbg, SP);
+}
+
+DISubprogram *Function::getSubprogram() const {
+  return cast_or_null<DISubprogram>(getMetadata(LLVMContext::MD_dbg));
+}
index c8aba14e8132e139f4dc4282d99dcb0cf3ba4b98..bcf8c0ffa1eea9e4eb13c38550aaa6d1fd0bfa11 100644 (file)
@@ -1779,8 +1779,20 @@ void Verifier::visitFunction(const Function &F) {
     }
 
     // Visit metadata attachments.
     }
 
     // Visit metadata attachments.
-    for (const auto &I : MDs)
+    for (const auto &I : MDs) {
+      // Verify that the attachment is legal.
+      switch (I.first) {
+      default:
+        break;
+      case LLVMContext::MD_dbg:
+        Assert(isa<DISubprogram>(I.second),
+               "function !dbg attachment must be a subprogram", &F, I.second);
+        break;
+      }
+
+      // Verify the metadata itself.
       visitMDNode(*I.second);
       visitMDNode(*I.second);
+    }
   }
 
   // If this function is actually an intrinsic, verify that it is only used in
   }
 
   // If this function is actually an intrinsic, verify that it is only used in
diff --git a/test/Verifier/metadata-function-dbg.ll b/test/Verifier/metadata-function-dbg.ll
new file mode 100644 (file)
index 0000000..43c632b
--- /dev/null
@@ -0,0 +1,23 @@
+; RUN: not llvm-as %s -disable-output 2>&1 | FileCheck %s
+
+define void @foo() !dbg !4 {
+  unreachable
+}
+
+; CHECK-NOT:  !dbg
+; CHECK:      function !dbg attachment must be a subprogram
+; CHECK-NEXT: void ()* @bar
+; CHECK-NEXT: !{{[0-9]+}} = !{}
+define void @bar() !dbg !6 {
+  unreachable
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+
+!llvm.dbg.cu = !{!1}
+!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, subprograms: !3)
+!2 = !DIFile(filename: "t.c", directory: "/path/to/dir")
+!3 = !{!4}
+!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !2, function: void ()* @foo)
+!6 = !{}
index b3c26eb407ff1075341af3a0ed9be12a2227e108..6741c79afc97913d43411df6e748526eda99765d 100644 (file)
@@ -2273,4 +2273,16 @@ TEST_F(FunctionAttachmentTest, EntryCount) {
   EXPECT_EQ(12304u, *F->getEntryCount());
 }
 
   EXPECT_EQ(12304u, *F->getEntryCount());
 }
 
+TEST_F(FunctionAttachmentTest, SubprogramAttachment) {
+  Function *F = getFunction("foo");
+  DISubprogram *SP = getSubprogram();
+  F->setSubprogram(SP);
+
+  // Note that the static_cast confirms that F->getSubprogram() actually
+  // returns an DISubprogram.
+  EXPECT_EQ(SP, static_cast<DISubprogram *>(F->getSubprogram()));
+  EXPECT_EQ(SP, F->getMetadata("dbg"));
+  EXPECT_EQ(SP, F->getMetadata(LLVMContext::MD_dbg));
+}
+
 }
 }