| 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 | |
| 16 | using namespace llvm; |
| 17 | using namespace llvm::dxil; |
| 18 | |
| 19 | static 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 | |
| 35 | static 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 | |
| 54 | DXILDebugInfoMap 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 | |