LLVM 23.0.0git
DXILDebugInfo.cpp
Go to the documentation of this file.
1//===--- DXILDebugInfo.cpp - analysis&lowering for Debug info -*- C++ -*- ---=//
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 "DXILDebugInfo.h"
10#include "DirectX.h"
13#include "llvm/IR/DebugInfo.h"
15#include "llvm/IR/IntrinsicsDirectX.h"
16#include "llvm/IR/Module.h"
18
19#define DEBUG_TYPE "dx-debug-info"
20
21using namespace llvm;
22using namespace llvm::dxil;
23
24// llvm.dbg.value has an additional "offset" operand in DXIL.
26 DXILDebugInfoMap &Res) {
27 if (DVI->getIntrinsicID() != Intrinsic::dbg_value) {
28 return;
29 }
30
31 Type *Int64Ty = Type::getInt64Ty(DVI->getContext());
32 Constant *ZeroOffset = ConstantInt::get(Int64Ty, 0);
33
34 Value *NewOps[] = {
35 DVI->getOperand(0),
36 ZeroOffset,
37 DVI->getOperand(1),
38 DVI->getOperand(2),
39 };
40
41 CallInst *NewI = CallInst::Create(NewF->getFunctionType(), NewF, NewOps);
42 NewI->setTailCall(DVI->isTailCall());
43 NewI->setDebugLoc(DVI->getDebugLoc());
44 Res.InstReplace.insert({DVI, decltype(Res.InstReplace)::mapped_type(NewI)});
45}
46
48 Function *F = getDeclarationIfExists(&M, Intrinsic::dbg_value);
49 if (!F)
50 return;
51
52 FunctionType *FT = F->getFunctionType();
53 Type *Int64Ty = Type::getInt64Ty(F->getContext());
55 FT->getReturnType(),
56 {FT->getParamType(0), Int64Ty, FT->getParamType(1), FT->getParamType(2)},
57 /*isVarArg=*/false);
58 Function *NewF = Function::Create(NewFT, F->getLinkage(), F->getName());
59 NewF->copyAttributesFrom(F);
60 Res.FuncReplace.insert({F, decltype(Res.FuncReplace)::mapped_type(NewF)});
61
62 for (User *U : F->users()) {
63 auto *DVI = cast<DbgVariableIntrinsic>(U);
64 replaceDbgVariableIntr(DVI, NewF, Res);
65 }
66}
67
69 M.convertFromNewDbgValues();
70
73 DIF.processModule(M);
74
75 const AttributeMask &AttrMask = getNonDXILAttributeMask();
76 for (auto &F : M) {
77 F.removeFnAttrs(AttrMask);
78 F.removeRetAttrs(AttrMask);
79 for (unsigned ArgNo = 0; ArgNo != F.arg_size(); ++ArgNo)
80 F.removeParamAttrs(ArgNo, AttrMask);
81
82 for (auto &BB : F) {
83 for (auto &I : make_early_inc_range(reverse(BB))) {
84 if (auto *DL = dyn_cast<DbgLabelInst>(&I)) {
85 DL->eraseFromParent();
86 continue;
87 }
88 }
89 }
90 }
91
92 for (DISubprogram *SP : DIF.subprograms()) {
93 if (MDTuple *RN = cast_or_null<MDTuple>(SP->getRawRetainedNodes())) {
94 SmallVector<Metadata *> MDs(RN->operands());
95 MDs.erase(std::remove_if(MDs.begin(), MDs.end(),
96 [](Metadata *M) { return isa<DILabel>(M); }),
97 MDs.end());
98 SP->replaceRetainedNodes(MDTuple::get(M.getContext(), MDs));
99 }
100 }
101
102 // Re-scan the module to account for removed metadata.
103 DIF.reset();
104 DIF.processModule(M);
105
106 // Replace llvm.dbg.value with equivalent DXIL intrinsics.
107 replaceDbgValue(M, Res);
108
109 for (DICompileUnit *CU : DIF.compile_units()) {
110 DISourceLanguageName Lang = CU->getSourceLanguage();
111 if (Lang.hasVersionedName()) {
112 auto LangName = static_cast<dwarf::SourceLanguageName>(Lang.getName());
113 Lang = dwarf::toDW_LANG(LangName, Lang.getVersion())
114 .value_or(dwarf::SourceLanguage{});
115 auto *NewCU = DICompileUnit::getDistinct(
116 M.getContext(), Lang, CU->getFile(), CU->getProducer(),
117 CU->isOptimized(), CU->getFlags(), CU->getRuntimeVersion(),
118 CU->getSplitDebugFilename(), CU->getEmissionKind(),
119 CU->getEnumTypes(), CU->getRetainedTypes(), CU->getGlobalVariables(),
120 CU->getImportedEntities(), CU->getMacros(), CU->getDWOId(),
121 CU->getSplitDebugInlining(), CU->getDebugInfoForProfiling(),
122 CU->getNameTableKind(), CU->getRangesBaseAddress(), CU->getSysRoot(),
123 CU->getSDK());
124 Res.MDReplace.insert({CU, NewCU});
125 }
126 }
127
128 std::vector<std::pair<const DICompileUnit *, const Metadata *>> CUSubprograms;
129
130 for (const Function &F : M) {
131 if (const DISubprogram *SP = F.getSubprogram()) {
132 auto *FunctionMD = ConstantAsMetadata::get(const_cast<Function *>(&F));
133 Res.MDExtra.insert({SP, FunctionMD});
134 }
135 }
136
137 for (const DISubprogram *SP : DIF.subprograms()) {
138 const DISubprogram *NewSP = SP;
139
140 static constexpr auto SupportedDIFlags =
141 static_cast<DISubprogram::DIFlags>(DISubprogram::FlagExportSymbols - 1);
142 static constexpr auto SupportedDISPFlags =
143 static_cast<DISubprogram::DISPFlags>(DISubprogram::SPFlagPure - 1);
144 if (SP->isDistinct() || SP->getFlags() & ~SupportedDIFlags ||
145 SP->getSPFlags() & ~SupportedDISPFlags) {
146 NewSP = DISubprogram::get(
147 M.getContext(), SP->getScope(), SP->getName(), SP->getLinkageName(),
148 SP->getFile(), SP->getLine(), SP->getType(), SP->getScopeLine(),
149 SP->getContainingType(), SP->getVirtualIndex(),
150 SP->getThisAdjustment(), SP->getFlags() & SupportedDIFlags,
151 SP->getSPFlags() & SupportedDISPFlags, SP->getUnit(),
152 SP->getTemplateParams(), SP->getDeclaration(), SP->getRetainedNodes(),
153 SP->getThrownTypes(), SP->getAnnotations(), SP->getTargetFuncName(),
154 SP->getKeyInstructionsEnabled());
155
156 Res.MDReplace.insert({SP, NewSP});
157
158 if (auto It = Res.MDExtra.find(SP); It != Res.MDExtra.end()) {
159 const Metadata *FunctionMD = It->second;
160 Res.MDExtra.erase(It);
161 Res.MDExtra.insert({NewSP, FunctionMD});
162 }
163 }
164
165 if (SP->getUnit())
166 CUSubprograms.push_back(
167 {SP->getUnit(), static_cast<const Metadata *>(SP)});
168 }
169
170 std::stable_sort(
171 CUSubprograms.begin(), CUSubprograms.end(), [](auto &&A, auto &&B) {
172 return std::less<const DICompileUnit *>()(A.first, B.first);
173 });
174 for (auto It = CUSubprograms.begin(), End = CUSubprograms.end(); It != End;) {
175 const DICompileUnit *CU = It->first;
176 const DICompileUnit *NewCU =
178 SmallVector<Metadata *, 16> Subprograms;
179 do {
180 Subprograms.push_back(const_cast<Metadata *>(It->second));
181 } while (++It != End && It->first == CU);
182 const auto *SubprogramsMD = MDTuple::get(M.getContext(), Subprograms);
183 Res.MDExtra.insert({NewCU, SubprogramsMD});
184 }
185
186 for (const GlobalVariable &GV : M.globals()) {
188 GV.getDebugInfo(GVEs);
189 for (DIGlobalVariableExpression *GVE : GVEs) {
190 if (GVE->getExpression()->getNumElements())
191 continue;
192 auto [It, Inserted] = Res.MDExtra.insert(
193 {GVE->getVariable(),
194 ValueAsMetadata::get(const_cast<GlobalVariable *>(&GV))});
195 if (!Inserted)
196 It->second = nullptr;
197 }
198 }
199
201 Res.MDReplace.insert({GVE, GVE->getVariable()});
202
203 for (DIType *T : DIF.types()) {
204 if (auto *SR = dyn_cast<DISubrangeType>(T)) {
205 DIType *BT = SR->getBaseType();
206 if (!BT)
208 SR->getContext(), dwarf::DW_TAG_base_type, SR->getName(),
209 SR->getSizeInBits(), SR->getAlignInBits(), dwarf::DW_ATE_unsigned,
210 SR->getNumExtraInhabitants(), /*DataSizeInBits=*/0, SR->getFlags());
211 Res.MDReplace.insert({T, BT});
212 }
213 }
214
215 return Res;
216}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
BitTracker BT
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void replaceDbgVariableIntr(DbgVariableIntrinsic *DVI, Function *NewF, DXILDebugInfoMap &Res)
static void replaceDbgValue(Module &M, DXILDebugInfoMap &Res)
This file contains constants used for implementing Dwarf debug support.
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define T
This class stores enough information to efficiently remove some attributes from an existing AttrBuild...
This class represents a function call, abstracting a target machine's calling convention.
bool isTailCall() const
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
void setTailCall(bool IsTc=true)
static ConstantAsMetadata * get(Constant *C)
Definition Metadata.h:537
This is an important base class in LLVM.
Definition Constant.h:43
A pair of DIGlobalVariable and DIExpression.
DIFlags
Debug info flags.
Wrapper structure that holds source language identity metadata that includes language name,...
uint32_t getVersion() const
Returns language version. Only valid for versioned language names.
uint16_t getName() const
Returns a versioned or unversioned language name.
Subprogram description. Uses SubclassData1.
DISPFlags
Debug info subprogram flags.
Base class for types.
This is the common base class for debug info intrinsics for variables.
Utility to find all debug info in a module.
Definition DebugInfo.h:105
LLVM_ABI void processModule(const Module &M)
Process entire module and collect debug info anchors.
LLVM_ABI void reset()
Clear all lists.
iterator_range< global_variable_expression_iterator > global_variables() const
Definition DebugInfo.h:154
iterator_range< subprogram_iterator > subprograms() const
Definition DebugInfo.h:152
iterator_range< type_iterator > types() const
Definition DebugInfo.h:158
iterator_range< compile_unit_iterator > compile_units() const
Definition DebugInfo.h:150
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:225
bool erase(const KeyT &Val)
Definition DenseMap.h:379
iterator end()
Definition DenseMap.h:143
ValueT lookup_or(const_arg_type_t< KeyT > Val, U &&Default) const
Definition DenseMap.h:262
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:286
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition Function.h:168
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:211
void copyAttributesFrom(const Function *Src)
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
Definition Function.cpp:843
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
static MDTuple * getDistinct(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1569
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1561
Tuple of metadata.
Definition Metadata.h:1489
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1518
Root of the metadata hierarchy.
Definition Metadata.h:64
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
iterator erase(const_iterator CI)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt64Ty(LLVMContext &C)
Definition Type.cpp:310
Value * getOperand(unsigned i) const
Definition User.h:207
static LLVM_ABI ValueAsMetadata * get(Value *V)
Definition Metadata.cpp:509
LLVM Value Representation.
Definition Value.h:75
LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.h:258
InstMap InstReplace
Completely replace one instruction with another in ValueEnumerator.
MDMap MDExtra
Enumerate extra metadata when Key is encountered in ValueEnumerator.
FuncMap FuncReplace
Completely replace one function with another in ValueEnumerator.
MDMap MDReplace
Completely replace one metadata with another in ValueEnumerator.
SourceLanguageName
Definition Dwarf.h:229
std::optional< SourceLanguage > toDW_LANG(SourceLanguageName name, uint32_t version)
Convert a DWARF 6 pair of language name and version to a DWARF 5 DW_LANG.
Definition Dwarf.h:237
DXILDebugInfoMap run(Module &M)
const AttributeMask & getNonDXILAttributeMask()
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
auto cast_or_null(const Y &Val)
Definition Casting.h:714
auto reverse(ContainerTy &&C)
Definition STLExtras.h:407
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559