blob: 0fa81186000f9504ec08b7e43d418fa78e4eaf17 [file] [edit]
//===--- DXILDebugInfo.cpp - analysis&lowering for Debug info -*- C++ -*- ---=//
//
// 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 "DXILDebugInfo.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicsDirectX.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#define DEBUG_TYPE "dx-debug-info"
using namespace llvm;
using namespace llvm::dxil;
// llvm.dbg.value has an additional "offset" operand in 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()) {
auto *DVI = cast<DbgVariableIntrinsic>(U);
replaceDbgVariableIntr(DVI, NewF, Res);
}
}
DXILDebugInfoMap DXILDebugInfoPass::run(Module &M) {
DXILDebugInfoMap Res;
DebugInfoFinder DIF;
DIF.processModule(M);
for (auto &F : M) {
for (auto &BB : F) {
for (auto &I : make_early_inc_range(reverse(BB))) {
if (auto *DL = dyn_cast<DbgLabelInst>(&I)) {
DL->eraseFromParent();
continue;
}
}
}
}
for (DISubprogram *SP : DIF.subprograms()) {
if (MDTuple *RN = cast_or_null<MDTuple>(SP->getRawRetainedNodes())) {
SmallVector<Metadata *> MDs(RN->operands());
MDs.erase(std::remove_if(MDs.begin(), MDs.end(),
[](Metadata *M) { return isa<DILabel>(M); }),
MDs.end());
SP->replaceRetainedNodes(MDTuple::get(M.getContext(), MDs));
}
}
// Re-scan the module to account for removed metadata.
DIF.reset();
DIF.processModule(M);
// Replace llvm.dbg.value with equivalent DXIL intrinsics.
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(), 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;) {
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 (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;
}