[llvm] [DirectX] Make DISubprogram writing LLVM 3.7-compatible (PR #194418)

Harald van Dijk via llvm-commits llvm-commits at lists.llvm.org
Fri May 8 18:38:06 PDT 2026


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

>From 3b1583eb41f0a5b41f7a6b478f7c216b5b1e6b3f Mon Sep 17 00:00:00 2001
From: Harald van Dijk <hdijk at accesssoftek.com>
Date: Thu, 5 Mar 2026 19:23:42 +0000
Subject: [PATCH 1/2] [DirectX] Fixes for generation of DISubprogram

* Reverse the links between DICompileUnit and DISubprogram
* Do not write DISubprogram as distinct
* Do not write DISubprogram metadata on function declarations
* Drop invalid flags for DISubprogram
---
 .../DirectX/DXILWriter/DXILBitcodeWriter.cpp  | 12 +++--
 .../DirectX/DirectXIRPasses/DXILDebugInfo.cpp | 26 ++++++++++
 llvm/test/tools/dxil-dis/debug-info.ll        | 20 ++++----
 llvm/test/tools/dxil-dis/di-subprogram.ll     | 48 ++++++++++++++++---
 4 files changed, 86 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
index 15eb886574e6e..b0f66894348d2 100644
--- a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
+++ b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
@@ -1544,7 +1544,7 @@ void DXILBitcodeWriter::writeDICompileUnit(const DICompileUnit *N,
   Record.push_back(N->getEmissionKind());
   Record.push_back(VE.getMetadataOrNullID(N->getEnumTypes().get()));
   Record.push_back(VE.getMetadataOrNullID(N->getRetainedTypes().get()));
-  Record.push_back(/* subprograms */ 0);
+  Record.push_back(VE.getMetadataOrNullID(DebugInfo.MDExtra.lookup(N)));
   Record.push_back(VE.getMetadataOrNullID(N->getGlobalVariables().get()));
   Record.push_back(VE.getMetadataOrNullID(N->getImportedEntities().get()));
   Record.push_back(N->getDWOId());
@@ -1556,7 +1556,7 @@ void DXILBitcodeWriter::writeDICompileUnit(const DICompileUnit *N,
 void DXILBitcodeWriter::writeDISubprogram(const DISubprogram *N,
                                           SmallVectorImpl<uint64_t> &Record,
                                           unsigned Abbrev) {
-  Record.push_back(N->isDistinct());
+  Record.push_back(/*Distinct*/ false);
   Record.push_back(VE.getMetadataOrNullID(N->getScope()));
   Record.push_back(VE.getMetadataOrNullID(N->getRawName()));
   Record.push_back(VE.getMetadataOrNullID(N->getRawLinkageName()));
@@ -1569,9 +1569,9 @@ void DXILBitcodeWriter::writeDISubprogram(const DISubprogram *N,
   Record.push_back(VE.getMetadataOrNullID(N->getContainingType()));
   Record.push_back(N->getVirtuality());
   Record.push_back(N->getVirtualIndex());
-  Record.push_back(N->getFlags());
+  Record.push_back(N->getFlags() & 0x7fff);
   Record.push_back(N->isOptimized());
-  Record.push_back(VE.getMetadataOrNullID(N->getRawUnit()));
+  Record.push_back(VE.getMetadataOrNullID(DebugInfo.MDExtra.lookup(N)));
   Record.push_back(VE.getMetadataOrNullID(N->getTemplateParams().get()));
   Record.push_back(VE.getMetadataOrNullID(N->getDeclaration()));
   Record.push_back(VE.getMetadataOrNullID(N->getRetainedNodes().get()));
@@ -1888,9 +1888,13 @@ void DXILBitcodeWriter::writeFunctionMetadataAttachment(const Function &F) {
   F.getAllMetadata(MDs);
   if (!MDs.empty()) {
     for (const auto &I : MDs) {
+      if (I.first == LLVMContext::MD_dbg)
+        continue;
       Record.push_back(I.first);
       Record.push_back(VE.getMetadataID(I.second));
     }
+  }
+  if (!Record.empty()) {
     Stream.EmitRecord(bitc::METADATA_ATTACHMENT, Record, 0);
     Record.clear();
   }
diff --git a/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp b/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
index 650338949d19a..0034aa1247fe7 100644
--- a/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
+++ b/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
@@ -10,6 +10,8 @@
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/Module.h"
 
+#include <map>
+
 #define DEBUG_TYPE "dx-debug-info"
 
 using namespace llvm;
@@ -20,5 +22,29 @@ DXILDebugInfoMap DXILDebugInfoPass::run(Module &M) {
   DebugInfoFinder DIF;
   DIF.processModule(M);
 
+  std::multimap<const DICompileUnit *, const Metadata *> CUSubprograms;
+
+  for (const Function &F : M) {
+    if (const DISubprogram *SP = F.getSubprogram()) {
+      auto *FunctionMD = ConstantAsMetadata::get(const_cast<Function *>(&F));
+      Res.MDExtra.insert({SP, FunctionMD});
+    }
+  }
+
+  for (const DISubprogram *SP : DIF.subprograms())
+    if (SP->getUnit())
+      CUSubprograms.insert({SP->getUnit(), SP});
+
+  for (auto It = CUSubprograms.begin(), End = CUSubprograms.end(); It != End;) {
+    auto *CU = It->first;
+    auto CUEnd = CUSubprograms.upper_bound(CU);
+    SmallVector<Metadata *, 16> Subprograms;
+    do
+      Subprograms.push_back(const_cast<Metadata *>(It->second));
+    while (++It != CUEnd);
+    auto *SubprogramMD = MDTuple::get(M.getContext(), Subprograms);
+    Res.MDExtra.insert({CU, SubprogramMD});
+  }
+
   return Res;
 }
diff --git a/llvm/test/tools/dxil-dis/debug-info.ll b/llvm/test/tools/dxil-dis/debug-info.ll
index 420078a54dd3a..3f2d0ba835251 100644
--- a/llvm/test/tools/dxil-dis/debug-info.ll
+++ b/llvm/test/tools/dxil-dis/debug-info.ll
@@ -3,7 +3,7 @@
 target triple = "dxil-unknown-shadermodel6.7-library"
 target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
 
-; CHECK: define float @fma(float, float, float) unnamed_addr #0 !dbg [[Fn:[!][0-9]+]]
+; CHECK: define float @fma(float, float, float) unnamed_addr #0
 define dso_local float @fma(float %0, float %1, float %2) local_unnamed_addr #0 !dbg !6 {
 ; CHECK-NEXT: call void @llvm.dbg.value(metadata float %0, metadata [[VarX:[!][0-9]+]], metadata [[Expr:[!][0-9]+]]), !dbg [[Line1:[!][0-9]+]]
 ; CHECK-NEXT: call void @llvm.dbg.value(metadata float %1, metadata [[VarY:[!][0-9]+]], metadata [[Expr]]), !dbg [[Line1]]
@@ -32,15 +32,15 @@ attributes #0 = { norecurse nounwind readnone willreturn "hlsl.export" }
 
 ; CHECK:      !0 = distinct !DICompileUnit
 ; CHECK-NEXT: !1 = !DIFile(filename:
-; CHECK:      [[Fn]] = distinct !DISubprogram(name: "fma",
-; CHECK:      [[VarX]] = !DILocalVariable(tag: DW_TAG_arg_variable
-; CHECK:      [[VarY]] = !DILocalVariable(tag: DW_TAG_arg_variable
-; CHECK:      [[VarZ]] = !DILocalVariable(tag: DW_TAG_arg_variable
-; CHECK-NEXT: [[Expr]] = !DIExpression()
-; CHECK-NEXT: [[Line1]] = !DILocation(line:
-; CHECK-NEXT: [[Line2]] = !DILocation(line:
-; CHECK-NEXT: [[Line3]] = !DILocation(line:
-; CHECK-NEXT: {{[!][0-9]+}} = !DILocation(line:
+; CHECK:      [[Fn:[!][0-9]+]] = !DISubprogram(name: "fma",
+; CHECK:      [[VarX]] = !DILocalVariable(tag:
+; CHECK:      [[VarY]] = !DILocalVariable(tag:
+; CHECK:      [[VarZ]] = !DILocalVariable(tag:
+; CHECK:      [[Expr]] = !DIExpression()
+; CHECK:      [[Line1]] = !DILocation(line:
+; CHECK:      [[Line2]] = !DILocation(line:
+; CHECK:      [[Line3]] = !DILocation(line:
+; CHECK:      {{[!][0-9]+}} = !DILocation(line:
 
 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
 !1 = !DIFile(filename: "in.c", directory: "dir")
diff --git a/llvm/test/tools/dxil-dis/di-subprogram.ll b/llvm/test/tools/dxil-dis/di-subprogram.ll
index 912421fb28ae5..78fe96ec3adc3 100644
--- a/llvm/test/tools/dxil-dis/di-subprogram.ll
+++ b/llvm/test/tools/dxil-dis/di-subprogram.ll
@@ -1,16 +1,52 @@
 ; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
 target triple = "dxil-unknown-shadermodel6.7-library"
 
+define float @fmaf(float %x, float %y, float %z) !dbg !4 {
+  unreachable
+}
+
+declare !dbg !14 double @fma(double %x, double %y, double %z)
+
 !llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!3, !4}
+!llvm.module.flags = !{!12, !13}
+!llvm.used = !{!5}
 
-; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Some Compiler", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2)
+; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Some Compiler", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3)
 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Some Compiler", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
 ; CHECK: !1 = !DIFile(filename: "some-source", directory: "some-path")
 !1 = !DIFile(filename: "some-source", directory: "some-path")
 !2 = !{}
 
-; CHECK: !3 = !{i32 2, !"Dwarf Version", i32 4}
-!3 = !{i32 2, !"Dwarf Version", i32 4}
-; CHECK: !4 = !{i32 2, !"Debug Info Version", i32 3}
-!4 = !{i32 2, !"Debug Info Version", i32 3}
+; CHECK: !4 = !DISubprogram(name: "fmaf", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, function: float (float, float, float)* @fmaf, variables: !8)
+!4 = distinct !DISubprogram(name: "fmaf", scope: !1, file: !1, line: 1, type: !5, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+
+; CHECK: !5 = !DISubroutineType(types: !6)
+!5 = !DISubroutineType(types: !6)
+
+; CHECK: !6 = !{!7, !7, !7, !7}
+!6 = !{!7, !7, !7, !7}
+
+; CHECK: !7 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
+!7 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
+
+; CHECK: !8 = !{!9, !10, !11}
+!8 = !{!9, !10, !11}
+
+; CHECK: !9 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "x", arg: 1, scope: !4, file: !1, line: 1, type: !7)
+!9 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !1, line: 1, type: !7)
+
+; CHECK: !10 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "y", arg: 2, scope: !4, file: !1, line: 1, type: !7)
+!10 = !DILocalVariable(name: "y", arg: 2, scope: !4, file: !1, line: 1, type: !7)
+
+; CHECK: !11 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "z", arg: 3, scope: !4, file: !1, line: 1, type: !7)
+!11 = !DILocalVariable(name: "z", arg: 3, scope: !4, file: !1, line: 1, type: !7)
+
+; CHECK: !12 = !{i32 2, !"Dwarf Version", i32 4}
+!12 = !{i32 2, !"Dwarf Version", i32 4}
+; CHECK: !13 = !{i32 2, !"Debug Info Version", i32 3}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+
+!14 = !DISubprogram(name: "fma", scope: !1, file: !1, line: 1, type: !15, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
+!15 = !DISubroutineType(types: !16)
+!16 = !{!17, !17, !17, !17}
+!17 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)

>From 3f198fc7faf1e3f77b8c076cd36016102dd3a274 Mon Sep 17 00:00:00 2001
From: Harald van Dijk <hdijk at accesssoftek.com>
Date: Wed, 6 May 2026 22:50:00 +0100
Subject: [PATCH 2/2] Move logic into DXILDebugInfoPass instead

---
 .../DirectX/DXILWriter/DXILBitcodeWriter.cpp  |  4 +-
 .../DirectX/DirectXIRPasses/DXILDebugInfo.cpp | 53 +++++++++++++++----
 2 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
index b0f66894348d2..0489e75817fbe 100644
--- a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
+++ b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
@@ -1556,7 +1556,7 @@ void DXILBitcodeWriter::writeDICompileUnit(const DICompileUnit *N,
 void DXILBitcodeWriter::writeDISubprogram(const DISubprogram *N,
                                           SmallVectorImpl<uint64_t> &Record,
                                           unsigned Abbrev) {
-  Record.push_back(/*Distinct*/ false);
+  Record.push_back(N->isDistinct());
   Record.push_back(VE.getMetadataOrNullID(N->getScope()));
   Record.push_back(VE.getMetadataOrNullID(N->getRawName()));
   Record.push_back(VE.getMetadataOrNullID(N->getRawLinkageName()));
@@ -1569,7 +1569,7 @@ void DXILBitcodeWriter::writeDISubprogram(const DISubprogram *N,
   Record.push_back(VE.getMetadataOrNullID(N->getContainingType()));
   Record.push_back(N->getVirtuality());
   Record.push_back(N->getVirtualIndex());
-  Record.push_back(N->getFlags() & 0x7fff);
+  Record.push_back(N->getFlags());
   Record.push_back(N->isOptimized());
   Record.push_back(VE.getMetadataOrNullID(DebugInfo.MDExtra.lookup(N)));
   Record.push_back(VE.getMetadataOrNullID(N->getTemplateParams().get()));
diff --git a/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp b/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
index 0034aa1247fe7..fe1614dbe1879 100644
--- a/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
+++ b/llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "DXILDebugInfo.h"
+#include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/Module.h"
 
@@ -22,7 +23,7 @@ DXILDebugInfoMap DXILDebugInfoPass::run(Module &M) {
   DebugInfoFinder DIF;
   DIF.processModule(M);
 
-  std::multimap<const DICompileUnit *, const Metadata *> CUSubprograms;
+  std::vector<std::pair<const DICompileUnit *, const Metadata *>> CUSubprograms;
 
   for (const Function &F : M) {
     if (const DISubprogram *SP = F.getSubprogram()) {
@@ -31,19 +32,53 @@ DXILDebugInfoMap DXILDebugInfoPass::run(Module &M) {
     }
   }
 
-  for (const DISubprogram *SP : DIF.subprograms())
+  for (const DISubprogram *SP : DIF.subprograms()) {
+    const DISubprogram *NewSP = SP;
+
+    static constexpr auto SupportedDIFlags =
+        static_cast<DISubprogram::DIFlags>(DISubprogram::FlagExportSymbols - 1);
+    static constexpr auto SupportedDISPFlags =
+        static_cast<DISubprogram::DISPFlags>(DISubprogram::SPFlagPure - 1);
+    if (SP->isDistinct() || SP->getFlags() & ~SupportedDIFlags ||
+        SP->getSPFlags() & ~SupportedDISPFlags) {
+      NewSP = DISubprogram::get(
+          M.getContext(), SP->getScope(), SP->getName(), SP->getLinkageName(),
+          SP->getFile(), SP->getLine(), SP->getType(), SP->getScopeLine(),
+          SP->getContainingType(), SP->getVirtualIndex(),
+          SP->getThisAdjustment(), SP->getFlags() & SupportedDIFlags,
+          SP->getSPFlags() & SupportedDISPFlags, SP->getUnit(),
+          SP->getTemplateParams(), SP->getDeclaration(), SP->getRetainedNodes(),
+          SP->getThrownTypes(), SP->getAnnotations(), SP->getTargetFuncName(),
+          SP->getKeyInstructionsEnabled());
+
+      Res.MDReplace.insert({SP, NewSP});
+
+      if (auto It = Res.MDExtra.find(SP); It != Res.MDExtra.end()) {
+        auto *FunctionMD = It->second;
+        Res.MDExtra.erase(It);
+        Res.MDExtra.insert({NewSP, FunctionMD});
+      }
+    }
+
     if (SP->getUnit())
-      CUSubprograms.insert({SP->getUnit(), SP});
+      CUSubprograms.push_back(
+          {SP->getUnit(), static_cast<const Metadata *>(SP)});
+  }
 
+  std::stable_sort(
+      CUSubprograms.begin(), CUSubprograms.end(), [](auto &&A, auto &&B) {
+        return std::less<const DICompileUnit *>()(A.first, B.first);
+      });
   for (auto It = CUSubprograms.begin(), End = CUSubprograms.end(); It != End;) {
-    auto *CU = It->first;
-    auto CUEnd = CUSubprograms.upper_bound(CU);
+    const DICompileUnit *CU = It->first;
+    const DICompileUnit *NewCU =
+        cast<DICompileUnit>(Res.MDReplace.lookup_or(CU, CU));
     SmallVector<Metadata *, 16> Subprograms;
-    do
+    do {
       Subprograms.push_back(const_cast<Metadata *>(It->second));
-    while (++It != CUEnd);
-    auto *SubprogramMD = MDTuple::get(M.getContext(), Subprograms);
-    Res.MDExtra.insert({CU, SubprogramMD});
+    } while (++It != End && It->first == CU);
+    const auto *SubprogramsMD = MDTuple::get(M.getContext(), Subprograms);
+    Res.MDExtra.insert({NewCU, SubprogramsMD});
   }
 
   return Res;



More information about the llvm-commits mailing list