1//===- DXILDebugInfoMap.cpp - DXIL debug info serialization --------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "DXILDebugInfoMap.h"
10#include "llvm/BinaryFormat/Dwarf.h"
11#include "llvm/IR/DebugInfo.h"
12#include "llvm/IR/Instructions.h"
13#include "llvm/IR/Module.h"
14#include "llvm/Support/Casting.h"
15
16using namespace llvm;
17using namespace llvm::dxil;
18
19static void replaceDbgVariableIntr(DbgVariableIntrinsic *DVI, Function *NewF,
20 DXILDebugInfoMap &Res) {
21 if (DVI->getIntrinsicID() != Intrinsic::dbg_value)
22 return;
23
24 Type *Int64Ty = Type::getInt64Ty(C&: DVI->getContext());
25 Constant *ZeroOffset = ConstantInt::get(Ty: Int64Ty, V: 0);
26 Value *NewOps[] = {DVI->getOperand(i_nocapture: 0), ZeroOffset, DVI->getOperand(i_nocapture: 1),
27 DVI->getOperand(i_nocapture: 2)};
28
29 CallInst *NewI = CallInst::Create(Ty: NewF->getFunctionType(), Func: NewF, Args: NewOps);
30 NewI->setTailCall(DVI->isTailCall());
31 NewI->setDebugLoc(DVI->getDebugLoc());
32 Res.InstReplace.insert(KV: {DVI, decltype(Res.InstReplace)::mapped_type(NewI)});
33}
34
35static void replaceDbgValue(Module &M, DXILDebugInfoMap &Res) {
36 Function *F = getDeclarationIfExists(M: &M, id: Intrinsic::dbg_value);
37 if (!F)
38 return;
39
40 FunctionType *FT = F->getFunctionType();
41 Type *Int64Ty = Type::getInt64Ty(C&: F->getContext());
42 FunctionType *NewFT = FunctionType::get(
43 Result: FT->getReturnType(),
44 Params: {FT->getParamType(i: 0), Int64Ty, FT->getParamType(i: 1), FT->getParamType(i: 2)},
45 /*isVarArg=*/false);
46 Function *NewF = Function::Create(Ty: NewFT, Linkage: F->getLinkage(), N: F->getName());
47 NewF->copyAttributesFrom(Src: F);
48 Res.FuncReplace.insert(KV: {F, decltype(Res.FuncReplace)::mapped_type(NewF)});
49
50 for (User *U : F->users())
51 replaceDbgVariableIntr(DVI: cast<DbgVariableIntrinsic>(Val: U), NewF, Res);
52}
53
54DXILDebugInfoMap dxil::collectDXILDebugInfo(Module &M) {
55 DXILDebugInfoMap Res;
56 DebugInfoFinder DIF;
57 DIF.processModule(M);
58
59 replaceDbgValue(M, Res);
60
61 for (DICompileUnit *CU : DIF.compile_units()) {
62 DISourceLanguageName Lang = CU->getSourceLanguage();
63 if (Lang.hasVersionedName()) {
64 auto LangName = static_cast<dwarf::SourceLanguageName>(Lang.getName());
65 Lang = dwarf::toDW_LANG(name: LangName, version: Lang.getVersion())
66 .value_or(u: dwarf::SourceLanguage{});
67 auto *NewCU = DICompileUnit::getDistinct(
68 Context&: M.getContext(), SourceLanguage: Lang, File: CU->getFile(), Producer: CU->getProducer(),
69 IsOptimized: CU->isOptimized(), Flags: CU->getFlags(), RuntimeVersion: CU->getRuntimeVersion(),
70 SplitDebugFilename: CU->getSplitDebugFilename(), EmissionKind: CU->getEmissionKind(),
71 EnumTypes: CU->getEnumTypes(), RetainedTypes: CU->getRetainedTypes(), GlobalVariables: CU->getGlobalVariables(),
72 ImportedEntities: CU->getImportedEntities(), Macros: CU->getMacros(), DWOId: CU->getDWOId(),
73 SplitDebugInlining: CU->getSplitDebugInlining(), DebugInfoForProfiling: CU->getDebugInfoForProfiling(),
74 NameTableKind: CU->getNameTableKind(), RangesBaseAddress: CU->getRangesBaseAddress(), SysRoot: CU->getSysRoot(),
75 SDK: CU->getSDK());
76 Res.MDReplace.insert(KV: {CU, NewCU});
77 }
78 }
79
80 std::vector<std::pair<const DICompileUnit *, const Metadata *>> CUSubprograms;
81
82 for (const Function &F : M) {
83 if (const DISubprogram *SP = F.getSubprogram()) {
84 auto *FunctionMD = ConstantAsMetadata::get(C: const_cast<Function *>(&F));
85 Res.MDExtra.insert(KV: {SP, FunctionMD});
86 }
87 }
88
89 for (const DISubprogram *SP : DIF.subprograms()) {
90 const DISubprogram *NewSP = SP;
91
92 static constexpr auto SupportedDIFlags =
93 static_cast<DISubprogram::DIFlags>(DISubprogram::FlagExportSymbols - 1);
94 static constexpr auto SupportedDISPFlags =
95 static_cast<DISubprogram::DISPFlags>(DISubprogram::SPFlagPure - 1);
96 if (SP->isDistinct() || SP->getFlags() & ~SupportedDIFlags ||
97 SP->getSPFlags() & ~SupportedDISPFlags) {
98 NewSP = DISubprogram::get(
99 Context&: M.getContext(), Scope: SP->getScope(), Name: SP->getName(), LinkageName: SP->getLinkageName(),
100 File: SP->getFile(), Line: SP->getLine(), Type: SP->getType(), ScopeLine: SP->getScopeLine(),
101 ContainingType: SP->getContainingType(), VirtualIndex: SP->getVirtualIndex(),
102 ThisAdjustment: SP->getThisAdjustment(), Flags: SP->getFlags() & SupportedDIFlags,
103 SPFlags: SP->getSPFlags() & SupportedDISPFlags, Unit: SP->getUnit(),
104 TemplateParams: SP->getTemplateParams(), Declaration: SP->getDeclaration(), RetainedNodes: SP->getRetainedNodes(),
105 ThrownTypes: SP->getThrownTypes(), Annotations: SP->getAnnotations(), TargetFuncName: SP->getTargetFuncName(),
106 UsesKeyInstructions: SP->getKeyInstructionsEnabled());
107
108 Res.MDReplace.insert(KV: {SP, NewSP});
109 if (auto It = Res.MDExtra.find(Val: SP); It != Res.MDExtra.end()) {
110 const Metadata *FunctionMD = It->second;
111 Res.MDExtra.erase(I: It);
112 Res.MDExtra.insert(KV: {NewSP, FunctionMD});
113 }
114 }
115
116 if (SP->getUnit())
117 CUSubprograms.push_back(x: {SP->getUnit(), SP});
118 }
119
120 std::stable_sort(
121 first: CUSubprograms.begin(), last: CUSubprograms.end(), comp: [](auto &&A, auto &&B) {
122 return std::less<const DICompileUnit *>()(A.first, B.first);
123 });
124 for (auto It = CUSubprograms.begin(), End = CUSubprograms.end(); It != End;) {
125 const DICompileUnit *CU = It->first;
126 const DICompileUnit *NewCU =
127 cast<DICompileUnit>(Val: Res.MDReplace.lookup_or(Val: CU, Default&: CU));
128 SmallVector<Metadata *, 16> Subprograms;
129 do {
130 Subprograms.push_back(Elt: const_cast<Metadata *>(It->second));
131 } while (++It != End && It->first == CU);
132 const auto *SubprogramsMD = MDTuple::get(Context&: M.getContext(), MDs: Subprograms);
133 Res.MDExtra.insert(KV: {NewCU, SubprogramsMD});
134 }
135
136 for (const GlobalVariable &GV : M.globals()) {
137 SmallVector<DIGlobalVariableExpression *, 4> GVEs;
138 GV.getDebugInfo(GVs&: GVEs);
139 for (DIGlobalVariableExpression *GVE : GVEs) {
140 if (GVE->getExpression()->getNumElements())
141 continue;
142 auto [It, Inserted] = Res.MDExtra.insert(
143 KV: {GVE->getVariable(),
144 ValueAsMetadata::get(V: const_cast<GlobalVariable *>(&GV))});
145 if (!Inserted)
146 It->second = nullptr;
147 }
148 }
149
150 for (DIGlobalVariableExpression *GVE : DIF.global_variables())
151 Res.MDReplace.insert(KV: {GVE, GVE->getVariable()});
152
153 for (DIScope *S : DIF.scopes()) {
154 if (auto *CB = dyn_cast<DICommonBlock>(Val: S)) {
155 const Metadata *Scope = CB->getScope();
156 Scope = Res.MDReplace.lookup_or(Val: Scope, Default&: Scope);
157 Res.MDReplace.insert(KV: {CB, Scope});
158 }
159 }
160
161 for (DIType *T : DIF.types()) {
162 if (auto *SR = dyn_cast<DISubrangeType>(Val: T)) {
163 DIType *BT = SR->getBaseType();
164 if (!BT)
165 BT = DIBasicType::get(Context&: SR->getContext(), Tag: dwarf::DW_TAG_base_type,
166 Name: SR->getName(), SizeInBits: SR->getSizeInBits(),
167 AlignInBits: SR->getAlignInBits(), Encoding: dwarf::DW_ATE_unsigned,
168 NumExtraInhabitants: SR->getNumExtraInhabitants(),
169 /*DataSizeInBits=*/0, Flags: SR->getFlags());
170 Res.MDReplace.insert(KV: {T, BT});
171 }
172 }
173
174 return Res;
175}
176