[llvm] 3feea34 - [DebugInfo] Do not delete debug intrinsics with empty metadata operands

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 26 01:58:47 PDT 2023


Author: OCHyams
Date: 2023-04-26T09:58:31+01:00
New Revision: 3feea34d77f65f0b68520bb7bf372580a72794ad

URL: https://github.com/llvm/llvm-project/commit/3feea34d77f65f0b68520bb7bf372580a72794ad
DIFF: https://github.com/llvm/llvm-project/commit/3feea34d77f65f0b68520bb7bf372580a72794ad.diff

LOG: [DebugInfo] Do not delete debug intrinsics with empty metadata operands

A ValueAsMetadata may be replaced with nullptr for several reasons including
deleting (certain) values and value remapping a use-before-def. In the case of
a MetadataAsValue user, handleChangedOperand intercepts and replaces the
metadata with an empty tuple (!{}).

At the moment, an empty metadata operand in a debug intrinsics signals that it
can be deleted.

Given that we end up with empty metadata operands in circumstances where the
Value has been "lost" the current behaviour can lead to incorrect variable
locations. Instead, we should treat empty metadata as meaning "there is no
location for the variable" (the same as we currently treat undef operands).

This patch removes the deletion logic from wouldInstructionBeTriviallyDead.

Related to https://discourse.llvm.org/t/auto-undef-debug-uses-of-a-deleted-value

Reviewed By: StephenTozer

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

Added: 
    llvm/test/DebugInfo/Generic/empty-metadata.ll

Modified: 
    llvm/lib/Transforms/Utils/Local.cpp
    llvm/unittests/Transforms/Utils/LocalTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index d8036f7299a59..1a714998c5285 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -424,23 +424,9 @@ bool llvm::wouldInstructionBeTriviallyDead(Instruction *I,
   if (I->isEHPad())
     return false;
 
-  // We don't want debug info removed by anything this general, unless
-  // debug info is empty.
-  if (DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(I)) {
-    if (DDI->getAddress())
-      return false;
-    return true;
-  }
-  if (DbgValueInst *DVI = dyn_cast<DbgValueInst>(I)) {
-    if (DVI->hasArgList() || DVI->getValue(0))
-      return false;
-    return true;
-  }
-  if (DbgLabelInst *DLI = dyn_cast<DbgLabelInst>(I)) {
-    if (DLI->getLabel())
-      return false;
-    return true;
-  }
+  // We don't want debug info removed by anything this general.
+  if (isa<DbgVariableIntrinsic>(I))
+    return false;
 
   if (auto *CB = dyn_cast<CallBase>(I))
     if (isRemovableAlloc(CB, TLI))

diff  --git a/llvm/test/DebugInfo/Generic/empty-metadata.ll b/llvm/test/DebugInfo/Generic/empty-metadata.ll
new file mode 100644
index 0000000000000..24af10c8e779b
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/empty-metadata.ll
@@ -0,0 +1,37 @@
+; RUN: opt -passes=dce -S %s -o - | FileCheck %s
+
+;; Check that DCE doesn't remove a dbg intrinsic that has an empty metadata
+;; operand.
+; CHECK: call void @llvm.dbg.declare(metadata ![[EMPTY:[0-9]+]],
+; CHECK: ![[EMPTY]] = !{}
+
+define dso_local void @fun() local_unnamed_addr #0 !dbg !9 {
+entry:
+  call void @llvm.dbg.declare(metadata !{}, metadata !13, metadata !DIExpression()), !dbg !15
+  ret void, !dbg !16
+}
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 16.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{!"clang version 16.0.0"}
+!9 = distinct !DISubprogram(name: "fun", scope: !1, file: !1, line: 1, type: !10, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
+!10 = !DISubroutineType(types: !11)
+!11 = !{null}
+!12 = !{!13}
+!13 = !DILocalVariable(name: "a", scope: !9, file: !1, line: 1, type: !14)
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DILocation(line: 1, column: 18, scope: !9)
+!16 = !DILocation(line: 1, column: 21, scope: !9)
+

diff  --git a/llvm/unittests/Transforms/Utils/LocalTest.cpp b/llvm/unittests/Transforms/Utils/LocalTest.cpp
index 4f2bc6f3b36c8..537abd91b79e2 100644
--- a/llvm/unittests/Transforms/Utils/LocalTest.cpp
+++ b/llvm/unittests/Transforms/Utils/LocalTest.cpp
@@ -603,6 +603,47 @@ TEST(Local, SimplifyVScaleWithRange) {
   delete CI;
 }
 
+TEST(Local, wouldInstructionBeTriviallyDead) {
+  LLVMContext Ctx;
+  std::unique_ptr<Module> M = parseIR(Ctx,
+                                      R"(
+    define dso_local void @fun() local_unnamed_addr #0 !dbg !9 {
+    entry:
+      call void @llvm.dbg.declare(metadata !{}, metadata !13, metadata !DIExpression()), !dbg !16
+      ret void, !dbg !16
+    }
+
+    declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+    !llvm.dbg.cu = !{!0}
+    !llvm.module.flags = !{!2, !3}
+    !llvm.ident = !{!8}
+
+    !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 16.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+    !1 = !DIFile(filename: "test.c", directory: "/")
+    !2 = !{i32 7, !"Dwarf Version", i32 5}
+    !3 = !{i32 2, !"Debug Info Version", i32 3}
+    !8 = !{!"clang version 16.0.0"}
+    !9 = distinct !DISubprogram(name: "fun", scope: !1, file: !1, line: 1, type: !10, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
+    !10 = !DISubroutineType(types: !11)
+    !11 = !{null}
+    !12 = !{!13}
+    !13 = !DILocalVariable(name: "a", scope: !9, file: !1, line: 1, type: !14)
+    !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+    !16 = !DILocation(line: 1, column: 21, scope: !9)
+    )");
+  bool BrokenDebugInfo = true;
+  verifyModule(*M, &errs(), &BrokenDebugInfo);
+  ASSERT_FALSE(BrokenDebugInfo);
+
+  // Get the dbg.declare.
+  Function &F = *cast<Function>(M->getNamedValue("fun"));
+  Instruction *DbgDeclare = &F.front().front();
+  ASSERT_TRUE(isa<DbgDeclareInst>(DbgDeclare));
+  // Debug intrinsics with empty metadata arguments are not dead.
+  EXPECT_FALSE(wouldInstructionBeTriviallyDead(DbgDeclare));
+}
+
 TEST(Local, ChangeToUnreachable) {
   LLVMContext Ctx;
 


        


More information about the llvm-commits mailing list