[llvm] [DirectX] Lower DbgAssign to DbgValue (PR #200267)

Harald van Dijk via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 06:27:26 PDT 2026


https://github.com/hvdijk updated https://github.com/llvm/llvm-project/pull/200267

>From 0d6c97caeeb5c07e25687e7d453e27fecf4ad3bf Mon Sep 17 00:00:00 2001
From: Harald van Dijk <hdijk at accesssoftek.com>
Date: Thu, 28 May 2026 19:23:15 +0100
Subject: [PATCH 1/4] [DirectX] Lower DbgAssign to DbgValue

DbgAssign is not representable in LLVM 3.7.
---
 .../DirectX/DirectXIRPasses/DXILDebugInfo.cpp | 106 ++++++++++++++++--
 llvm/test/tools/dxil-dis/dbg-assign.ll        |  42 +++++++
 2 files changed, 141 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/tools/dxil-dis/dbg-assign.ll

diff --git a/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp b/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
index 0fa81186000f9..138c2011f263f 100644
--- a/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
+++ b/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
@@ -8,6 +8,8 @@
 
 #include "DXILDebugInfo.h"
 #include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/IR/AttributeMask.h"
+#include "llvm/IR/Attributes.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicsDirectX.h"
@@ -68,14 +70,103 @@ DXILDebugInfoMap DXILDebugInfoPass::run(Module &M) {
   DebugInfoFinder DIF;
   DIF.processModule(M);
 
-  for (auto &F : M) {
-    for (auto &BB : F) {
-      for (auto &I : make_early_inc_range(reverse(BB))) {
+  Function *DVDecl = nullptr;
+
+  for (Function &F : M) {
+    bool IsEntryBlock = true;
+    for (BasicBlock &BB : F) {
+      DenseMap<DILocalVariable *, std::pair<Instruction *, DbgValueInst *>>
+          DbgValues;
+      DenseMap<std::pair<DILocalVariable *, DIExpression *>,
+               std::pair<Instruction *, DbgValueInst *>>
+          DbgValueFragments;
+      Instruction *NextNonDebugInst = nullptr;
+      for (Instruction &I : make_early_inc_range(reverse(BB))) {
+        I.eraseMetadataIf([](unsigned KindID, MDNode *) {
+          return KindID == LLVMContext::MD_DIAssignID;
+        });
+        if (!isa<DbgInfoIntrinsic>(I)) {
+          NextNonDebugInst = &I;
+          continue;
+        }
         if (auto *DL = dyn_cast<DbgLabelInst>(&I)) {
           DL->eraseFromParent();
           continue;
         }
+        // Process both llvm.dbg.value and llvm.dbg.assign here. We convert
+        // llvm.dbg.assign to llvm.dbg.value by dropping the last arguments, and
+        // remove redundant llvm.dbg.values.
+        if (auto *DV = dyn_cast<DbgValueInst>(&I)) {
+          // Keep track of the last location where we saw any debug value for a
+          // variable.
+          DILocalVariable *V = DV->getVariable();
+          DIExpression *E = DV->getExpression();
+          std::pair<Instruction *, DbgValueInst *> &DbgValue = DbgValues[V];
+          std::pair<Instruction *, DbgValueInst *> &DbgValueFragment =
+              DbgValueFragments[{V, E}];
+          if (DbgValue.second) {
+            // If there is a later value of the same fragment at the same
+            // location, this value is redundant.
+            if (DbgValueFragment.first == NextNonDebugInst) {
+              DV->eraseFromParent();
+              continue;
+            }
+            // If there is a later identical value of the same fragment at a
+            // later point, and there have been no intervening values of
+            // different possibly overlapping fragments, that later value is
+            // redundant.
+            if (DbgValueFragment.second &&
+                DbgValueFragment.second == DbgValue.second &&
+                DbgValueFragment.second->getValue() == DV->getValue()) {
+              DbgValue.second->eraseFromParent();
+            }
+          }
+          // If this is already an llvm.dbg.value instruction, just keep it,
+          // otherwise convert it.
+          DbgValueInst *NewDV;
+          if (DV->getIntrinsicID() == Intrinsic::dbg_value) {
+            NewDV = DV;
+          } else {
+            if (!DVDecl) {
+              DVDecl =
+                  Intrinsic::getOrInsertDeclaration(&M, Intrinsic::dbg_value);
+              AttributeMask AM;
+              for (Attribute A : DVDecl->getAttributes().getFnAttrs())
+                if (A.isStringAttribute() ||
+                    (A.getKindAsEnum() != Attribute::NoUnwind &&
+                     A.getKindAsEnum() != Attribute::Memory))
+                  AM.addAttribute(A);
+              DVDecl->removeFnAttrs(AM);
+            }
+            NewDV = cast<DbgValueInst>(
+                CallInst::Create(DVDecl,
+                                 {DV->getArgOperand(0), DV->getArgOperand(1),
+                                  DV->getArgOperand(2)},
+                                 {}, "", std::next(DV->getIterator())));
+            NewDV->setTailCall();
+            NewDV->setDebugLoc(DV->getDebugLoc());
+            DV->eraseFromParent();
+          }
+          DbgValue = DbgValueFragment = {NextNonDebugInst, NewDV};
+          continue;
+        }
+      }
+      // If this is the entry block, if the first value we see for each debug
+      // value is undef, it is redundant.
+      if (IsEntryBlock) {
+        DenseSet<DILocalVariable *> Seen;
+        for (Instruction &I : make_early_inc_range(BB)) {
+          auto *DV = dyn_cast<DbgValueInst>(&I);
+          if (!DV || Seen.contains(DV->getVariable()))
+            continue;
+          if (isa<UndefValue>(DV->getValue())) {
+            DV->eraseFromParent();
+            continue;
+          }
+          Seen.insert(DV->getVariable());
+        }
       }
+      IsEntryBlock = false;
     }
   }
 
@@ -177,10 +268,11 @@ DXILDebugInfoMap DXILDebugInfoPass::run(Module &M) {
     if (auto *SR = dyn_cast<DISubrangeType>(T)) {
       DIType *BT = SR->getBaseType();
       if (!BT)
-        BT = DIBasicType::get(
-            SR->getContext(), dwarf::DW_TAG_base_type, SR->getName(),
-            SR->getSizeInBits(), SR->getAlignInBits(), dwarf::DW_ATE_unsigned,
-            SR->getNumExtraInhabitants(), /*DataSizeInBits=*/0, SR->getFlags());
+        BT = DIBasicType::get(SR->getContext(), dwarf::DW_TAG_base_type,
+                              SR->getName(), SR->getSizeInBits(),
+                              SR->getAlignInBits(), dwarf::DW_ATE_unsigned,
+                              SR->getNumExtraInhabitants(),
+                              /*DataSizeInBits=*/0, SR->getFlags());
       Res.MDReplace.insert({T, BT});
     }
   }
diff --git a/llvm/test/tools/dxil-dis/dbg-assign.ll b/llvm/test/tools/dxil-dis/dbg-assign.ll
new file mode 100644
index 0000000000000..5ae256cc74794
--- /dev/null
+++ b/llvm/test/tools/dxil-dis/dbg-assign.ll
@@ -0,0 +1,42 @@
+;; RUN: llc --filetype=obj -o - %s | dxil-dis -o - | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.3-library"
+
+;; CHECK: define i32 @dbgassign(i32 %a, i32 %b) {
+;; CHECK-NEXT: entry:
+;; CHECK-NEXT:   call void @llvm.dbg.value(metadata i32 %a, i64 0, metadata [[LV:![0-9]+]], metadata [[EX:![0-9]+]])
+;; CHECK-NEXT:   %add = add nsw i32 %a, %b
+;; CHECK-NEXT:   call void @llvm.dbg.value(metadata i32 %add, i64 0, metadata [[LV]], metadata [[EX]])
+;; CHECK-NEXT:   ret i32 %add
+;; CHECK-NEXT: }
+
+define i32 @dbgassign(i32 %a, i32 %b) !dbg !5 {
+entry:
+    #dbg_assign(i1 poison, !10, !DIExpression(), !11, ptr poison, !DIExpression(), !12)
+    #dbg_assign(i32 0, !10, !DIExpression(), !13, ptr poison, !DIExpression(), !12)
+    #dbg_assign(i32 %a, !10, !DIExpression(), !14, ptr poison, !DIExpression(), !12)
+  %add = add nsw i32 %a, %b, !dbg !15
+    #dbg_assign(i32 %add, !10, !DIExpression(), !16, ptr poison, !DIExpression(), !12)
+  ret i32 %add
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "dbgassign.c", directory: "")
+!2 = !{i32 7, !"Dwarf Version", i32 4}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+!5 = distinct !DISubprogram(name: "dbgassign", scope: !1, file: !1, line: 2, type: !6, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !9, keyInstructions: true)
+!6 = !DISubroutineType(types: !7)
+!7 = !{!8, !8, !8}
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = !{!10}
+!10 = !DILocalVariable(name: "result", scope: !5, file: !1, line: 3, type: !8)
+!11 = distinct !DIAssignID()
+!12 = !DILocation(line: 0, scope: !5)
+!13 = distinct !DIAssignID()
+!14 = distinct !DIAssignID()
+!15 = !DILocation(line: 7, column: 10, scope: !5, atomGroup: 3, atomRank: 2)
+!16 = distinct !DIAssignID()

>From a4f4dd98e2a0a693c90085cc98304c4d46f39a97 Mon Sep 17 00:00:00 2001
From: Harald van Dijk <hdijk at accesssoftek.com>
Date: Thu, 4 Jun 2026 23:15:09 +0100
Subject: [PATCH 2/4] Add CodeGen test

---
 .../CodeGen/DirectX/DebugInfo/dbg-assign.ll   | 45 +++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 llvm/test/CodeGen/DirectX/DebugInfo/dbg-assign.ll

diff --git a/llvm/test/CodeGen/DirectX/DebugInfo/dbg-assign.ll b/llvm/test/CodeGen/DirectX/DebugInfo/dbg-assign.ll
new file mode 100644
index 0000000000000..9c682bcf2fe23
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/DebugInfo/dbg-assign.ll
@@ -0,0 +1,45 @@
+;; RUN: llc -o - %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.3-library"
+
+;; CHECK: define i32 @dbgassign(i32 %a, i32 %b) !dbg [[SP:![0-9]+]] {
+;; CHECK-NEXT: entry:
+;; CHECK-NEXT:   ; DXIL: to be replaced with: tail call addrspace(0) void @llvm.dbg.value(metadata i32 %a, i64 0, metadata [[LV:![0-9]+]], metadata !DIExpression())
+;; CHECK-NEXT:   tail call void @llvm.dbg.value(metadata i32 %a, metadata [[LV:![0-9]+]], metadata !DIExpression())
+;; CHECK-NEXT:   %add = add nsw i32 %a, %b
+;; CHECK-NEXT:   ; DXIL: to be replaced with: tail call addrspace(0) void @llvm.dbg.value(metadata i32 %add, i64 0, metadata [[LV]], metadata !DIExpression())
+;; CHECK-NEXT:   tail call void @llvm.dbg.value(metadata i32 %add, metadata [[LV]], metadata !DIExpression()
+;; CHECK-NEXT:   ret i32 %add
+;; CHECK-NEXT: }
+;; CHECK-NOT: !DIAssignID()
+
+define i32 @dbgassign(i32 %a, i32 %b) !dbg !5 {
+entry:
+    #dbg_assign(i1 poison, !10, !DIExpression(), !11, ptr poison, !DIExpression(), !12)
+    #dbg_assign(i32 0, !10, !DIExpression(), !13, ptr poison, !DIExpression(), !12)
+    #dbg_assign(i32 %a, !10, !DIExpression(), !14, ptr poison, !DIExpression(), !12)
+  %add = add nsw i32 %a, %b, !dbg !15
+    #dbg_assign(i32 %add, !10, !DIExpression(), !16, ptr poison, !DIExpression(), !12)
+  ret i32 %add
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "dbgassign.c", directory: "")
+!2 = !{i32 7, !"Dwarf Version", i32 4}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+!5 = distinct !DISubprogram(name: "dbgassign", scope: !1, file: !1, line: 2, type: !6, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !9, keyInstructions: true)
+!6 = !DISubroutineType(types: !7)
+!7 = !{!8, !8, !8}
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = !{!10}
+!10 = !DILocalVariable(name: "result", scope: !5, file: !1, line: 3, type: !8)
+!11 = distinct !DIAssignID()
+!12 = !DILocation(line: 0, scope: !5)
+!13 = distinct !DIAssignID()
+!14 = distinct !DIAssignID()
+!15 = !DILocation(line: 7, column: 10, scope: !5, atomGroup: 3, atomRank: 2)
+!16 = distinct !DIAssignID()

>From b8f696c7c27f42a16f727f4d0ca1d70cd11df65e Mon Sep 17 00:00:00 2001
From: Harald van Dijk <hdijk at accesssoftek.com>
Date: Mon, 8 Jun 2026 14:22:54 +0100
Subject: [PATCH 3/4] Move DbgValue(Fragment)s out of loop

---
 .../DirectX/DirectXIRPasses/DXILDebugInfo.cpp | 187 +++++++++---------
 1 file changed, 98 insertions(+), 89 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp b/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
index 921675c9b9ce2..9fa5fc689dcdf 100644
--- a/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
+++ b/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
@@ -70,103 +70,112 @@ DXILDebugInfoMap DXILDebugInfoPass::run(Module &M) {
   DebugInfoFinder DIF;
   DIF.processModule(M);
 
-  Function *DVDecl = nullptr;
+  {
+    Function *DVDecl = nullptr;
 
-  for (Function &F : M) {
-    bool IsEntryBlock = true;
-    for (BasicBlock &BB : F) {
-      DenseMap<DILocalVariable *, std::pair<Instruction *, DbgValueInst *>>
-          DbgValues;
-      DenseMap<std::pair<DILocalVariable *, DIExpression *>,
-               std::pair<Instruction *, DbgValueInst *>>
-          DbgValueFragments;
-      Instruction *NextNonDebugInst = nullptr;
-      for (Instruction &I : make_early_inc_range(reverse(BB))) {
-        I.eraseMetadataIf([](unsigned KindID, MDNode *) {
-          return KindID == LLVMContext::MD_DIAssignID;
-        });
-        if (!isa<DbgInfoIntrinsic>(I)) {
-          NextNonDebugInst = &I;
-          continue;
-        }
-        if (auto *DL = dyn_cast<DbgLabelInst>(&I)) {
-          DL->eraseFromParent();
-          continue;
-        }
-        // Process both llvm.dbg.value and llvm.dbg.assign here. We convert
-        // llvm.dbg.assign to llvm.dbg.value by dropping the last arguments, and
-        // remove redundant llvm.dbg.values.
-        if (auto *DV = dyn_cast<DbgValueInst>(&I)) {
-          // Keep track of the last location where we saw any debug value for a
-          // variable.
-          DILocalVariable *V = DV->getVariable();
-          DIExpression *E = DV->getExpression();
-          std::pair<Instruction *, DbgValueInst *> &DbgValue = DbgValues[V];
-          std::pair<Instruction *, DbgValueInst *> &DbgValueFragment =
-              DbgValueFragments[{V, E}];
-          if (DbgValue.second) {
-            // If there is a later value of the same fragment at the same
-            // location, this value is redundant.
-            if (DbgValueFragment.first == NextNonDebugInst) {
-              DV->eraseFromParent();
-              continue;
-            }
-            // If there is a later identical value of the same fragment at a
-            // later point, and there have been no intervening values of
-            // different possibly overlapping fragments, that later value is
-            // redundant.
-            if (DbgValueFragment.second &&
-                DbgValueFragment.second == DbgValue.second &&
-                DbgValueFragment.second->getValue() == DV->getValue()) {
-              DbgValue.second->eraseFromParent();
-            }
+    // Logically these should be variables in the
+    //  for (BasicBlock &BB : F) loop.
+    // They are defined here and cleared at the start of the loop body to avoid
+    // the cost of deconstruction and reconstruction.
+    DenseMap<DILocalVariable *, std::pair<Instruction *, DbgValueInst *>>
+        DbgValues;
+    DenseMap<std::pair<DILocalVariable *, DIExpression *>,
+             std::pair<Instruction *, DbgValueInst *>>
+        DbgValueFragments;
+
+    for (Function &F : M) {
+      bool IsEntryBlock = true;
+      for (BasicBlock &BB : F) {
+        Instruction *NextNonDebugInst = nullptr;
+        DbgValues.clear();
+        DbgValueFragments.clear();
+        for (Instruction &I : make_early_inc_range(reverse(BB))) {
+          I.eraseMetadataIf([](unsigned KindID, MDNode *) {
+            return KindID == LLVMContext::MD_DIAssignID;
+          });
+          if (!isa<DbgInfoIntrinsic>(I)) {
+            NextNonDebugInst = &I;
+            continue;
+          }
+          if (auto *DL = dyn_cast<DbgLabelInst>(&I)) {
+            DL->eraseFromParent();
+            continue;
           }
-          // If this is already an llvm.dbg.value instruction, just keep it,
-          // otherwise convert it.
-          DbgValueInst *NewDV;
-          if (DV->getIntrinsicID() == Intrinsic::dbg_value) {
-            NewDV = DV;
-          } else {
-            if (!DVDecl) {
-              DVDecl =
-                  Intrinsic::getOrInsertDeclaration(&M, Intrinsic::dbg_value);
-              AttributeMask AM;
-              for (Attribute A : DVDecl->getAttributes().getFnAttrs())
-                if (A.isStringAttribute() ||
-                    (A.getKindAsEnum() != Attribute::NoUnwind &&
-                     A.getKindAsEnum() != Attribute::Memory))
-                  AM.addAttribute(A);
-              DVDecl->removeFnAttrs(AM);
+          // Process both llvm.dbg.value and llvm.dbg.assign here. We convert
+          // llvm.dbg.assign to llvm.dbg.value by dropping the last arguments,
+          // and remove redundant llvm.dbg.values.
+          if (auto *DV = dyn_cast<DbgValueInst>(&I)) {
+            // Keep track of the last location where we saw any debug value for
+            // a variable.
+            DILocalVariable *V = DV->getVariable();
+            DIExpression *E = DV->getExpression();
+            std::pair<Instruction *, DbgValueInst *> &DbgValue = DbgValues[V];
+            std::pair<Instruction *, DbgValueInst *> &DbgValueFragment =
+                DbgValueFragments[{V, E}];
+            if (DbgValue.second) {
+              // If there is a later value of the same fragment at the same
+              // location, this value is redundant.
+              if (DbgValueFragment.first == NextNonDebugInst) {
+                DV->eraseFromParent();
+                continue;
+              }
+              // If there is a later identical value of the same fragment at a
+              // later point, and there have been no intervening values of
+              // different possibly overlapping fragments, that later value is
+              // redundant.
+              if (DbgValueFragment.second &&
+                  DbgValueFragment.second == DbgValue.second &&
+                  DbgValueFragment.second->getValue() == DV->getValue()) {
+                DbgValue.second->eraseFromParent();
+              }
             }
-            NewDV = cast<DbgValueInst>(
-                CallInst::Create(DVDecl,
-                                 {DV->getArgOperand(0), DV->getArgOperand(1),
-                                  DV->getArgOperand(2)},
-                                 {}, "", std::next(DV->getIterator())));
-            NewDV->setTailCall();
-            NewDV->setDebugLoc(DV->getDebugLoc());
-            DV->eraseFromParent();
+            // If this is already an llvm.dbg.value instruction, just keep it,
+            // otherwise convert it.
+            DbgValueInst *NewDV;
+            if (DV->getIntrinsicID() == Intrinsic::dbg_value) {
+              NewDV = DV;
+            } else {
+              if (!DVDecl) {
+                DVDecl =
+                    Intrinsic::getOrInsertDeclaration(&M, Intrinsic::dbg_value);
+                AttributeMask AM;
+                for (Attribute A : DVDecl->getAttributes().getFnAttrs())
+                  if (A.isStringAttribute() ||
+                      (A.getKindAsEnum() != Attribute::NoUnwind &&
+                       A.getKindAsEnum() != Attribute::Memory))
+                    AM.addAttribute(A);
+                DVDecl->removeFnAttrs(AM);
+              }
+              NewDV = cast<DbgValueInst>(
+                  CallInst::Create(DVDecl,
+                                   {DV->getArgOperand(0), DV->getArgOperand(1),
+                                    DV->getArgOperand(2)},
+                                   {}, "", std::next(DV->getIterator())));
+              NewDV->setTailCall();
+              NewDV->setDebugLoc(DV->getDebugLoc());
+              DV->eraseFromParent();
+            }
+            DbgValue = DbgValueFragment = {NextNonDebugInst, NewDV};
+            continue;
           }
-          DbgValue = DbgValueFragment = {NextNonDebugInst, NewDV};
-          continue;
         }
-      }
-      // If this is the entry block, if the first value we see for each debug
-      // value is undef, it is redundant.
-      if (IsEntryBlock) {
-        DenseSet<DILocalVariable *> Seen;
-        for (Instruction &I : make_early_inc_range(BB)) {
-          auto *DV = dyn_cast<DbgValueInst>(&I);
-          if (!DV || Seen.contains(DV->getVariable()))
-            continue;
-          if (isa<UndefValue>(DV->getValue())) {
-            DV->eraseFromParent();
-            continue;
+        // If this is the entry block, if the first value we see for each debug
+        // value is undef, it is redundant.
+        if (IsEntryBlock) {
+          DenseSet<DILocalVariable *> Seen;
+          for (Instruction &I : make_early_inc_range(BB)) {
+            auto *DV = dyn_cast<DbgValueInst>(&I);
+            if (!DV || Seen.contains(DV->getVariable()))
+              continue;
+            if (isa<UndefValue>(DV->getValue())) {
+              DV->eraseFromParent();
+              continue;
+            }
+            Seen.insert(DV->getVariable());
           }
-          Seen.insert(DV->getVariable());
         }
+        IsEntryBlock = false;
       }
-      IsEntryBlock = false;
     }
   }
 

>From e68eff88a068ace9189c24966b62d61c2574aa14 Mon Sep 17 00:00:00 2001
From: Harald van Dijk <hdijk at accesssoftek.com>
Date: Mon, 8 Jun 2026 14:27:12 +0100
Subject: [PATCH 4/4] Same for (DbgVariables)Seen

---
 .../lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp b/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
index 9fa5fc689dcdf..53f738c90c0da 100644
--- a/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
+++ b/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
@@ -82,9 +82,13 @@ DXILDebugInfoMap DXILDebugInfoPass::run(Module &M) {
     DenseMap<std::pair<DILocalVariable *, DIExpression *>,
              std::pair<Instruction *, DbgValueInst *>>
         DbgValueFragments;
+    // Likewise, logically, this should be a variable in the
+    // for (Function &F : M) loop.
+    DenseSet<DILocalVariable *> DbgVariablesSeen;
 
     for (Function &F : M) {
       bool IsEntryBlock = true;
+      DbgVariablesSeen.clear();
       for (BasicBlock &BB : F) {
         Instruction *NextNonDebugInst = nullptr;
         DbgValues.clear();
@@ -162,16 +166,15 @@ DXILDebugInfoMap DXILDebugInfoPass::run(Module &M) {
         // If this is the entry block, if the first value we see for each debug
         // value is undef, it is redundant.
         if (IsEntryBlock) {
-          DenseSet<DILocalVariable *> Seen;
           for (Instruction &I : make_early_inc_range(BB)) {
             auto *DV = dyn_cast<DbgValueInst>(&I);
-            if (!DV || Seen.contains(DV->getVariable()))
+            if (!DV || DbgVariablesSeen.contains(DV->getVariable()))
               continue;
             if (isa<UndefValue>(DV->getValue())) {
               DV->eraseFromParent();
               continue;
             }
-            Seen.insert(DV->getVariable());
+            DbgVariablesSeen.insert(DV->getVariable());
           }
         }
         IsEntryBlock = false;



More information about the llvm-commits mailing list