[PATCH] Let replaceVTableHolder accept any type

Tom Tromey via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 16 12:25:14 PDT 2017


In Rust, a trait can be implemented for any type, and if a trait
object pointer is used for the type, then a virtual table will be
emitted for that trait/type combination.

We would like debuggers to be able to inspect trait objects, which
requires finding the concrete type associated with a given vtable.

This patch changes LLVM so that any type can be passed to
replaceVTableHolder.  This allows the Rust compiler to emit the needed
debug info -- associating a vtable with the concrete type for which it
was emitted.

This is a DWARF extension: DWARF only specifies the meaning of
DW_AT_containing_type in one specific situation.  This style of DWARF
extension is routine, though, and LLVM already has one such case for
DW_AT_containing_type.
---
 include/llvm/IR/DIBuilder.h                        |  4 +--
 lib/CodeGen/AsmPrinter/DwarfUnit.cpp               |  5 +--
 lib/IR/DIBuilder.cpp                               |  2 +-
 .../DebugInfo/Generic/containing-type-extension.ll | 38 ++++++++++++++++++++++
 unittests/IR/MetadataTest.cpp                      |  4 +++
 5 files changed, 48 insertions(+), 5 deletions(-)
 create mode 100644 test/DebugInfo/Generic/containing-type-extension.ll

diff --git a/include/llvm/IR/DIBuilder.h b/include/llvm/IR/DIBuilder.h
index eac48d9..3c2074d 100644
--- a/include/llvm/IR/DIBuilder.h
+++ b/include/llvm/IR/DIBuilder.h
@@ -757,12 +757,12 @@ namespace llvm {
                                          const DILocation *DL,
                                          Instruction *InsertBefore);
 
-    /// Replace the vtable holder in the given composite type.
+    /// Replace the vtable holder in the given type.
     ///
     /// If this creates a self reference, it may orphan some unresolved cycles
     /// in the operands of \c T, so \a DIBuilder needs to track that.
     void replaceVTableHolder(DICompositeType *&T,
-                             DICompositeType *VTableHolder);
+                             DIType *VTableHolder);
 
     /// Replace arrays on a composite type.
     ///
diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index 784a1d5..ce74659 100644
--- a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -960,8 +960,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
 
     // This is outside the DWARF spec, but GDB expects a DW_AT_containing_type
     // inside C++ composite types to point to the base class with the vtable.
-    if (auto *ContainingType =
-            dyn_cast_or_null<DICompositeType>(resolve(CTy->getVTableHolder())))
+    // Rust uses DW_AT_containing_type to link a vtable to the type
+    // for which it was created.
+    if (auto *ContainingType = resolve(CTy->getVTableHolder()))
       addDIEEntry(Buffer, dwarf::DW_AT_containing_type,
                   *getOrCreateTypeDIE(ContainingType));
 
diff --git a/lib/IR/DIBuilder.cpp b/lib/IR/DIBuilder.cpp
index 18979a8..837b1ec 100644
--- a/lib/IR/DIBuilder.cpp
+++ b/lib/IR/DIBuilder.cpp
@@ -874,7 +874,7 @@ Instruction *DIBuilder::insertDbgValueIntrinsic(
 }
 
 void DIBuilder::replaceVTableHolder(DICompositeType *&T,
-                                    DICompositeType *VTableHolder) {
+                                    DIType *VTableHolder) {
   {
     TypedTrackingMDRef<DICompositeType> N(T);
     N->replaceVTableHolder(VTableHolder);
diff --git a/test/DebugInfo/Generic/containing-type-extension.ll b/test/DebugInfo/Generic/containing-type-extension.ll
new file mode 100644
index 0000000..7f39f6b
--- /dev/null
+++ b/test/DebugInfo/Generic/containing-type-extension.ll
@@ -0,0 +1,38 @@
+; REQUIRES: object-emission
+
+; RUN: %llc_dwarf -O0 -filetype=obj < %s > %t
+; RUN: llvm-dwarfdump -v -debug-info %t | FileCheck %s
+
+; Make sure we correctly handle context of a subprogram being a type identifier.
+; CHECK: [[SP:.*]]: DW_TAG_structure_type
+; CHECK: DW_AT_containing_type [DW_FORM_ref4]       (cu + {{.*}}
+; CHECK: DW_AT_name [DW_FORM_strp] {{.*}}= "vtable")
+
+; The code doesn't actually matter.
+define i32 @main() #0 !dbg !4 {
+entry:
+  %retval = alloca i32, align 4
+  store i32 0, i32* %retval
+  ret i32 0, !dbg !10
+}
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!9, !11}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.4 (trunk 185475)", isOptimized: false, emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !2, globals: !15, imports: !2)
+!1 = !DIFile(filename: "CodeGen/dwarf-version.c", directory: "test")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "main", line: 6, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped | DIFlagMainSubprogram, isOptimized: false, unit: !0, scopeLine: 6, file: !1, scope: !5, type: !6, variables: !2)
+!5 = !DIFile(filename: "CodeGen/dwarf-version.c", directory: "test")
+!6 = !DISubroutineType(types: !7)
+!7 = !{!8}
+!8 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!9 = !{i32 2, !"Dwarf Version", i32 4}
+!10 = !DILocation(line: 7, scope: !4)
+!11 = !{i32 1, !"Debug Info Version", i32 3}
+!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "vtable", size: 8, align: 8, elements: !2, identifier: "vtable", vtableHolder: !8)
+!13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression())
+!14 = !DIGlobalVariable(name: "vtable", linkageName: "vtable", scope: null, file: !1, line: 1, type: !12, isLocal: true, isDefinition: true)
+!15 = !{!13}
diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp
index 3ab0ad4..03e2d27 100644
--- a/unittests/IR/MetadataTest.cpp
+++ b/unittests/IR/MetadataTest.cpp
@@ -1314,6 +1314,10 @@ TEST_F(DICompositeTypeTest, replaceOperands) {
   EXPECT_EQ(nullptr, N->getVTableHolder());
   N->replaceVTableHolder(VTableHolder);
   EXPECT_EQ(VTableHolder, N->getVTableHolder());
+  // As an extension, the containing type can be anything.
+  DIType *BasicType = getBasicType("basic");
+  N->replaceVTableHolder(BasicType);
+  EXPECT_EQ(BasicType, N->getVTableHolder());
   N->replaceVTableHolder(nullptr);
   EXPECT_EQ(nullptr, N->getVTableHolder());
 
-- 
2.9.5



More information about the llvm-commits mailing list