[llvm] 7ed95d1 - [debug-info] Add support for llvm.dbg.addr in DIBuilder.

Michael Gottesman via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 18 18:26:57 PST 2022


Author: Michael Gottesman
Date: 2022-01-18T18:26:50-08:00
New Revision: 7ed95d1577558f95db6b03968b561b17bbb0fec3

URL: https://github.com/llvm/llvm-project/commit/7ed95d1577558f95db6b03968b561b17bbb0fec3
DIFF: https://github.com/llvm/llvm-project/commit/7ed95d1577558f95db6b03968b561b17bbb0fec3.diff

LOG: [debug-info] Add support for llvm.dbg.addr in DIBuilder.

I based this off of the API already create for llvm.dbg.value since both
intrinsics have the same arguments at the API level.

I added some tests exercising the API a little as well as an additional small
test that shows how one can use llvm.dbg.addr to limit the PC range where an
address value is available in the debugger. This is done by calling
llvm.dbg.value with undef and the same metadata info as one used to create the
llvm.dbg.addr.

rdar://83957028

Reviewed By: aprantl

Differential Revision: https://reviews.llvm.org/D117442

Added: 
    

Modified: 
    llvm/include/llvm/IR/DIBuilder.h
    llvm/lib/IR/DIBuilder.cpp
    llvm/test/DebugInfo/X86/dbg-addr.ll
    llvm/unittests/IR/DebugInfoTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h
index d8861c61fcb2a..61885c4de923a 100644
--- a/llvm/include/llvm/IR/DIBuilder.h
+++ b/llvm/include/llvm/IR/DIBuilder.h
@@ -23,6 +23,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/TrackingMDRef.h"
 #include "llvm/Support/Casting.h"
 #include <algorithm>
@@ -46,6 +47,7 @@ namespace llvm {
     Function *DeclareFn;     ///< llvm.dbg.declare
     Function *ValueFn;       ///< llvm.dbg.value
     Function *LabelFn;       ///< llvm.dbg.label
+    Function *AddrFn;        ///< llvm.dbg.addr
 
     SmallVector<Metadata *, 4> AllEnumTypes;
     /// Track the RetainTypes, since they can be updated later on.
@@ -86,11 +88,34 @@ namespace llvm {
     Instruction *insertLabel(DILabel *LabelInfo, const DILocation *DL,
                              BasicBlock *InsertBB, Instruction *InsertBefore);
 
+    /// Internal helper with common code used by insertDbg{Value,Addr}Intrinsic.
+    Instruction *insertDbgIntrinsic(llvm::Function *Intrinsic, llvm::Value *Val,
+                                    DILocalVariable *VarInfo,
+                                    DIExpression *Expr, const DILocation *DL,
+                                    BasicBlock *InsertBB,
+                                    Instruction *InsertBefore);
+
     /// Internal helper for insertDbgValueIntrinsic.
     Instruction *
     insertDbgValueIntrinsic(llvm::Value *Val, DILocalVariable *VarInfo,
                             DIExpression *Expr, const DILocation *DL,
-                            BasicBlock *InsertBB, Instruction *InsertBefore);
+                            BasicBlock *InsertBB, Instruction *InsertBefore) {
+      if (!ValueFn)
+        ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value);
+      return insertDbgIntrinsic(ValueFn, Val, VarInfo, Expr, DL, InsertBB,
+                                InsertBefore);
+    }
+
+    /// Internal helper for insertDbgAddrIntrinsic.
+    Instruction *
+    insertDbgAddrIntrinsic(llvm::Value *Val, DILocalVariable *VarInfo,
+                           DIExpression *Expr, const DILocation *DL,
+                           BasicBlock *InsertBB, Instruction *InsertBefore) {
+      if (!AddrFn)
+        AddrFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_addr);
+      return insertDbgIntrinsic(AddrFn, Val, VarInfo, Expr, DL, InsertBB,
+                                InsertBefore);
+    }
 
   public:
     /// Construct a builder for a module.
@@ -929,6 +954,30 @@ namespace llvm {
                                          const DILocation *DL,
                                          Instruction *InsertBefore);
 
+    /// Insert a new llvm.dbg.addr intrinsic call.
+    /// \param Addr          llvm::Value of the address
+    /// \param VarInfo      Variable's debug info descriptor.
+    /// \param Expr         A complex location expression.
+    /// \param DL           Debug info location.
+    /// \param InsertAtEnd Location for the new intrinsic.
+    Instruction *insertDbgAddrIntrinsic(llvm::Value *Addr,
+                                        DILocalVariable *VarInfo,
+                                        DIExpression *Expr,
+                                        const DILocation *DL,
+                                        BasicBlock *InsertAtEnd);
+
+    /// Insert a new llvm.dbg.addr intrinsic call.
+    /// \param Addr         llvm::Value of the address.
+    /// \param VarInfo      Variable's debug info descriptor.
+    /// \param Expr         A complex location expression.
+    /// \param DL           Debug info location.
+    /// \param InsertBefore Location for the new intrinsic.
+    Instruction *insertDbgAddrIntrinsic(llvm::Value *Addr,
+                                        DILocalVariable *VarInfo,
+                                        DIExpression *Expr,
+                                        const DILocation *DL,
+                                        Instruction *InsertBefore);
+
     /// Replace the vtable holder in the given type.
     ///
     /// If this creates a self reference, it may orphan some unresolved cycles

diff  --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp
index 16429e08382fd..5712f4e9998ee 100644
--- a/llvm/lib/IR/DIBuilder.cpp
+++ b/llvm/lib/IR/DIBuilder.cpp
@@ -33,7 +33,7 @@ static cl::opt<bool>
 
 DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes, DICompileUnit *CU)
     : M(m), VMContext(M.getContext()), CUNode(CU), DeclareFn(nullptr),
-      ValueFn(nullptr), LabelFn(nullptr),
+      ValueFn(nullptr), LabelFn(nullptr), AddrFn(nullptr),
       AllowUnresolvedNodes(AllowUnresolvedNodes) {
   if (CUNode) {
     if (const auto &ETs = CUNode->getEnumTypes())
@@ -974,6 +974,24 @@ Instruction *DIBuilder::insertDbgValueIntrinsic(Value *V,
   return insertDbgValueIntrinsic(V, VarInfo, Expr, DL, InsertAtEnd, nullptr);
 }
 
+Instruction *DIBuilder::insertDbgAddrIntrinsic(Value *V,
+                                               DILocalVariable *VarInfo,
+                                               DIExpression *Expr,
+                                               const DILocation *DL,
+                                               Instruction *InsertBefore) {
+  return insertDbgAddrIntrinsic(
+      V, VarInfo, Expr, DL, InsertBefore ? InsertBefore->getParent() : nullptr,
+      InsertBefore);
+}
+
+Instruction *DIBuilder::insertDbgAddrIntrinsic(Value *V,
+                                               DILocalVariable *VarInfo,
+                                               DIExpression *Expr,
+                                               const DILocation *DL,
+                                               BasicBlock *InsertAtEnd) {
+  return insertDbgAddrIntrinsic(V, VarInfo, Expr, DL, InsertAtEnd, nullptr);
+}
+
 /// Initialize IRBuilder for inserting dbg.declare and dbg.value intrinsics.
 /// This abstracts over the various ways to specify an insert position.
 static void initIRBuilder(IRBuilder<> &Builder, const DILocation *DL,
@@ -1018,17 +1036,20 @@ Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo,
   return B.CreateCall(DeclareFn, Args);
 }
 
-Instruction *DIBuilder::insertDbgValueIntrinsic(
-    Value *V, DILocalVariable *VarInfo, DIExpression *Expr,
-    const DILocation *DL, BasicBlock *InsertBB, Instruction *InsertBefore) {
-  assert(V && "no value passed to dbg.value");
-  assert(VarInfo && "empty or invalid DILocalVariable* passed to dbg.value");
+Instruction *DIBuilder::insertDbgIntrinsic(llvm::Function *IntrinsicFn,
+                                           Value *V, DILocalVariable *VarInfo,
+                                           DIExpression *Expr,
+                                           const DILocation *DL,
+                                           BasicBlock *InsertBB,
+                                           Instruction *InsertBefore) {
+  assert(IntrinsicFn && "must pass a non-null intrinsic function");
+  assert(V && "must pass a value to a dbg intrinsic");
+  assert(VarInfo &&
+         "empty or invalid DILocalVariable* passed to debug intrinsic");
   assert(DL && "Expected debug loc");
   assert(DL->getScope()->getSubprogram() ==
              VarInfo->getScope()->getSubprogram() &&
          "Expected matching subprograms");
-  if (!ValueFn)
-    ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value);
 
   trackIfUnresolved(VarInfo);
   trackIfUnresolved(Expr);
@@ -1038,7 +1059,7 @@ Instruction *DIBuilder::insertDbgValueIntrinsic(
 
   IRBuilder<> B(DL->getContext());
   initIRBuilder(B, DL, InsertBB, InsertBefore);
-  return B.CreateCall(ValueFn, Args);
+  return B.CreateCall(IntrinsicFn, Args);
 }
 
 Instruction *DIBuilder::insertLabel(DILabel *LabelInfo, const DILocation *DL,

diff  --git a/llvm/test/DebugInfo/X86/dbg-addr.ll b/llvm/test/DebugInfo/X86/dbg-addr.ll
index f55686fafebc3..52cc9c3af8812 100644
--- a/llvm/test/DebugInfo/X86/dbg-addr.ll
+++ b/llvm/test/DebugInfo/X86/dbg-addr.ll
@@ -1,11 +1,11 @@
 ;; Run twice -- once with DBG_VALUEs, once with instruction referencing.
 ; RUN: llc %s -o %t.s -experimental-debug-variable-locations=false
 ; RUN: llvm-mc -triple x86_64--linux %t.s -filetype=obj -o %t.o
-; RUN: FileCheck < %t.s %s
+; RUN: FileCheck -input-file=%t.s %s
 ; RUN: llvm-dwarfdump %t.o | FileCheck %s --check-prefix=DWARF
 ; RUN: llc %s -o %t.s -experimental-debug-variable-locations=true
 ; RUN: llvm-mc -triple x86_64--linux %t.s -filetype=obj -o %t.o
-; RUN: FileCheck < %t.s %s
+; RUN: FileCheck -input-file=%t.s %s
 ; RUN: llvm-dwarfdump %t.o | FileCheck %s --check-prefix=DWARF
 
 
@@ -20,6 +20,19 @@
 ; DWARF-NEXT:              DW_AT_location (DW_OP_fbreg +0)
 ; DWARF-NEXT:              DW_AT_name ("o")
 
+; Make sure that in the second case, we properly get a validity range in the
+; dwarf for the value. This ensures that we can use this technique to invalidate
+; variables.
+
+; CHECK-LABEL: test_dbg_addr_and_dbg_val_undef
+; CHECK: #DEBUG_VALUE: test_dbg_addr_and_dbg_val_undef:second_o <- [$rsp+0]
+; CHECK: #DEBUG_VALUE: test_dbg_addr_and_dbg_val_undef:second_o <- undef
+; CHECK-NOT: #DEBUG_VALUE:
+
+; DWARF: DW_TAG_variable
+; DWARF-NEXT:              DW_AT_location (0x{{[0-9a-z][0-9a-z]*}}:
+; DWARF-NEXT:                 [0x{{[0-9a-z][0-9a-z]*}}, 0x{{[0-9a-z][0-9a-z]*}}): DW_OP_breg7 RSP+0)
+; DWARF-NEXT:              DW_AT_name ("second_o")
 
 ; ModuleID = 't.c'
 source_filename = "t.c"
@@ -37,8 +50,18 @@ entry:
   ret void, !dbg !18
 }
 
+define void @test_dbg_addr_and_dbg_val_undef() #0 !dbg !117 {
+entry:
+  %o = alloca %struct.Foo, align 4
+  call void @llvm.dbg.addr(metadata %struct.Foo* %o, metadata !1110, metadata !1115), !dbg !1116
+  call void @escape_foo(%struct.Foo* %o), !dbg !1117
+  call void @llvm.dbg.value(metadata %struct.Foo* undef, metadata !1110, metadata !1115), !dbg !1116
+  ret void, !dbg !1118
+}
+
 ; Function Attrs: nounwind readnone speculatable
 declare void @llvm.dbg.addr(metadata, metadata, metadata) #1
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
 
 declare void @escape_foo(%struct.Foo*)
 
@@ -68,3 +91,16 @@ attributes #1 = { nounwind readnone speculatable }
 !16 = !DILocation(line: 4, column: 14, scope: !7)
 !17 = !DILocation(line: 5, column: 3, scope: !7)
 !18 = !DILocation(line: 6, column: 1, scope: !7)
+
+!117 = distinct !DISubprogram(name: "test_dbg_addr_and_dbg_val_undef", scope: !1, file: !1, line: 3, type: !118, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!118 = !DISubroutineType(types: !119)
+!119 = !{null}
+!1110 = !DILocalVariable(name: "second_o", scope: !117, file: !1, line: 4, type: !1111)
+!1111 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 1, size: 32, elements: !1112)
+!1112 = !{!1113}
+!1113 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !1111, file: !1, line: 1, baseType: !1114, size: 32)
+!1114 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!1115 = !DIExpression()
+!1116 = !DILocation(line: 4, column: 14, scope: !117)
+!1117 = !DILocation(line: 5, column: 3, scope: !117)
+!1118 = !DILocation(line: 6, column: 1, scope: !117)

diff  --git a/llvm/unittests/IR/DebugInfoTest.cpp b/llvm/unittests/IR/DebugInfoTest.cpp
index 17b6e54644b23..8605fbbcbd401 100644
--- a/llvm/unittests/IR/DebugInfoTest.cpp
+++ b/llvm/unittests/IR/DebugInfoTest.cpp
@@ -11,8 +11,10 @@
 #include "llvm/AsmParser/Parser.h"
 #include "llvm/IR/DIBuilder.h"
 #include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Verifier.h"
 #include "llvm/Support/SourceMgr.h"
@@ -262,4 +264,69 @@ TEST(DIBuilder, DIEnumerator) {
   EXPECT_FALSE(E2);
 }
 
+TEST(DIBuilder, createDbgAddr) {
+  LLVMContext C;
+  std::unique_ptr<Module> M = parseIR(C, R"(
+    define void @f() !dbg !6 {
+      %a = alloca i16, align 8
+      ;; It is important that we put the debug marker on the return.
+      ;; We take advantage of that to conjure up a debug loc without
+      ;; having to synthesize one programatically.
+      ret void, !dbg !11
+    }
+    declare void @llvm.dbg.value(metadata, metadata, metadata) #0
+    attributes #0 = { nounwind readnone speculatable willreturn }
+
+    !llvm.dbg.cu = !{!0}
+    !llvm.module.flags = !{!5}
+
+    !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+    !1 = !DIFile(filename: "t.ll", directory: "/")
+    !2 = !{}
+    !5 = !{i32 2, !"Debug Info Version", i32 3}
+    !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+    !7 = !DISubroutineType(types: !2)
+    !8 = !{!9}
+    !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
+    !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
+    !11 = !DILocation(line: 1, column: 1, scope: !6)
+)");
+  auto *F = M->getFunction("f");
+  auto *EntryBlock = &F->getEntryBlock();
+
+  auto *CU =
+      cast<DICompileUnit>(M->getNamedMetadata("llvm.dbg.cu")->getOperand(0));
+  auto *Alloca = &*EntryBlock->begin();
+  auto *Ret = EntryBlock->getTerminator();
+
+  auto *SP = cast<DISubprogram>(F->getMetadata(LLVMContext::MD_dbg));
+  auto *File = SP->getFile();
+  std::string Name = "myName";
+  const auto *Loc = Ret->getDebugLoc().get();
+
+  IRBuilder<> Builder(EntryBlock);
+  DIBuilder DIB(*M, true, CU);
+  DIType *DT = DIB.createBasicType("ty16", 16, dwarf::DW_ATE_unsigned);
+
+  DILocalVariable *LocalVar =
+      DIB.createAutoVariable(SP, Name, File, 5 /*line*/, DT,
+                             /*AlwaysPreserve=*/true);
+
+  auto *Inst = DIB.insertDbgAddrIntrinsic(Alloca, LocalVar,
+                                          DIB.createExpression(), Loc, Ret);
+
+  DIB.finalize();
+
+  EXPECT_EQ(Inst->getDebugLoc().get(), Loc);
+
+  auto *MD0 = cast<MetadataAsValue>(Inst->getOperand(0))->getMetadata();
+  auto *MD0Local = cast<LocalAsMetadata>(MD0);
+  EXPECT_EQ(MD0Local->getValue(), Alloca);
+  auto *MD1 = cast<MetadataAsValue>(Inst->getOperand(1))->getMetadata();
+  EXPECT_EQ(MD1->getMetadataID(), Metadata::MetadataKind::DILocalVariableKind);
+  auto *MD2 = cast<MetadataAsValue>(Inst->getOperand(2))->getMetadata();
+  auto *MDExp = cast<DIExpression>(MD2);
+  EXPECT_EQ(MDExp->getNumElements(), 0u);
+}
+
 } // end namespace


        


More information about the llvm-commits mailing list