| //===- DXILDebugInfoMap.cpp - DXIL debug info serialization --------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "DXILDebugInfoMap.h" | |
| #include "llvm/BinaryFormat/Dwarf.h" | |
| #include "llvm/IR/DebugInfo.h" | |
| #include "llvm/IR/Instructions.h" | |
| #include "llvm/IR/Module.h" | |
| #include "llvm/Support/Casting.h" | |
| using namespace llvm; | |
| using namespace llvm::dxil; | |
| static void replaceDbgVariableIntr(DbgVariableIntrinsic *DVI, Function *NewF, | |
| DXILDebugInfoMap &Res) { | |
| if (DVI->getIntrinsicID() != Intrinsic::dbg_value) | |
| return; | |
| Type *Int64Ty = Type::getInt64Ty(DVI->getContext()); | |
| Constant *ZeroOffset = ConstantInt::get(Int64Ty, 0); | |
| Value *NewOps[] = {DVI->getOperand(0), ZeroOffset, DVI->getOperand(1), | |
| DVI->getOperand(2)}; | |
| CallInst *NewI = CallInst::Create(NewF->getFunctionType(), NewF, NewOps); | |
| NewI->setTailCall(DVI->isTailCall()); | |
| NewI->setDebugLoc(DVI->getDebugLoc()); | |
| Res.InstReplace.insert({DVI, decltype(Res.InstReplace)::mapped_type(NewI)}); | |
| } | |
| static void replaceDbgValue(Module &M, DXILDebugInfoMap &Res) { | |
| Function *F = getDeclarationIfExists(&M, Intrinsic::dbg_value); | |
| if (!F) | |
| return; | |
| FunctionType *FT = F->getFunctionType(); | |
| Type *Int64Ty = Type::getInt64Ty(F->getContext()); | |
| FunctionType *NewFT = FunctionType::get( | |
| FT->getReturnType(), | |
| {FT->getParamType(0), Int64Ty, FT->getParamType(1), FT->getParamType(2)}, | |
| /*isVarArg=*/false); | |
| Function *NewF = Function::Create(NewFT, F->getLinkage(), F->getName()); | |
| NewF->copyAttributesFrom(F); | |
| Res.FuncReplace.insert({F, decltype(Res.FuncReplace)::mapped_type(NewF)}); | |
| for (User *U : F->users()) | |
| replaceDbgVariableIntr(cast<DbgVariableIntrinsic>(U), NewF, Res); | |
| } | |
| DXILDebugInfoMap dxil::collectDXILDebugInfo(Module &M) { | |
| DXILDebugInfoMap Res; | |
| DebugInfoFinder DIF; | |
| DIF.processModule(M); | |
| replaceDbgValue(M, Res); | |
| for (DICompileUnit *CU : DIF.compile_units()) { | |
| DISourceLanguageName Lang = CU->getSourceLanguage(); | |
| if (Lang.hasVersionedName()) { | |
| auto LangName = static_cast<dwarf::SourceLanguageName>(Lang.getName()); | |
| Lang = dwarf::toDW_LANG(LangName, Lang.getVersion()) | |
| .value_or(dwarf::SourceLanguage{}); | |
| auto *NewCU = DICompileUnit::getDistinct( | |
| M.getContext(), Lang, CU->getFile(), CU->getProducer(), | |
| CU->isOptimized(), CU->getFlags(), CU->getRuntimeVersion(), | |
| CU->getSplitDebugFilename(), CU->getEmissionKind(), | |
| CU->getEnumTypes(), CU->getRetainedTypes(), CU->getGlobalVariables(), | |
| CU->getImportedEntities(), CU->getMacros(), CU->getDWOId(), | |
| CU->getSplitDebugInlining(), CU->getDebugInfoForProfiling(), | |
| CU->getNameTableKind(), CU->getRangesBaseAddress(), CU->getSysRoot(), | |
| CU->getSDK()); | |
| Res.MDReplace.insert({CU, NewCU}); | |
| } | |
| } | |
| std::vector<std::pair<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()) { | |
| 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()) { | |
| const Metadata *FunctionMD = It->second; | |
| Res.MDExtra.erase(It); | |
| Res.MDExtra.insert({NewSP, FunctionMD}); | |
| } | |
| } | |
| if (SP->getUnit()) | |
| CUSubprograms.push_back({SP->getUnit(), 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;) { | |
| const DICompileUnit *CU = It->first; | |
| const DICompileUnit *NewCU = | |
| cast<DICompileUnit>(Res.MDReplace.lookup_or(CU, CU)); | |
| SmallVector<Metadata *, 16> Subprograms; | |
| do { | |
| Subprograms.push_back(const_cast<Metadata *>(It->second)); | |
| } while (++It != End && It->first == CU); | |
| const auto *SubprogramsMD = MDTuple::get(M.getContext(), Subprograms); | |
| Res.MDExtra.insert({NewCU, SubprogramsMD}); | |
| } | |
| for (const GlobalVariable &GV : M.globals()) { | |
| SmallVector<DIGlobalVariableExpression *, 4> GVEs; | |
| GV.getDebugInfo(GVEs); | |
| for (DIGlobalVariableExpression *GVE : GVEs) { | |
| if (GVE->getExpression()->getNumElements()) | |
| continue; | |
| auto [It, Inserted] = Res.MDExtra.insert( | |
| {GVE->getVariable(), | |
| ValueAsMetadata::get(const_cast<GlobalVariable *>(&GV))}); | |
| if (!Inserted) | |
| It->second = nullptr; | |
| } | |
| } | |
| for (DIGlobalVariableExpression *GVE : DIF.global_variables()) | |
| Res.MDReplace.insert({GVE, GVE->getVariable()}); | |
| for (DIScope *S : DIF.scopes()) { | |
| if (auto *CB = dyn_cast<DICommonBlock>(S)) { | |
| const Metadata *Scope = CB->getScope(); | |
| Scope = Res.MDReplace.lookup_or(Scope, Scope); | |
| Res.MDReplace.insert({CB, Scope}); | |
| } | |
| } | |
| for (DIType *T : DIF.types()) { | |
| 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()); | |
| Res.MDReplace.insert({T, BT}); | |
| } | |
| } | |
| return Res; | |
| } |