1844 lines
77 KiB
C++
1844 lines
77 KiB
C++
//===- SPIRVToLLVMDbgTran.cpp - Converts debug info to LLVM -----*- C++ -*-===//
|
|
//
|
|
// The LLVM/SPIR-V Translator
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
// Copyright (c) 2018 Intel Corporation. All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
// to deal with the Software without restriction, including without limitation
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
//
|
|
// Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimers.
|
|
// Redistributions in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the following disclaimers in the documentation
|
|
// and/or other materials provided with the distribution.
|
|
// Neither the names of Intel Corporation, nor the names of its
|
|
// contributors may be used to endorse or promote products derived from this
|
|
// Software without specific prior written permission.
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
|
|
// THE SOFTWARE.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements translation of debug info from SPIR-V to LLVM metadata
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SPIRVToLLVMDbgTran.h"
|
|
#include "SPIRV.debug.h"
|
|
#include "SPIRVEntry.h"
|
|
#include "SPIRVFunction.h"
|
|
#include "SPIRVInstruction.h"
|
|
#include "SPIRVInternal.h"
|
|
#include "SPIRVReader.h"
|
|
#include "SPIRVType.h"
|
|
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/IR/DIBuilder.h"
|
|
#include "llvm/IR/DebugProgramInstruction.h"
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
#include "llvm/IR/Module.h"
|
|
|
|
using namespace SPIRVDebug::Operand;
|
|
|
|
namespace SPIRV {
|
|
|
|
static uint64_t getDerivedSizeInBits(const DIType *Ty) {
|
|
if (auto Size = Ty->getSizeInBits())
|
|
return Size;
|
|
if (auto *DT = llvm::dyn_cast<const llvm::DIDerivedType>(Ty))
|
|
if (auto *BT = llvm::dyn_cast<const llvm::DIType>(DT->getRawBaseType()))
|
|
return getDerivedSizeInBits(BT);
|
|
return 0;
|
|
}
|
|
SPIRVToLLVMDbgTran::SPIRVToLLVMDbgTran(SPIRVModule *TBM, Module *TM,
|
|
SPIRVToLLVM *Reader)
|
|
: BM(TBM), M(TM), SPIRVReader(Reader) {
|
|
Enable = BM->hasDebugInfo();
|
|
}
|
|
|
|
void SPIRVToLLVMDbgTran::addDbgInfoVersion() {
|
|
if (!Enable)
|
|
return;
|
|
M->addModuleFlag(Module::Warning, "Debug Info Version",
|
|
DEBUG_METADATA_VERSION);
|
|
}
|
|
|
|
DIFile *
|
|
SPIRVToLLVMDbgTran::getDIFile(const std::string &FileName,
|
|
std::optional<DIFile::ChecksumInfo<StringRef>> CS,
|
|
std::optional<StringRef> Source) {
|
|
return getOrInsert(FileMap, FileName, [=]() {
|
|
SplitFileName Split(FileName);
|
|
// Use the first builder from the map to crete DIFile since it's
|
|
// relations with other debug metadata is not going through DICompileUnit
|
|
if (!Split.BaseName.empty())
|
|
return BuilderMap.begin()->second->createFile(Split.BaseName, Split.Path,
|
|
CS, Source);
|
|
return static_cast<DIFile *>(nullptr);
|
|
});
|
|
}
|
|
|
|
SPIRVExtInst *SPIRVToLLVMDbgTran::getDbgInst(const SPIRVId Id) {
|
|
SPIRVEntry *E = BM->getEntry(Id);
|
|
if (isa<OpExtInst>(E)) {
|
|
SPIRVExtInst *EI = static_cast<SPIRVExtInst *>(E);
|
|
if (EI->getExtSetKind() == SPIRV::SPIRVEIS_Debug ||
|
|
EI->getExtSetKind() == SPIRV::SPIRVEIS_OpenCL_DebugInfo_100 ||
|
|
EI->getExtSetKind() ==
|
|
SPIRV::SPIRVEIS_NonSemantic_Shader_DebugInfo_100 ||
|
|
EI->getExtSetKind() == SPIRV::SPIRVEIS_NonSemantic_Shader_DebugInfo_200)
|
|
return EI;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Check if module is generated using NonSemantic.Shader.DebugInfo.XXX
|
|
// extended instruction set
|
|
inline bool isNonSemanticDebugInfo(const SPIRVExtInstSetKind Kind) {
|
|
return (Kind == SPIRVEIS_NonSemantic_Shader_DebugInfo_100 ||
|
|
Kind == SPIRVEIS_NonSemantic_Shader_DebugInfo_200);
|
|
}
|
|
|
|
// Get integer parameter of debug instruction considering whether it's
|
|
// Literal or <id> of OpConstant instruction depending on DebugInfo
|
|
// extended instruction set kind
|
|
SPIRVWord
|
|
SPIRVToLLVMDbgTran::getConstantValueOrLiteral(const std::vector<SPIRVWord> &Ops,
|
|
const SPIRVWord Idx,
|
|
const SPIRVExtInstSetKind Kind) {
|
|
if (!isNonSemanticDebugInfo(Kind))
|
|
return Ops[Idx];
|
|
|
|
SPIRVValue *SPVConst = BM->get<SPIRVValue>(Ops[Idx]);
|
|
assert(isConstantOpCode(SPVConst->getOpCode()) &&
|
|
"NonSemantic Debug instruction's parameters must be OpConstant");
|
|
ConstantInt *Const =
|
|
cast<ConstantInt>(SPIRVReader->transValue(SPVConst, nullptr, nullptr));
|
|
return Const->getZExtValue();
|
|
}
|
|
|
|
const std::string &SPIRVToLLVMDbgTran::getString(const SPIRVId Id) {
|
|
SPIRVString *String = BM->get<SPIRVString>(Id);
|
|
assert(String && "Invalid string");
|
|
return String->getStr();
|
|
}
|
|
|
|
const std::string
|
|
SPIRVToLLVMDbgTran::getStringSourceContinued(const SPIRVId Id,
|
|
SPIRVExtInst *DebugInst) {
|
|
if (!isValidId(Id) || getDbgInst<SPIRVDebug::DebugInfoNone>(Id))
|
|
return "";
|
|
std::string Str = BM->get<SPIRVString>(Id)->getStr();
|
|
using namespace SPIRVDebug::Operand::SourceContinued;
|
|
for (auto *I : DebugInst->getContinuedInstructions()) {
|
|
std::string TmpStr =
|
|
BM->get<SPIRVString>(I->getArguments()[TextIdx])->getStr();
|
|
Str.append(TmpStr);
|
|
}
|
|
return Str;
|
|
}
|
|
|
|
void SPIRVToLLVMDbgTran::transDbgInfo(const SPIRVValue *SV, Value *V) {
|
|
// Constant samplers and composites do not have a corresponding
|
|
// SPIRVInstruction, but they may be mapped to an LLVM Instruction.
|
|
if (SV->getOpCode() == OpConstantSampler ||
|
|
SV->getOpCode() == OpConstantComposite)
|
|
return;
|
|
|
|
if (Instruction *I = dyn_cast<Instruction>(V)) {
|
|
if (SV->isInst()) {
|
|
const SPIRVInstruction *SI = static_cast<const SPIRVInstruction *>(SV);
|
|
I->setDebugLoc(transDebugScope(SI));
|
|
}
|
|
}
|
|
}
|
|
|
|
DIScope *SPIRVToLLVMDbgTran::getScope(const SPIRVEntry *ScopeInst) {
|
|
if (ScopeInst->getOpCode() == OpString)
|
|
return getDIFile(static_cast<const SPIRVString *>(ScopeInst)->getStr());
|
|
return transDebugInst<DIScope>(static_cast<const SPIRVExtInst *>(ScopeInst));
|
|
}
|
|
|
|
void SPIRVToLLVMDbgTran::appendToSourceLangLiteral(DICompileUnit *CompileUnit,
|
|
SPIRVWord SourceLang) {
|
|
if (!M->getModuleFlag("Source Lang Literal")) {
|
|
M->addModuleFlag(llvm::Module::Warning, "Source Lang Literal",
|
|
MDTuple::get(M->getContext(), {}));
|
|
}
|
|
auto *SourceLangLiteral =
|
|
dyn_cast<MDTuple>(M->getModuleFlag("Source Lang Literal"));
|
|
|
|
// Copy old content
|
|
SmallVector<Metadata *, 4> Nodes;
|
|
for (auto &Node : SourceLangLiteral->operands()) {
|
|
Nodes.push_back(Node);
|
|
}
|
|
|
|
// Add new entry
|
|
Nodes.push_back(MDTuple::get(
|
|
M->getContext(), SmallVector<Metadata *, 2>{
|
|
CompileUnit,
|
|
ConstantAsMetadata::get(ConstantInt::get(
|
|
Type::getInt32Ty(M->getContext()), SourceLang)),
|
|
}));
|
|
|
|
// Update
|
|
M->setModuleFlag(llvm::Module::Warning, "Source Lang Literal",
|
|
MDTuple::get(M->getContext(), Nodes));
|
|
}
|
|
|
|
DICompileUnit *
|
|
SPIRVToLLVMDbgTran::transCompilationUnit(const SPIRVExtInst *DebugInst,
|
|
const std::string CompilerVersion,
|
|
const std::string Flags) {
|
|
// Do nothing in case we have already translated the CU (e.g. during
|
|
// DebugEntryPoint translation)
|
|
if (BuilderMap[DebugInst->getId()])
|
|
return cast<DICompileUnit>(DebugInstCache[DebugInst]);
|
|
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
|
|
using namespace SPIRVDebug::Operand::CompilationUnit;
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
// We must preserve only one Dwarf version module level metadata
|
|
// UpgradeDebugInfo from llvm/lib/IR/AutoUpgrade.cpp has already done all
|
|
// work for us during linking stage leaving a single Dwarf version in the
|
|
// module
|
|
if (!M->getModuleFlag("Dwarf Version")) {
|
|
SPIRVWord DWARFVersion = getConstantValueOrLiteral(
|
|
Ops, DWARFVersionIdx, DebugInst->getExtSetKind());
|
|
M->addModuleFlag(llvm::Module::Max, "Dwarf Version", DWARFVersion);
|
|
}
|
|
SPIRVWord SourceLang =
|
|
getConstantValueOrLiteral(Ops, LanguageIdx, DebugInst->getExtSetKind());
|
|
SPIRVWord OriginalSourceLang = SourceLang;
|
|
bool InvalidSourceLang = false;
|
|
if (DebugInst->getExtSetKind() == SPIRVEIS_NonSemantic_Shader_DebugInfo_200) {
|
|
SourceLang = convertSPIRVSourceLangToDWARFNonSemanticDbgInfo(SourceLang);
|
|
} else if (isSPIRVSourceLangValid(SourceLang)) {
|
|
SourceLang = convertSPIRVSourceLangToDWARF(SourceLang);
|
|
} else {
|
|
// Some SPIR-V producers generate invalid source language value. In such
|
|
// case the original value should be preserved in "Source Lang Literal"
|
|
// module flag for later use by LLVM IR consumers.
|
|
SourceLang = dwarf::DW_LANG_OpenCL;
|
|
InvalidSourceLang = true;
|
|
}
|
|
|
|
BuilderMap[DebugInst->getId()] = std::make_unique<DIBuilder>(*M);
|
|
|
|
assert(BuilderMap.size() != 0 && "No debug compile units");
|
|
if (isNonSemanticDebugInfo(DebugInst->getExtSetKind())) {
|
|
// Only initialize once
|
|
if (BuilderMap.size() == 1)
|
|
setBuildIdentifierAndStoragePath();
|
|
|
|
// This assertion is a guard/reminder to update the Producer argument to
|
|
// createCompileUnit() if a new DebugInfo type is ever created
|
|
assert(DebugInst->getExtSetKind() ==
|
|
SPIRVEIS_NonSemantic_Shader_DebugInfo_100 ||
|
|
DebugInst->getExtSetKind() ==
|
|
SPIRVEIS_NonSemantic_Shader_DebugInfo_200);
|
|
|
|
auto *CompileUnit = BuilderMap[DebugInst->getId()]->createCompileUnit(
|
|
SourceLang, getFile(Ops[SourceIdx]),
|
|
DebugInst->getExtSetKind() == SPIRVEIS_NonSemantic_Shader_DebugInfo_100
|
|
? CompilerVersion
|
|
: getString(Ops[ProducerIdx]),
|
|
false, Flags, 0, StoragePath,
|
|
DICompileUnit::DebugEmissionKind::FullDebug, BuildIdentifier);
|
|
if (InvalidSourceLang) {
|
|
appendToSourceLangLiteral(CompileUnit, OriginalSourceLang);
|
|
}
|
|
return CompileUnit;
|
|
}
|
|
|
|
// TODO: Remove this workaround once we switch to NonSemantic.Shader.* debug
|
|
// info by default
|
|
auto Producer = findModuleProducer();
|
|
auto *CompileUnit = BuilderMap[DebugInst->getId()]->createCompileUnit(
|
|
SourceLang, getFile(Ops[SourceIdx]), Producer, false, Flags, 0);
|
|
if (InvalidSourceLang) {
|
|
appendToSourceLangLiteral(CompileUnit, OriginalSourceLang);
|
|
}
|
|
return CompileUnit;
|
|
}
|
|
|
|
DIBasicType *SPIRVToLLVMDbgTran::transTypeBasic(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeBasic;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert((Ops.size() == OperandCountOCL ||
|
|
Ops.size() == OperandCountNonSemantic) &&
|
|
"Invalid number of operands");
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
auto Tag = static_cast<SPIRVDebug::EncodingTag>(
|
|
getConstantValueOrLiteral(Ops, EncodingIdx, DebugInst->getExtSetKind()));
|
|
unsigned Encoding = SPIRV::DbgEncodingMap::rmap(Tag);
|
|
if (Encoding == 0)
|
|
return getDIBuilder(DebugInst).createUnspecifiedType(Name);
|
|
uint64_t Size = BM->get<SPIRVConstant>(Ops[SizeIdx])->getZExtIntValue();
|
|
return getDIBuilder(DebugInst).createBasicType(Name, Size, Encoding);
|
|
}
|
|
|
|
DIDerivedType *
|
|
SPIRVToLLVMDbgTran::transTypeQualifier(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeQualifier;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() == OperandCount && "Invalid number of operands");
|
|
DIType *BaseTy =
|
|
transDebugInst<DIType>(BM->get<SPIRVExtInst>(Ops[BaseTypeIdx]));
|
|
SPIRVWord Tag = SPIRV::DbgTypeQulifierMap::rmap(
|
|
static_cast<SPIRVDebug::TypeQualifierTag>(getConstantValueOrLiteral(
|
|
Ops, QualifierIdx, DebugInst->getExtSetKind())));
|
|
return getDIBuilder(DebugInst).createQualifiedType(Tag, BaseTy);
|
|
}
|
|
|
|
DIType *SPIRVToLLVMDbgTran::transTypePointer(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypePointer;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() == OperandCount && "Invalid number of operands");
|
|
DIType *PointeeTy = nullptr;
|
|
if (BM->getEntry(Ops[BaseTypeIdx])->getOpCode() != OpTypeVoid)
|
|
PointeeTy = transDebugInst<DIType>(BM->get<SPIRVExtInst>(Ops[BaseTypeIdx]));
|
|
std::optional<unsigned> AS;
|
|
SPIRVWord SC = getConstantValueOrLiteral(Ops, StorageClassIdx,
|
|
DebugInst->getExtSetKind());
|
|
if (SC != ~0U) // all ones denote no address space
|
|
AS = SPIRSPIRVAddrSpaceMap::rmap(static_cast<SPIRVStorageClassKind>(SC));
|
|
DIType *Ty;
|
|
SPIRVWord Flags =
|
|
getConstantValueOrLiteral(Ops, FlagsIdx, DebugInst->getExtSetKind());
|
|
if (Flags & SPIRVDebug::FlagIsLValueReference)
|
|
Ty = getDIBuilder(DebugInst).createReferenceType(
|
|
dwarf::DW_TAG_reference_type, PointeeTy, 0, 0, AS);
|
|
else if (Flags & SPIRVDebug::FlagIsRValueReference)
|
|
Ty = getDIBuilder(DebugInst).createReferenceType(
|
|
dwarf::DW_TAG_rvalue_reference_type, PointeeTy, 0, 0, AS);
|
|
else
|
|
Ty = getDIBuilder(DebugInst).createPointerType(
|
|
PointeeTy, BM->getAddressingModel() * 32, 0, AS);
|
|
|
|
if (Flags & SPIRVDebug::FlagIsObjectPointer)
|
|
Ty = getDIBuilder(DebugInst).createObjectPointerType(Ty, /*Implicit=*/true);
|
|
else if (Flags & SPIRVDebug::FlagIsArtificial)
|
|
Ty = getDIBuilder(DebugInst).createArtificialType(Ty);
|
|
|
|
return Ty;
|
|
}
|
|
|
|
DICompositeType *
|
|
SPIRVToLLVMDbgTran::transTypeArray(const SPIRVExtInst *DebugInst) {
|
|
if (DebugInst->getExtSetKind() == SPIRVEIS_NonSemantic_Shader_DebugInfo_200)
|
|
return transTypeArrayNonSemantic(DebugInst);
|
|
|
|
// TODO: figure out better naming for transTypeArrayOpenCL since
|
|
// it also handles SPIRVEIS_NonSemantic_Shader_DebugInfo_100.
|
|
// Also to consider separating OpenCL from NonSemantic, as OpenCL has several
|
|
// workarounds
|
|
return transTypeArrayOpenCL(DebugInst);
|
|
}
|
|
|
|
DICompositeType *
|
|
SPIRVToLLVMDbgTran::transTypeArrayOpenCL(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeArray;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
DIType *BaseTy =
|
|
transNonNullDebugType(BM->get<SPIRVExtInst>(Ops[BaseTypeIdx]));
|
|
size_t TotalCount = 1;
|
|
SmallVector<llvm::Metadata *, 8> Subscripts;
|
|
// Ops looks like: { BaseType, count1|upperBound1, count2|upperBound2, ...,
|
|
// countN|upperBoundN, lowerBound1, lowerBound2, ..., lowerBoundN }
|
|
for (size_t I = ComponentCountIdx, E = Ops.size() / 2 + 1; I < E; ++I) {
|
|
if (auto *LocalVar = getDbgInst<SPIRVDebug::LocalVariable>(Ops[I])) {
|
|
auto *UpperBound = transDebugInst<DILocalVariable>(LocalVar);
|
|
SPIRVConstant *C = BM->get<SPIRVConstant>(Ops[Ops.size() / 2 + I]);
|
|
int64_t ConstantAsInt = static_cast<int64_t>(C->getZExtIntValue());
|
|
auto *LowerBound = ConstantAsMetadata::get(
|
|
ConstantInt::get(M->getContext(), APInt(64, ConstantAsInt)));
|
|
Subscripts.push_back(getDIBuilder(DebugInst).getOrCreateSubrange(
|
|
nullptr, LowerBound, UpperBound, nullptr));
|
|
continue;
|
|
}
|
|
if (const SPIRVExtInst * ExprUB, *ExprLB;
|
|
(ExprUB = getDbgInst<SPIRVDebug::Expression>(Ops[I])) &&
|
|
(ExprLB =
|
|
getDbgInst<SPIRVDebug::Expression>(Ops[Ops.size() / 2 + I]))) {
|
|
auto *UpperBound = transDebugInst<DIExpression>(ExprUB);
|
|
auto *LowerBound = transDebugInst<DIExpression>(ExprLB);
|
|
Subscripts.push_back(getDIBuilder(DebugInst).getOrCreateSubrange(
|
|
nullptr, LowerBound, UpperBound, nullptr));
|
|
continue;
|
|
}
|
|
if (!getDbgInst<SPIRVDebug::DebugInfoNone>(Ops[I])) {
|
|
SPIRVConstant *C = BM->get<SPIRVConstant>(Ops[I]);
|
|
int64_t Count = static_cast<int64_t>(C->getZExtIntValue());
|
|
// If the SPIR-V file was generated by an older version of the translator,
|
|
// Ops may not contain the LowerBound
|
|
if (Ops.size() / 2 + I < Ops.size()) {
|
|
C = BM->get<SPIRVConstant>(Ops[Ops.size() / 2 + I]);
|
|
int64_t LowerBound = static_cast<int64_t>(C->getZExtIntValue());
|
|
Subscripts.push_back(
|
|
getDIBuilder(DebugInst).getOrCreateSubrange(LowerBound, Count));
|
|
} else {
|
|
auto *CountAsMD = ConstantAsMetadata::get(
|
|
ConstantInt::get(M->getContext(), APInt(64, Count)));
|
|
Subscripts.push_back(getDIBuilder(DebugInst).getOrCreateSubrange(
|
|
CountAsMD, nullptr, nullptr, nullptr));
|
|
}
|
|
// Count = -1 means that the array is empty
|
|
TotalCount *= Count > 0 ? static_cast<size_t>(Count) : 0;
|
|
continue;
|
|
}
|
|
}
|
|
DINodeArray SubscriptArray =
|
|
getDIBuilder(DebugInst).getOrCreateArray(Subscripts);
|
|
size_t Size = getDerivedSizeInBits(BaseTy) * TotalCount;
|
|
return getDIBuilder(DebugInst).createArrayType(Size, 0 /*align*/, BaseTy,
|
|
SubscriptArray);
|
|
}
|
|
|
|
DICompositeType *
|
|
SPIRVToLLVMDbgTran::transTypeArrayNonSemantic(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeArray;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
DIType *BaseTy =
|
|
transNonNullDebugType(BM->get<SPIRVExtInst>(Ops[BaseTypeIdx]));
|
|
size_t TotalCount = 1;
|
|
SmallVector<llvm::Metadata *, 8> Subscripts;
|
|
if (DebugInst->getExtOp() == SPIRVDebug::TypeArray) {
|
|
for (size_t I = SubrangesIdx; I < Ops.size(); ++I) {
|
|
auto *SR = transDebugInst<DISubrange>(BM->get<SPIRVExtInst>(Ops[I]));
|
|
if (auto *Count = cast<ConstantInt *>(SR->getCount()))
|
|
TotalCount *= Count->getSExtValue() > 0 ? Count->getSExtValue() : 0;
|
|
Subscripts.push_back(SR);
|
|
}
|
|
}
|
|
DINodeArray SubscriptArray =
|
|
getDIBuilder(DebugInst).getOrCreateArray(Subscripts);
|
|
size_t Size = getDerivedSizeInBits(BaseTy) * TotalCount;
|
|
return getDIBuilder(DebugInst).createArrayType(Size, 0 /*align*/, BaseTy,
|
|
SubscriptArray);
|
|
}
|
|
|
|
DICompositeType *
|
|
SPIRVToLLVMDbgTran::transTypeArrayDynamic(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeArrayDynamic;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
DIType *BaseTy =
|
|
transNonNullDebugType(BM->get<SPIRVExtInst>(Ops[BaseTypeIdx]));
|
|
size_t TotalCount = 1;
|
|
SmallVector<llvm::Metadata *, 8> Subscripts;
|
|
for (size_t I = SubrangesIdx; I < Ops.size(); ++I) {
|
|
auto *SR = transDebugInst<DISubrange>(BM->get<SPIRVExtInst>(Ops[I]));
|
|
if (auto *Count = cast<ConstantInt *>(SR->getCount()))
|
|
TotalCount *= Count->getSExtValue() > 0 ? Count->getSExtValue() : 0;
|
|
Subscripts.push_back(SR);
|
|
}
|
|
DINodeArray SubscriptArray =
|
|
getDIBuilder(DebugInst).getOrCreateArray(Subscripts);
|
|
size_t Size = getDerivedSizeInBits(BaseTy) * TotalCount;
|
|
|
|
auto TransOperand =
|
|
[&](SPIRVWord Idx) -> PointerUnion<DIExpression *, DIVariable *> {
|
|
if (!getDbgInst<SPIRVDebug::DebugInfoNone>(Ops[Idx])) {
|
|
if (const auto *GV = getDbgInst<SPIRVDebug::GlobalVariable>(Ops[Idx]))
|
|
return transDebugInst<DIGlobalVariable>(GV);
|
|
if (const auto *LV = getDbgInst<SPIRVDebug::LocalVariable>(Ops[Idx]))
|
|
return transDebugInst<DILocalVariable>(LV);
|
|
if (const auto *DIExpr = getDbgInst<SPIRVDebug::Expression>(Ops[Idx]))
|
|
return transDebugInst<DIExpression>(DIExpr);
|
|
}
|
|
return nullptr;
|
|
};
|
|
PointerUnion<DIExpression *, DIVariable *> DataLocation =
|
|
TransOperand(DataLocationIdx);
|
|
PointerUnion<DIExpression *, DIVariable *> Associated =
|
|
TransOperand(AssociatedIdx);
|
|
PointerUnion<DIExpression *, DIVariable *> Allocated =
|
|
TransOperand(AllocatedIdx);
|
|
PointerUnion<DIExpression *, DIVariable *> Rank = TransOperand(RankIdx);
|
|
return getDIBuilder(DebugInst).createArrayType(Size, 0 /*align*/, BaseTy,
|
|
SubscriptArray, DataLocation,
|
|
Associated, Allocated, Rank);
|
|
}
|
|
|
|
DICompositeType *
|
|
SPIRVToLLVMDbgTran::transTypeVector(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeVector;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
DIType *BaseTy =
|
|
transNonNullDebugType(BM->get<SPIRVExtInst>(Ops[BaseTypeIdx]));
|
|
SPIRVWord Count = getConstantValueOrLiteral(Ops, ComponentCountIdx,
|
|
DebugInst->getExtSetKind());
|
|
// Round up to a power of two.
|
|
// OpenCL/SYCL 3-element vectors
|
|
// occupy the same amount of memory as 4-element vectors
|
|
// Clang rounds up the memory size of vectors to a power of 2.
|
|
// Vulkan allows vec3 to have a memory size of 12, but in RenderDoc memory
|
|
// size is not derived from debug info.
|
|
uint64_t Size = getDerivedSizeInBits(BaseTy) * llvm::bit_ceil(Count);
|
|
|
|
SmallVector<llvm::Metadata *, 8> Subscripts;
|
|
Subscripts.push_back(getDIBuilder(DebugInst).getOrCreateSubrange(0, Count));
|
|
DINodeArray SubscriptArray =
|
|
getDIBuilder(DebugInst).getOrCreateArray(Subscripts);
|
|
|
|
return getDIBuilder(DebugInst).createVectorType(Size, 0 /*align*/, BaseTy,
|
|
SubscriptArray);
|
|
}
|
|
|
|
DICompositeType *
|
|
SPIRVToLLVMDbgTran::transTypeComposite(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeComposite;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
SPIRVWord LineNo =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
DIScope *ParentScope = getScope(BM->getEntry(Ops[ParentIdx]));
|
|
|
|
uint64_t Size = 0;
|
|
SPIRVEntry *SizeEntry = BM->getEntry(Ops[SizeIdx]);
|
|
if (!(SizeEntry->isExtInst(SPIRVEIS_Debug, SPIRVDebug::DebugInfoNone) ||
|
|
SizeEntry->isExtInst(SPIRVEIS_OpenCL_DebugInfo_100,
|
|
SPIRVDebug::DebugInfoNone) ||
|
|
SizeEntry->isExtInst(SPIRVEIS_NonSemantic_Shader_DebugInfo_200,
|
|
SPIRVDebug::DebugInfoNone))) {
|
|
Size = BM->get<SPIRVConstant>(Ops[SizeIdx])->getZExtIntValue();
|
|
}
|
|
|
|
uint64_t Align = 0;
|
|
DIType *DerivedFrom = nullptr;
|
|
StringRef Identifier;
|
|
SPIRVEntry *UniqId = BM->get<SPIRVEntry>(Ops[LinkageNameIdx]);
|
|
if (UniqId->getOpCode() == OpString)
|
|
Identifier = static_cast<SPIRVString *>(UniqId)->getStr();
|
|
|
|
DINode::DIFlags Flags = DINode::FlagZero;
|
|
SPIRVWord SPIRVFlags =
|
|
getConstantValueOrLiteral(Ops, FlagsIdx, DebugInst->getExtSetKind());
|
|
if (SPIRVFlags & SPIRVDebug::FlagIsFwdDecl)
|
|
Flags |= DINode::FlagFwdDecl;
|
|
if (SPIRVFlags & SPIRVDebug::FlagTypePassByValue)
|
|
Flags |= DINode::FlagTypePassByValue;
|
|
if (SPIRVFlags & SPIRVDebug::FlagTypePassByReference)
|
|
Flags |= DINode::FlagTypePassByReference;
|
|
|
|
DICompositeType *CT = nullptr;
|
|
switch (getConstantValueOrLiteral(Ops, TagIdx, DebugInst->getExtSetKind())) {
|
|
case SPIRVDebug::Class:
|
|
// TODO: should be replaced with createClassType, when bug with creating
|
|
// ClassType with llvm::dwarf::DW_TAG_struct_type tag will be fixed
|
|
CT = getDIBuilder(DebugInst).createReplaceableCompositeType(
|
|
llvm::dwarf::DW_TAG_class_type, Name, ParentScope, File, LineNo, 0,
|
|
Size, Align, Flags, Identifier);
|
|
CT = llvm::MDNode::replaceWithDistinct(llvm::TempDICompositeType(CT));
|
|
break;
|
|
case SPIRVDebug::Structure:
|
|
CT = getDIBuilder(DebugInst).createStructType(
|
|
ParentScope, Name, File, LineNo, Size, Align, Flags, DerivedFrom,
|
|
DINodeArray() /*elements*/, 0 /*RunTimeLang*/, nullptr /*VTableHolder*/,
|
|
Identifier);
|
|
break;
|
|
case SPIRVDebug::Union:
|
|
CT = getDIBuilder(DebugInst).createUnionType(
|
|
ParentScope, Name, File, LineNo, Size, Align, Flags, DINodeArray(),
|
|
0 /*RuntimrLang*/, Identifier);
|
|
break;
|
|
default:
|
|
llvm_unreachable("Unexpected composite type");
|
|
break;
|
|
}
|
|
DebugInstCache[DebugInst] = CT;
|
|
SmallVector<llvm::Metadata *, 8> EltTys;
|
|
for (size_t I = FirstMemberIdx; I < Ops.size(); ++I) {
|
|
auto *MemberInst = BM->get<SPIRVExtInst>(Ops[I]);
|
|
if (MemberInst->getExtOp() == SPIRVDebug::TypeMember) {
|
|
auto *SPVMemberInst = BM->get<SPIRVExtInst>(Ops[I]);
|
|
DINode *MemberMD =
|
|
transTypeMember(SPVMemberInst, DebugInst, cast<DIScope>(CT));
|
|
EltTys.push_back(MemberMD);
|
|
DebugInstCache[SPVMemberInst] = MemberMD;
|
|
} else if (MemberInst->getExtOp() == SPIRVDebug::TypeInheritance) {
|
|
auto *SPVMemberInst = BM->get<SPIRVExtInst>(Ops[I]);
|
|
DINode *MemberMD = transTypeInheritance(SPVMemberInst, cast<DIType>(CT));
|
|
EltTys.push_back(MemberMD);
|
|
DebugInstCache[SPVMemberInst] = MemberMD;
|
|
} else {
|
|
EltTys.emplace_back(transDebugInst(BM->get<SPIRVExtInst>(Ops[I])));
|
|
}
|
|
}
|
|
DINodeArray Elements = getDIBuilder(DebugInst).getOrCreateArray(EltTys);
|
|
getDIBuilder(DebugInst).replaceArrays(CT, Elements);
|
|
assert(CT && "Composite type translation failed.");
|
|
return CT;
|
|
}
|
|
|
|
DISubrange *
|
|
SPIRVToLLVMDbgTran::transTypeSubrange(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeSubrange;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert((Ops.size() == MinOperandCount || Ops.size() == MaxOperandCount) &&
|
|
"Invalid number of operands");
|
|
std::vector<Metadata *> TranslatedOps(MaxOperandCount, nullptr);
|
|
auto TransOperand = [&Ops, &TranslatedOps, this](int Idx) -> void {
|
|
if (!getDbgInst<SPIRVDebug::DebugInfoNone>(Ops[Idx])) {
|
|
if (auto *GlobalVar = getDbgInst<SPIRVDebug::GlobalVariable>(Ops[Idx])) {
|
|
TranslatedOps[Idx] =
|
|
cast<Metadata>(transDebugInst<DIGlobalVariable>(GlobalVar));
|
|
} else if (auto *LocalVar =
|
|
getDbgInst<SPIRVDebug::LocalVariable>(Ops[Idx])) {
|
|
TranslatedOps[Idx] =
|
|
cast<Metadata>(transDebugInst<DILocalVariable>(LocalVar));
|
|
} else if (auto *Expr = getDbgInst<SPIRVDebug::Expression>(Ops[Idx])) {
|
|
TranslatedOps[Idx] = cast<Metadata>(transDebugInst<DIExpression>(Expr));
|
|
} else if (auto *Const = BM->get<SPIRVConstant>(Ops[Idx])) {
|
|
int64_t ConstantAsInt = static_cast<int64_t>(Const->getZExtIntValue());
|
|
TranslatedOps[Idx] = cast<Metadata>(ConstantAsMetadata::get(
|
|
ConstantInt::get(M->getContext(), APInt(64, ConstantAsInt))));
|
|
}
|
|
}
|
|
};
|
|
for (size_t Idx = 0; Idx < Ops.size(); ++Idx)
|
|
TransOperand(Idx);
|
|
return getDIBuilder(DebugInst).getOrCreateSubrange(
|
|
TranslatedOps[CountIdx], TranslatedOps[LowerBoundIdx],
|
|
TranslatedOps[UpperBoundIdx], TranslatedOps[StrideIdx]);
|
|
}
|
|
|
|
DIStringType *
|
|
SPIRVToLLVMDbgTran::transTypeString(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeString;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
unsigned Encoding = 0;
|
|
if (!getDbgInst<SPIRVDebug::DebugInfoNone>((Ops[BaseTypeIdx]))) {
|
|
DIBasicType *BaseTy =
|
|
transTypeBasic(BM->get<SPIRVExtInst>(Ops[BaseTypeIdx]));
|
|
Encoding = BaseTy->getEncoding();
|
|
}
|
|
|
|
DIExpression *StrLocationExp = nullptr;
|
|
if (!getDbgInst<SPIRVDebug::DebugInfoNone>(Ops[DataLocationIdx])) {
|
|
if (const auto *DIExpr =
|
|
getDbgInst<SPIRVDebug::Expression>(Ops[DataLocationIdx]))
|
|
StrLocationExp = transDebugInst<DIExpression>(DIExpr);
|
|
}
|
|
|
|
uint64_t SizeInBits = BM->get<SPIRVConstant>(Ops[SizeIdx])->getZExtIntValue();
|
|
|
|
DIExpression *StringLengthExp = nullptr;
|
|
DIVariable *StringLengthVar = nullptr;
|
|
if (!getDbgInst<SPIRVDebug::DebugInfoNone>(Ops[LengthAddrIdx])) {
|
|
if (const auto *GV =
|
|
getDbgInst<SPIRVDebug::GlobalVariable>(Ops[LengthAddrIdx]))
|
|
StringLengthVar = transDebugInst<DIGlobalVariable>(GV);
|
|
if (const auto *LV =
|
|
getDbgInst<SPIRVDebug::LocalVariable>(Ops[LengthAddrIdx]))
|
|
StringLengthVar = transDebugInst<DILocalVariable>(LV);
|
|
if (const auto *DIExpr =
|
|
getDbgInst<SPIRVDebug::Expression>(Ops[LengthAddrIdx]))
|
|
StringLengthExp = transDebugInst<DIExpression>(DIExpr);
|
|
}
|
|
|
|
return DIStringType::get(M->getContext(), dwarf::DW_TAG_string_type, Name,
|
|
cast_or_null<Metadata>(StringLengthVar),
|
|
cast_or_null<Metadata>(StringLengthExp),
|
|
cast_or_null<Metadata>(StrLocationExp), SizeInBits,
|
|
0 /*AlignInBits*/, Encoding);
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transTypeMember(const SPIRVExtInst *DebugInst,
|
|
const SPIRVExtInst *ParentInst,
|
|
DIScope *Scope) {
|
|
if (isNonSemanticDebugInfo(DebugInst->getExtSetKind()))
|
|
// In NonSemantic spec TypeMember doesn't have Scope parameter
|
|
return transTypeMemberNonSemantic(DebugInst, ParentInst, Scope);
|
|
return transTypeMemberOpenCL(DebugInst);
|
|
}
|
|
|
|
DINode *
|
|
SPIRVToLLVMDbgTran::transTypeMemberOpenCL(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeMember::OpenCL;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
SPIRVWord LineNo =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
DIScope *Scope = getScope(BM->getEntry(Ops[ParentIdx]));
|
|
DIType *BaseType = transNonNullDebugType(BM->get<SPIRVExtInst>(Ops[TypeIdx]));
|
|
uint64_t OffsetInBits =
|
|
BM->get<SPIRVConstant>(Ops[OffsetIdx])->getZExtIntValue();
|
|
SPIRVWord SPIRVFlags =
|
|
getConstantValueOrLiteral(Ops, FlagsIdx, DebugInst->getExtSetKind());
|
|
DINode::DIFlags Flags = DINode::FlagZero;
|
|
if ((SPIRVDebug::FlagAccess & SPIRVFlags) == SPIRVDebug::FlagIsPublic) {
|
|
Flags |= DINode::FlagPublic;
|
|
} else if (SPIRVFlags & SPIRVDebug::FlagIsProtected) {
|
|
Flags |= DINode::FlagProtected;
|
|
} else if (SPIRVFlags & SPIRVDebug::FlagIsPrivate) {
|
|
Flags |= DINode::FlagPrivate;
|
|
}
|
|
if (SPIRVFlags & SPIRVDebug::FlagIsStaticMember)
|
|
Flags |= DINode::FlagStaticMember;
|
|
if (Flags & DINode::FlagStaticMember) {
|
|
llvm::Value *Val = nullptr;
|
|
if (Ops.size() > MinOperandCount) {
|
|
SPIRVValue *ConstVal = BM->get<SPIRVValue>(Ops[ValueIdx]);
|
|
assert(isConstantOpCode(ConstVal->getOpCode()) &&
|
|
"Static member must be a constant");
|
|
Val = SPIRVReader->transValue(ConstVal, nullptr, nullptr);
|
|
}
|
|
auto Tag = M->getDwarfVersion() >= 5 ? llvm::dwarf::DW_TAG_variable
|
|
: llvm::dwarf::DW_TAG_member;
|
|
return getDIBuilder(DebugInst).createStaticMemberType(
|
|
Scope, Name, File, LineNo, BaseType, Flags,
|
|
cast_or_null<llvm::Constant>(Val), Tag);
|
|
}
|
|
uint64_t Size = BM->get<SPIRVConstant>(Ops[SizeIdx])->getZExtIntValue();
|
|
uint64_t Alignment = 0;
|
|
|
|
return getDIBuilder(DebugInst).createMemberType(Scope, Name, File, LineNo,
|
|
Size, Alignment, OffsetInBits,
|
|
Flags, BaseType);
|
|
}
|
|
|
|
DINode *
|
|
SPIRVToLLVMDbgTran::transTypeMemberNonSemantic(const SPIRVExtInst *DebugInst,
|
|
const SPIRVExtInst *ParentInst,
|
|
DIScope *Scope) {
|
|
if (!Scope)
|
|
// Will be translated later when processing TypeMember's parent
|
|
return nullptr;
|
|
using namespace SPIRVDebug::Operand::TypeMember::NonSemantic;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
SPIRVWord LineNo =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
DIType *BaseType = transNonNullDebugType(BM->get<SPIRVExtInst>(Ops[TypeIdx]));
|
|
uint64_t OffsetInBits =
|
|
BM->get<SPIRVConstant>(Ops[OffsetIdx])->getZExtIntValue();
|
|
SPIRVWord SPIRVFlags =
|
|
getConstantValueOrLiteral(Ops, FlagsIdx, DebugInst->getExtSetKind());
|
|
DINode::DIFlags Flags = DINode::FlagZero;
|
|
if ((SPIRVDebug::FlagAccess & SPIRVFlags) == SPIRVDebug::FlagIsPublic) {
|
|
Flags |= DINode::FlagPublic;
|
|
} else if (SPIRVFlags & SPIRVDebug::FlagIsProtected) {
|
|
Flags |= DINode::FlagProtected;
|
|
} else if (SPIRVFlags & SPIRVDebug::FlagIsPrivate) {
|
|
Flags |= DINode::FlagPrivate;
|
|
}
|
|
if (SPIRVFlags & SPIRVDebug::FlagIsStaticMember)
|
|
Flags |= DINode::FlagStaticMember;
|
|
if (SPIRVFlags & SPIRVDebug::FlagBitField)
|
|
Flags |= DINode::FlagBitField;
|
|
|
|
if (Flags & DINode::FlagStaticMember) {
|
|
llvm::Value *Val = nullptr;
|
|
if (Ops.size() > MinOperandCount) {
|
|
SPIRVValue *ConstVal = BM->get<SPIRVValue>(Ops[ValueIdx]);
|
|
assert(isConstantOpCode(ConstVal->getOpCode()) &&
|
|
"Static member must be a constant");
|
|
Val = SPIRVReader->transValue(ConstVal, nullptr, nullptr);
|
|
}
|
|
auto Tag = M->getDwarfVersion() >= 5 ? llvm::dwarf::DW_TAG_variable
|
|
: llvm::dwarf::DW_TAG_member;
|
|
return getDIBuilder(DebugInst).createStaticMemberType(
|
|
Scope, Name, File, LineNo, BaseType, Flags,
|
|
cast_or_null<llvm::Constant>(Val), Tag);
|
|
}
|
|
uint64_t Size = BM->get<SPIRVConstant>(Ops[SizeIdx])->getZExtIntValue();
|
|
uint64_t Alignment = 0;
|
|
|
|
return getDIBuilder(ParentInst)
|
|
.createMemberType(Scope, Name, File, LineNo, Size, Alignment,
|
|
OffsetInBits, Flags, BaseType);
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transTypeEnum(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeEnum;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
SPIRVWord LineNo =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
DIScope *Scope = getScope(BM->getEntry(Ops[ParentIdx]));
|
|
uint64_t SizeInBits = BM->get<SPIRVConstant>(Ops[SizeIdx])->getZExtIntValue();
|
|
SPIRVWord AlignInBits = 0;
|
|
SPIRVWord Flags =
|
|
getConstantValueOrLiteral(Ops, FlagsIdx, DebugInst->getExtSetKind());
|
|
if (Flags & SPIRVDebug::FlagIsFwdDecl) {
|
|
return getDIBuilder(DebugInst).createForwardDecl(
|
|
dwarf::DW_TAG_enumeration_type, Name, Scope, File, LineNo, AlignInBits,
|
|
SizeInBits);
|
|
} else {
|
|
SmallVector<llvm::Metadata *, 16> Elts;
|
|
for (size_t I = FirstEnumeratorIdx, E = Ops.size(); I < E; I += 2) {
|
|
uint64_t Val = BM->get<SPIRVConstant>(Ops[I])->getZExtIntValue();
|
|
StringRef Name = getString(Ops[I + 1]);
|
|
Elts.push_back(getDIBuilder(DebugInst).createEnumerator(Name, Val));
|
|
}
|
|
DINodeArray Enumerators = getDIBuilder(DebugInst).getOrCreateArray(Elts);
|
|
DIType *UnderlyingType = nullptr;
|
|
SPIRVEntry *E = BM->getEntry(Ops[UnderlyingTypeIdx]);
|
|
if (!isa<OpTypeVoid>(E))
|
|
UnderlyingType = transDebugInst<DIType>(static_cast<SPIRVExtInst *>(E));
|
|
return getDIBuilder(DebugInst).createEnumerationType(
|
|
Scope, Name, File, LineNo, SizeInBits, AlignInBits, Enumerators,
|
|
UnderlyingType, 0, "", Flags & SPIRVDebug::FlagIsEnumClass);
|
|
}
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transTypeFunction(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeFunction;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
|
|
SPIRVWord SPIRVFlags =
|
|
getConstantValueOrLiteral(Ops, FlagsIdx, DebugInst->getExtSetKind());
|
|
DINode::DIFlags Flags = DINode::FlagZero;
|
|
if (SPIRVFlags & SPIRVDebug::FlagIsLValueReference)
|
|
Flags |= llvm::DINode::FlagLValueReference;
|
|
if (SPIRVFlags & SPIRVDebug::FlagIsRValueReference)
|
|
Flags |= llvm::DINode::FlagRValueReference;
|
|
|
|
SPIRVEntry *E = BM->getEntry(Ops[ReturnTypeIdx]);
|
|
MDNode *RT = isa<OpTypeVoid>(E)
|
|
? nullptr
|
|
: transDebugInst(BM->get<SPIRVExtInst>(Ops[ReturnTypeIdx]));
|
|
SmallVector<llvm::Metadata *, 16> Elements{RT};
|
|
for (size_t I = FirstParameterIdx, E = Ops.size(); I < E; ++I) {
|
|
SPIRVEntry *P = BM->getEntry(Ops[I]);
|
|
MDNode *Param = isa<OpTypeVoid>(P)
|
|
? nullptr
|
|
: transDebugInst(BM->get<SPIRVExtInst>(Ops[I]));
|
|
|
|
Elements.push_back(Param);
|
|
}
|
|
DITypeRefArray ArgTypes =
|
|
getDIBuilder(DebugInst).getOrCreateTypeArray(Elements);
|
|
return getDIBuilder(DebugInst).createSubroutineType(ArgTypes, Flags);
|
|
}
|
|
|
|
DINode *
|
|
SPIRVToLLVMDbgTran::transTypePtrToMember(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypePtrToMember;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= OperandCount && "Invalid number of operands");
|
|
SPIRVExtInst *Member = BM->get<SPIRVExtInst>(Ops[MemberTypeIdx]);
|
|
DIType *PointeeTy = transNonNullDebugType(Member);
|
|
SPIRVExtInst *ContainingTy = BM->get<SPIRVExtInst>(Ops[ParentIdx]);
|
|
DIType *BaseTy = transNonNullDebugType(ContainingTy);
|
|
return getDIBuilder(DebugInst).createMemberPointerType(PointeeTy, BaseTy, 0);
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transLexicalBlock(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::LexicalBlock;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
DIScope *ParentScope = getScope(BM->getEntry(Ops[ParentIdx]));
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
SPIRVWord LineNo =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
if (Ops.size() > MinOperandCount) {
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
bool InlinedNamespace = false;
|
|
if (DebugInst->getExtSetKind() ==
|
|
SPIRVEIS_NonSemantic_Shader_DebugInfo_200) {
|
|
SPIRVValue *V = BM->get<SPIRVValue>(Ops[InlineNamespaceIdx]);
|
|
Value *Var = SPIRVReader->transValue(V, nullptr, nullptr);
|
|
InlinedNamespace = cast<ConstantInt>(Var)->isOne();
|
|
}
|
|
return getDIBuilder(DebugInst).createNameSpace(ParentScope, Name,
|
|
InlinedNamespace);
|
|
}
|
|
unsigned Column = Ops[ColumnIdx];
|
|
return getDIBuilder(DebugInst).createLexicalBlock(ParentScope, File, LineNo,
|
|
Column);
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transLexicalBlockDiscriminator(
|
|
const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::LexicalBlockDiscriminator;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
SPIRVWord Disc = getConstantValueOrLiteral(Ops, DiscriminatorIdx,
|
|
DebugInst->getExtSetKind());
|
|
DIScope *ParentScope = getScope(BM->getEntry(Ops[ParentIdx]));
|
|
return getDIBuilder(DebugInst).createLexicalBlockFile(ParentScope, File,
|
|
Disc);
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transFunction(const SPIRVExtInst *DebugInst,
|
|
bool IsMainSubprogram) {
|
|
using namespace SPIRVDebug::Operand::Function;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCountNonSem && "Invalid number of operands");
|
|
if (!isNonSemanticDebugInfo(DebugInst->getExtSetKind()))
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
DISubroutineType *Ty =
|
|
transDebugInst<DISubroutineType>(BM->get<SPIRVExtInst>(Ops[TypeIdx]));
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
SPIRVWord LineNo =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
DIScope *Scope = getScope(BM->getEntry(Ops[ParentIdx]));
|
|
StringRef LinkageName = getString(Ops[LinkageNameIdx]);
|
|
|
|
SPIRVWord SPIRVDebugFlags =
|
|
getConstantValueOrLiteral(Ops, FlagsIdx, DebugInst->getExtSetKind());
|
|
DINode::DIFlags Flags = DINode::FlagZero;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsArtificial)
|
|
Flags |= llvm::DINode::FlagArtificial;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsExplicit)
|
|
Flags |= llvm::DINode::FlagExplicit;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsPrototyped)
|
|
Flags |= llvm::DINode::FlagPrototyped;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsLValueReference)
|
|
Flags |= llvm::DINode::FlagLValueReference;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsRValueReference)
|
|
Flags |= llvm::DINode::FlagRValueReference;
|
|
if ((SPIRVDebugFlags & SPIRVDebug::FlagAccess) == SPIRVDebug::FlagIsPublic)
|
|
Flags |= llvm::DINode::FlagPublic;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsProtected)
|
|
Flags |= llvm::DINode::FlagProtected;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsPrivate)
|
|
Flags |= llvm::DINode::FlagPrivate;
|
|
|
|
bool IsDefinition = SPIRVDebugFlags & SPIRVDebug::FlagIsDefinition;
|
|
bool IsOptimized = SPIRVDebugFlags & SPIRVDebug::FlagIsOptimized;
|
|
bool IsLocal = SPIRVDebugFlags & SPIRVDebug::FlagIsLocal;
|
|
bool IsMainSubprogramFlag =
|
|
IsMainSubprogram ||
|
|
(!isNonSemanticDebugInfo(DebugInst->getExtSetKind()) &&
|
|
BM->isEntryPoint(spv::ExecutionModelKernel, Ops[FunctionIdIdx]));
|
|
|
|
DISubprogram::DISPFlags SPFlags = DISubprogram::toSPFlags(
|
|
IsLocal, IsDefinition, IsOptimized, DISubprogram::SPFlagNonvirtual,
|
|
IsMainSubprogramFlag);
|
|
|
|
SPIRVWord ScopeLine =
|
|
getConstantValueOrLiteral(Ops, ScopeLineIdx, DebugInst->getExtSetKind());
|
|
|
|
// Function declaration descriptor
|
|
DISubprogram *FD = nullptr;
|
|
if (isNonSemanticDebugInfo(DebugInst->getExtSetKind()) &&
|
|
Ops.size() > DeclarationNonSemIdx) {
|
|
FD = transDebugInst<DISubprogram>(
|
|
BM->get<SPIRVExtInst>(Ops[DeclarationNonSemIdx]));
|
|
} else if (Ops.size() > DeclarationIdx) {
|
|
FD = transDebugInst<DISubprogram>(
|
|
BM->get<SPIRVExtInst>(Ops[DeclarationIdx]));
|
|
}
|
|
|
|
// Here we create fake array of template parameters. If it was plain nullptr,
|
|
// the template parameter operand would be removed in DISubprogram::getImpl.
|
|
// But we want it to be there, because if there is DebugTypeTemplate
|
|
// instruction refering to this function, transTypeTemplate method must be
|
|
// able to replace the template parameter operand, thus it must be in the
|
|
// operands list.
|
|
SmallVector<llvm::Metadata *, 8> Elts;
|
|
DINodeArray TParams = getDIBuilder(DebugInst).getOrCreateArray(Elts);
|
|
llvm::DITemplateParameterArray TParamsArray = TParams.get();
|
|
|
|
DISubprogram *DIS = nullptr;
|
|
if (Scope && (isa<DICompositeType>(Scope) || isa<DINamespace>(Scope)) &&
|
|
!IsDefinition)
|
|
DIS = getDIBuilder(DebugInst).createMethod(Scope, Name, LinkageName, File,
|
|
LineNo, Ty, 0, 0, nullptr, Flags,
|
|
SPFlags, TParamsArray);
|
|
else {
|
|
// Create targetFuncName mostly for Fortran trampoline function if it is
|
|
// the case
|
|
StringRef TargetFunction = "";
|
|
if (DebugInst->getExtSetKind() ==
|
|
SPIRVEIS_NonSemantic_Shader_DebugInfo_200 &&
|
|
Ops.size() > TargetFunctionNameIdx) {
|
|
TargetFunction = getString(Ops[TargetFunctionNameIdx]);
|
|
}
|
|
DIS = getDIBuilder(DebugInst).createFunction(
|
|
Scope, Name, LinkageName, File, LineNo, Ty, ScopeLine, Flags, SPFlags,
|
|
TParamsArray, FD,
|
|
/*ThrownTypes*/ nullptr,
|
|
/*Annotations*/ nullptr, TargetFunction);
|
|
}
|
|
DebugInstCache[DebugInst] = DIS;
|
|
|
|
// At this point, we don't have info about the function definition for
|
|
// NonSemantic.Shader debug info. If function definition is present, it'll be
|
|
// translated later within the function scope.
|
|
// For "default" debug info we do translate function body here.
|
|
if (!isNonSemanticDebugInfo(DebugInst->getExtSetKind()))
|
|
transFunctionBody(DIS, Ops[FunctionIdIdx]);
|
|
|
|
return DIS;
|
|
}
|
|
|
|
void SPIRVToLLVMDbgTran::transFunctionBody(DISubprogram *DIS, SPIRVId FuncId) {
|
|
FuncMap[FuncId] = DIS;
|
|
|
|
SPIRVEntry *E = BM->getEntry(FuncId);
|
|
if (E->getOpCode() == OpFunction) {
|
|
SPIRVFunction *BF = static_cast<SPIRVFunction *>(E);
|
|
llvm::Function *F = SPIRVReader->transFunction(BF);
|
|
assert(F && "Translation of function failed!");
|
|
if (!F->hasMetadata("dbg"))
|
|
F->setMetadata("dbg", DIS);
|
|
}
|
|
}
|
|
|
|
DINode *
|
|
SPIRVToLLVMDbgTran::transFunctionDefinition(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::FunctionDefinition;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
|
|
SPIRVExtInst *Func = BM->get<SPIRVExtInst>(Ops[FunctionIdx]);
|
|
DISubprogram *LLVMFunc = cast<DISubprogram>(DebugInstCache[Func]);
|
|
|
|
transFunctionBody(LLVMFunc, Ops[DefinitionIdx]);
|
|
return nullptr;
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transFunctionDecl(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::FunctionDeclaration;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() == OperandCount && "Invalid number of operands");
|
|
// Scope
|
|
DIScope *Scope = getScope(BM->getEntry(Ops[ParentIdx]));
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
StringRef LinkageName = getString(Ops[LinkageNameIdx]);
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
SPIRVWord LineNo =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
DISubroutineType *Ty =
|
|
transDebugInst<DISubroutineType>(BM->get<SPIRVExtInst>(Ops[TypeIdx]));
|
|
|
|
SPIRVWord SPIRVDebugFlags =
|
|
getConstantValueOrLiteral(Ops, FlagsIdx, DebugInst->getExtSetKind());
|
|
bool IsDefinition = SPIRVDebugFlags & SPIRVDebug::FlagIsDefinition;
|
|
bool IsOptimized = SPIRVDebugFlags & SPIRVDebug::FlagIsOptimized;
|
|
bool IsLocal = SPIRVDebugFlags & SPIRVDebug::FlagIsLocal;
|
|
DINode::DIFlags Flags = DINode::FlagZero;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsArtificial)
|
|
Flags |= llvm::DINode::FlagArtificial;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsExplicit)
|
|
Flags |= llvm::DINode::FlagExplicit;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsPrototyped)
|
|
Flags |= llvm::DINode::FlagPrototyped;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsLValueReference)
|
|
Flags |= llvm::DINode::FlagLValueReference;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsRValueReference)
|
|
Flags |= llvm::DINode::FlagRValueReference;
|
|
if ((SPIRVDebugFlags & SPIRVDebug::FlagAccess) == SPIRVDebug::FlagIsPublic)
|
|
Flags |= llvm::DINode::FlagPublic;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsProtected)
|
|
Flags |= llvm::DINode::FlagProtected;
|
|
if (SPIRVDebugFlags & SPIRVDebug::FlagIsPrivate)
|
|
Flags |= llvm::DINode::FlagPrivate;
|
|
|
|
// Here we create fake array of template parameters. If it was plain nullptr,
|
|
// the template parameter operand would be removed in DISubprogram::getImpl.
|
|
// But we want it to be there, because if there is DebugTypeTemplate
|
|
// instruction refering to this function, transTypeTemplate method must be
|
|
// able to replace the template parameter operand, thus it must be in the
|
|
// operands list.
|
|
SmallVector<llvm::Metadata *, 8> Elts;
|
|
DINodeArray TParams = getDIBuilder(DebugInst).getOrCreateArray(Elts);
|
|
llvm::DITemplateParameterArray TParamsArray = TParams.get();
|
|
|
|
DISubprogram *DIS = nullptr;
|
|
DISubprogram::DISPFlags SPFlags =
|
|
DISubprogram::toSPFlags(IsLocal, IsDefinition, IsOptimized);
|
|
if (isa<DICompositeType>(Scope) || isa<DINamespace>(Scope))
|
|
DIS = getDIBuilder(DebugInst).createMethod(Scope, Name, LinkageName, File,
|
|
LineNo, Ty, 0, 0, nullptr, Flags,
|
|
SPFlags, TParamsArray);
|
|
else {
|
|
// Since a function declaration doesn't have any retained nodes, resolve
|
|
// the temporary placeholder for them immediately.
|
|
DIS = getDIBuilder(DebugInst).createTempFunctionFwdDecl(
|
|
Scope, Name, LinkageName, File, LineNo, Ty, 0, Flags, SPFlags,
|
|
TParamsArray);
|
|
llvm::TempMDNode FwdDecl(cast<llvm::MDNode>(DIS));
|
|
DIS = getDIBuilder(DebugInst).replaceTemporary(std::move(FwdDecl), DIS);
|
|
}
|
|
DebugInstCache[DebugInst] = DIS;
|
|
|
|
return DIS;
|
|
}
|
|
|
|
MDNode *SPIRVToLLVMDbgTran::transEntryPoint(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::EntryPoint;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() == OperandCount && "Invalid number of operands");
|
|
|
|
SPIRVExtInst *EP = BM->get<SPIRVExtInst>(Ops[EntryPointIdx]);
|
|
SPIRVExtInst *CU = BM->get<SPIRVExtInst>(Ops[CompilationUnitIdx]);
|
|
std::string Producer = getString(Ops[CompilerSignatureIdx]);
|
|
std::string CLArgs = getString(Ops[CommandLineArgsIdx]);
|
|
|
|
DICompileUnit *C = transCompilationUnit(CU, Producer, CLArgs); // NOLINT
|
|
DebugInstCache[CU] = C;
|
|
|
|
return transFunction(EP, true /*IsMainSubprogram*/);
|
|
}
|
|
|
|
MDNode *SPIRVToLLVMDbgTran::transGlobalVariable(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::GlobalVariable;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
DIType *Ty = transNonNullDebugType(BM->get<SPIRVExtInst>(Ops[TypeIdx]));
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
SPIRVWord LineNo =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
DIScope *Parent = getScope(BM->getEntry(Ops[ParentIdx]));
|
|
StringRef LinkageName = getString(Ops[LinkageNameIdx]);
|
|
|
|
DIDerivedType *StaticMemberDecl = nullptr;
|
|
if (Ops.size() > MinOperandCount) {
|
|
StaticMemberDecl = transDebugInst<DIDerivedType>(
|
|
BM->get<SPIRVExtInst>(Ops[StaticMemberDeclarationIdx]));
|
|
}
|
|
|
|
DIExpression *DIExpr = nullptr;
|
|
// Check if Ops[VariableIdx] is not being used to hold a variable operand.
|
|
// Instead it is being used to hold an Expression that holds the initial
|
|
// value of the GlobalVariable.
|
|
if (getDbgInst<SPIRVDebug::Expression>(Ops[VariableIdx]))
|
|
DIExpr =
|
|
transDebugInst<DIExpression>(BM->get<SPIRVExtInst>(Ops[VariableIdx]));
|
|
|
|
SPIRVWord Flags =
|
|
getConstantValueOrLiteral(Ops, FlagsIdx, DebugInst->getExtSetKind());
|
|
bool IsLocal = Flags & SPIRVDebug::FlagIsLocal;
|
|
bool IsDefinition = Flags & SPIRVDebug::FlagIsDefinition;
|
|
MDNode *VarDecl = nullptr;
|
|
if (IsDefinition) {
|
|
VarDecl = getDIBuilder(DebugInst).createGlobalVariableExpression(
|
|
Parent, Name, LinkageName, File, LineNo, Ty, IsLocal, IsDefinition,
|
|
DIExpr, StaticMemberDecl);
|
|
} else {
|
|
VarDecl = getDIBuilder(DebugInst).createTempGlobalVariableFwdDecl(
|
|
Parent, Name, LinkageName, File, LineNo, Ty, IsLocal, StaticMemberDecl);
|
|
// replaceAllUsesWith call makes VarDecl non-temp.
|
|
// Otherwise DIBuilder will crash at finalization.
|
|
llvm::TempMDNode TMP(VarDecl);
|
|
VarDecl = getDIBuilder(DebugInst).replaceTemporary(std::move(TMP), VarDecl);
|
|
}
|
|
|
|
// Ops[VariableIdx] was not used to hold an Expression with the initial value
|
|
// for the GlobalVariable
|
|
if (!DIExpr) {
|
|
// If the variable has no initializer Ops[VariableIdx] is OpDebugInfoNone.
|
|
// Otherwise Ops[VariableIdx] may be a global variable or a constant(C++
|
|
// static const).
|
|
if (VarDecl && !getDbgInst<SPIRVDebug::DebugInfoNone>(Ops[VariableIdx])) {
|
|
SPIRVValue *V = BM->get<SPIRVValue>(Ops[VariableIdx]);
|
|
Value *Var = SPIRVReader->transValue(V, nullptr, nullptr);
|
|
llvm::GlobalVariable *GV = dyn_cast_or_null<llvm::GlobalVariable>(Var);
|
|
if (GV && !GV->hasMetadata("dbg"))
|
|
GV->addMetadata("dbg", *VarDecl);
|
|
}
|
|
}
|
|
return VarDecl;
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transLocalVariable(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::LocalVariable;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
|
|
DIScope *Scope = getScope(BM->getEntry(Ops[ParentIdx]));
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
SPIRVWord LineNo =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
DIType *Ty = transNonNullDebugType(BM->get<SPIRVExtInst>(Ops[TypeIdx]));
|
|
DINode::DIFlags Flags = DINode::FlagZero;
|
|
SPIRVWord SPIRVFlags =
|
|
getConstantValueOrLiteral(Ops, FlagsIdx, DebugInst->getExtSetKind());
|
|
if (SPIRVFlags & SPIRVDebug::FlagIsArtificial)
|
|
Flags |= DINode::FlagArtificial;
|
|
if (SPIRVFlags & SPIRVDebug::FlagIsObjectPointer)
|
|
Flags |= DINode::FlagObjectPointer;
|
|
|
|
if (Ops.size() > ArgNumberIdx)
|
|
return getDIBuilder(DebugInst).createParameterVariable(
|
|
Scope, Name, Ops[ArgNumberIdx], File, LineNo, Ty, true, Flags);
|
|
return getDIBuilder(DebugInst).createAutoVariable(Scope, Name, File, LineNo,
|
|
Ty, true, Flags);
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transTypedef(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::Typedef;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= OperandCount && "Invalid number of operands");
|
|
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
SPIRVWord LineNo =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
StringRef Alias = getString(Ops[NameIdx]);
|
|
SPIRVEntry *TypeInst = BM->getEntry(Ops[BaseTypeIdx]);
|
|
DIType *Ty = transDebugInst<DIType>(static_cast<SPIRVExtInst *>(TypeInst));
|
|
DIScope *Scope = getScope(BM->getEntry(Ops[ParentIdx]));
|
|
assert(Scope && "Typedef should have a parent scope");
|
|
return getDIBuilder(DebugInst).createTypedef(Ty, Alias, File, LineNo, Scope);
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transTypeInheritance(const SPIRVExtInst *DebugInst,
|
|
DIType *ChildClass) {
|
|
using namespace SPIRVDebug::Operand::TypeInheritance;
|
|
// The value is used when assertions are enabled
|
|
[[maybe_unused]] unsigned OperandCount;
|
|
unsigned ParentIdx, OffsetIdx, FlagsIdx;
|
|
if (isNonSemanticDebugInfo(DebugInst->getExtSetKind())) {
|
|
if (!ChildClass) {
|
|
// Will be translated later when processing TypeMember's parent
|
|
return nullptr;
|
|
}
|
|
OperandCount = NonSemantic::OperandCount;
|
|
ParentIdx = NonSemantic::ParentIdx;
|
|
OffsetIdx = NonSemantic::OffsetIdx;
|
|
FlagsIdx = NonSemantic::FlagsIdx;
|
|
} else {
|
|
OperandCount = OpenCL::OperandCount;
|
|
ParentIdx = OpenCL::ParentIdx;
|
|
OffsetIdx = OpenCL::OffsetIdx;
|
|
FlagsIdx = OpenCL::FlagsIdx;
|
|
}
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() == OperandCount && "Invalid number of operands");
|
|
DIType *Parent =
|
|
transDebugInst<DIType>(BM->get<SPIRVExtInst>(Ops[ParentIdx]));
|
|
DINode::DIFlags Flags = DINode::FlagZero;
|
|
SPIRVWord SPIRVFlags =
|
|
getConstantValueOrLiteral(Ops, FlagsIdx, DebugInst->getExtSetKind());
|
|
if ((SPIRVFlags & SPIRVDebug::FlagAccess) == SPIRVDebug::FlagIsPublic)
|
|
Flags |= llvm::DINode::FlagPublic;
|
|
if ((SPIRVFlags & SPIRVDebug::FlagAccess) == SPIRVDebug::FlagIsProtected)
|
|
Flags |= llvm::DINode::FlagProtected;
|
|
if ((SPIRVFlags & SPIRVDebug::FlagAccess) == SPIRVDebug::FlagIsPrivate)
|
|
Flags |= llvm::DINode::FlagPrivate;
|
|
uint64_t OffsetVal =
|
|
BM->get<SPIRVConstant>(Ops[OffsetIdx])->getZExtIntValue();
|
|
DIType *Child;
|
|
if (isNonSemanticDebugInfo(DebugInst->getExtSetKind())) {
|
|
Child = ChildClass;
|
|
} else {
|
|
Child =
|
|
transDebugInst<DIType>(BM->get<SPIRVExtInst>(Ops[OpenCL::ChildIdx]));
|
|
}
|
|
return getDIBuilder(DebugInst).createInheritance(Child, Parent, OffsetVal, 0,
|
|
Flags);
|
|
}
|
|
|
|
DINode *
|
|
SPIRVToLLVMDbgTran::transTypeTemplateParameter(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeTemplateParameter;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= OperandCount && "Invalid number of operands");
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
SPIRVEntry *ActualType = BM->getEntry(Ops[TypeIdx]);
|
|
DIType *Ty = nullptr;
|
|
if (!isa<OpTypeVoid>(ActualType))
|
|
Ty = transDebugInst<DIType>(static_cast<SPIRVExtInst *>(ActualType));
|
|
DIScope *Context = nullptr;
|
|
if (!getDbgInst<SPIRVDebug::DebugInfoNone>(Ops[ValueIdx])) {
|
|
SPIRVValue *Val = BM->get<SPIRVValue>(Ops[ValueIdx]);
|
|
Value *V = SPIRVReader->transValue(Val, nullptr, nullptr);
|
|
return getDIBuilder(DebugInst).createTemplateValueParameter(
|
|
Context, Name, Ty, false, cast<Constant>(V));
|
|
}
|
|
return getDIBuilder(DebugInst).createTemplateTypeParameter(Context, Name, Ty,
|
|
false);
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transTypeTemplateTemplateParameter(
|
|
const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeTemplateTemplateParameter;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= OperandCount && "Invalid number of operands");
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
StringRef TemplName = getString(Ops[TemplateNameIdx]);
|
|
DIScope *Context = nullptr;
|
|
return getDIBuilder(DebugInst).createTemplateTemplateParameter(
|
|
Context, Name, nullptr, TemplName);
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transTypeTemplateParameterPack(
|
|
const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeTemplateParameterPack;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
SmallVector<llvm::Metadata *, 8> Elts;
|
|
for (size_t I = FirstParameterIdx, E = Ops.size(); I < E; ++I) {
|
|
Elts.push_back(transDebugInst(BM->get<SPIRVExtInst>(Ops[I])));
|
|
}
|
|
DINodeArray Pack = getDIBuilder(DebugInst).getOrCreateArray(Elts);
|
|
DIScope *Context = nullptr;
|
|
return getDIBuilder(DebugInst).createTemplateParameterPack(Context, Name,
|
|
nullptr, Pack);
|
|
}
|
|
|
|
MDNode *SPIRVToLLVMDbgTran::transTypeTemplate(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::TypeTemplate;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
const size_t NumOps = Ops.size();
|
|
assert(NumOps >= MinOperandCount && "Invalid number of operands");
|
|
|
|
auto *Templ = BM->get<SPIRVExtInst>(Ops[TargetIdx]);
|
|
MDNode *D = transDebugInst(Templ);
|
|
|
|
SmallVector<llvm::Metadata *, 8> Elts;
|
|
for (size_t I = FirstParameterIdx; I < NumOps; ++I) {
|
|
Elts.push_back(transDebugInst(BM->get<SPIRVExtInst>(Ops[I])));
|
|
}
|
|
DINodeArray TParams = getDIBuilder(DebugInst).getOrCreateArray(Elts);
|
|
|
|
if (DICompositeType *Comp = dyn_cast<DICompositeType>(D)) {
|
|
getDIBuilder(DebugInst).replaceArrays(Comp, Comp->getElements(), TParams);
|
|
return Comp;
|
|
}
|
|
if (isa<DISubprogram>(D)) {
|
|
// This constant matches with one used in
|
|
// DISubprogram::getRawTemplateParams()
|
|
const unsigned TemplateParamsIndex = 9;
|
|
D->replaceOperandWith(TemplateParamsIndex, TParams.get());
|
|
return D;
|
|
}
|
|
llvm_unreachable("Invalid template");
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transImportedEntry(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::ImportedEntity;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
// FIXME: 'OpenCL/bugged' version is kept because it's hard to remove it
|
|
// It's W/A for missing 2nd index in OpenCL's implementation
|
|
const SPIRVWord OffsetIdx =
|
|
static_cast<int>(isNonSemanticDebugInfo(DebugInst->getExtSetKind()));
|
|
|
|
assert(Ops.size() == (OpenCL::OperandCount - OffsetIdx) &&
|
|
"Invalid number of operands");
|
|
DIScope *Scope = getScope(BM->getEntry(Ops[OpenCL::ParentIdx - OffsetIdx]));
|
|
SPIRVWord Line = getConstantValueOrLiteral(Ops, OpenCL::LineIdx - OffsetIdx,
|
|
DebugInst->getExtSetKind());
|
|
DIFile *File = getFile(Ops[OpenCL::SourceIdx - OffsetIdx]);
|
|
auto *Entity = transDebugInst<DINode>(
|
|
BM->get<SPIRVExtInst>(Ops[OpenCL::EntityIdx - OffsetIdx]));
|
|
SPIRVWord Tag = getConstantValueOrLiteral(Ops, OpenCL::TagIdx,
|
|
DebugInst->getExtSetKind());
|
|
if (Tag == SPIRVDebug::ImportedModule) {
|
|
if (!Entity)
|
|
return getDIBuilder(DebugInst).createImportedModule(
|
|
Scope, static_cast<DIImportedEntity *>(nullptr), File, Line);
|
|
if (DIModule *DM = dyn_cast<DIModule>(Entity))
|
|
return getDIBuilder(DebugInst).createImportedModule(Scope, DM, File,
|
|
Line);
|
|
if (DIImportedEntity *IE = dyn_cast<DIImportedEntity>(Entity))
|
|
return getDIBuilder(DebugInst).createImportedModule(Scope, IE, File,
|
|
Line);
|
|
if (DINamespace *NS = dyn_cast<DINamespace>(Entity))
|
|
return getDIBuilder(DebugInst).createImportedModule(Scope, NS, File,
|
|
Line);
|
|
}
|
|
if (Tag == SPIRVDebug::ImportedDeclaration) {
|
|
StringRef Name = getString(Ops[OpenCL::NameIdx]);
|
|
if (DIGlobalVariableExpression *GVE =
|
|
dyn_cast<DIGlobalVariableExpression>(Entity))
|
|
return getDIBuilder(DebugInst).createImportedDeclaration(
|
|
Scope, GVE->getVariable(), File, Line, Name);
|
|
return getDIBuilder(DebugInst).createImportedDeclaration(Scope, Entity,
|
|
File, Line, Name);
|
|
}
|
|
llvm_unreachable("Unexpected kind of imported entity!");
|
|
}
|
|
|
|
DINode *SPIRVToLLVMDbgTran::transModule(const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::ModuleINTEL;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= OperandCount && "Invalid number of operands");
|
|
DIScope *Scope = getScope(BM->getEntry(Ops[ParentIdx]));
|
|
// In case we translate DebugModuleINTEL instruction (not DebugModule of
|
|
// NonSemantic.Shader.200 spec), we should not apply the rule "literals are
|
|
// not allowed for NonSemantic specification". This is a hack to avoid getting
|
|
// constant value instead of literal in such case.
|
|
const SPIRVExtInstSetKind ExtKind =
|
|
DebugInst->getExtOp() == SPIRVDebug::Instruction::ModuleINTEL
|
|
? SPIRVEIS_OpenCL_DebugInfo_100
|
|
: DebugInst->getExtSetKind();
|
|
SPIRVWord Line = getConstantValueOrLiteral(Ops, LineIdx, ExtKind);
|
|
DIFile *File = getFile(Ops[SourceIdx]);
|
|
StringRef Name = getString(Ops[NameIdx]);
|
|
StringRef ConfigMacros = getString(Ops[ConfigMacrosIdx]);
|
|
StringRef IncludePath = getString(Ops[IncludePathIdx]);
|
|
StringRef ApiNotes = getString(Ops[ApiNotesIdx]);
|
|
bool IsDecl = getConstantValueOrLiteral(Ops, IsDeclIdx, ExtKind);
|
|
return getDIBuilder(DebugInst).createModule(
|
|
Scope, Name, ConfigMacros, IncludePath, ApiNotes, File, Line, IsDecl);
|
|
}
|
|
|
|
MDNode *SPIRVToLLVMDbgTran::transExpression(const SPIRVExtInst *DebugInst) {
|
|
const SPIRVWordVec &Args = DebugInst->getArguments();
|
|
std::vector<uint64_t> Ops;
|
|
for (SPIRVId A : Args) {
|
|
using namespace SPIRVDebug::Operand::Operation;
|
|
SPIRVExtInst *O = BM->get<SPIRVExtInst>(A);
|
|
const SPIRVWordVec &Operands = O->getArguments();
|
|
auto OpCode =
|
|
static_cast<SPIRVDebug::ExpressionOpCode>(getConstantValueOrLiteral(
|
|
Operands, OpCodeIdx, DebugInst->getExtSetKind()));
|
|
Ops.push_back(SPIRV::DbgExpressionOpCodeMap::rmap(OpCode));
|
|
for (unsigned I = 1, E = Operands.size(); I < E; ++I) {
|
|
Ops.push_back(
|
|
getConstantValueOrLiteral(Operands, I, DebugInst->getExtSetKind()));
|
|
}
|
|
}
|
|
ArrayRef<uint64_t> Addr(Ops.data(), Ops.size());
|
|
return getDIBuilder(DebugInst).createExpression(Addr);
|
|
}
|
|
|
|
DIType *
|
|
SPIRVToLLVMDbgTran::transNonNullDebugType(const SPIRVExtInst *DebugInst) {
|
|
if (DebugInst->getExtOp() != SPIRVDebug::DebugInfoNone)
|
|
return transDebugInst<DIType>(DebugInst);
|
|
return getDIBuilder(DebugInst).createUnspecifiedType("SPIRV unknown type");
|
|
}
|
|
|
|
MDNode *SPIRVToLLVMDbgTran::transDebugInstImpl(const SPIRVExtInst *DebugInst) {
|
|
switch (DebugInst->getExtOp()) {
|
|
case SPIRVDebug::DebugInfoNone:
|
|
return nullptr;
|
|
|
|
case SPIRVDebug::CompilationUnit:
|
|
return transCompilationUnit(DebugInst);
|
|
|
|
case SPIRVDebug::TypeBasic:
|
|
return transTypeBasic(DebugInst);
|
|
|
|
case SPIRVDebug::TypeQualifier:
|
|
return transTypeQualifier(DebugInst);
|
|
|
|
case SPIRVDebug::TypePointer:
|
|
return transTypePointer(DebugInst);
|
|
|
|
case SPIRVDebug::TypeArray:
|
|
return transTypeArray(DebugInst);
|
|
|
|
case SPIRVDebug::TypeSubrange:
|
|
return transTypeSubrange(DebugInst);
|
|
|
|
case SPIRVDebug::TypeString:
|
|
return transTypeString(DebugInst);
|
|
|
|
case SPIRVDebug::TypeVector:
|
|
return transTypeVector(DebugInst);
|
|
|
|
case SPIRVDebug::TypeComposite:
|
|
return transTypeComposite(DebugInst);
|
|
|
|
case SPIRVDebug::TypeMember:
|
|
return transTypeMember(DebugInst);
|
|
|
|
case SPIRVDebug::TypePtrToMember:
|
|
return transTypePtrToMember(DebugInst);
|
|
|
|
case SPIRVDebug::TypeEnum:
|
|
return transTypeEnum(DebugInst);
|
|
|
|
case SPIRVDebug::TypeFunction:
|
|
return transTypeFunction(DebugInst);
|
|
|
|
case SPIRVDebug::LexicalBlock:
|
|
return transLexicalBlock(DebugInst);
|
|
|
|
case SPIRVDebug::LexicalBlockDiscriminator:
|
|
return transLexicalBlockDiscriminator(DebugInst);
|
|
|
|
case SPIRVDebug::Function:
|
|
return transFunction(DebugInst);
|
|
|
|
case SPIRVDebug::FunctionDeclaration:
|
|
return transFunctionDecl(DebugInst);
|
|
|
|
case SPIRVDebug::FunctionDefinition:
|
|
return transFunctionDefinition(DebugInst);
|
|
|
|
case SPIRVDebug::EntryPoint:
|
|
return transEntryPoint(DebugInst);
|
|
|
|
case SPIRVDebug::GlobalVariable:
|
|
return transGlobalVariable(DebugInst);
|
|
|
|
case SPIRVDebug::LocalVariable:
|
|
return transLocalVariable(DebugInst);
|
|
|
|
case SPIRVDebug::Typedef:
|
|
return transTypedef(DebugInst);
|
|
|
|
case SPIRVDebug::InlinedAt:
|
|
return transDebugInlined(DebugInst);
|
|
|
|
case SPIRVDebug::TypeInheritance:
|
|
return transTypeInheritance(DebugInst);
|
|
|
|
case SPIRVDebug::TypeTemplateParameter:
|
|
return transTypeTemplateParameter(DebugInst);
|
|
|
|
case SPIRVDebug::TypeTemplateTemplateParameter:
|
|
return transTypeTemplateTemplateParameter(DebugInst);
|
|
|
|
case SPIRVDebug::TypeTemplateParameterPack:
|
|
return transTypeTemplateParameterPack(DebugInst);
|
|
|
|
case SPIRVDebug::TypeTemplate:
|
|
return transTypeTemplate(DebugInst);
|
|
|
|
case SPIRVDebug::ImportedEntity:
|
|
return transImportedEntry(DebugInst);
|
|
|
|
case SPIRVDebug::Module:
|
|
case SPIRVDebug::ModuleINTEL:
|
|
return transModule(DebugInst);
|
|
|
|
case SPIRVDebug::Operation: // To be translated with transExpression
|
|
case SPIRVDebug::Source: // To be used by other instructions
|
|
case SPIRVDebug::SourceContinued:
|
|
case SPIRVDebug::BuildIdentifier: // To be used by transCompilationUnit
|
|
case SPIRVDebug::StoragePath: // To be used by transCompilationUnit
|
|
return nullptr;
|
|
|
|
case SPIRVDebug::Expression:
|
|
return transExpression(DebugInst);
|
|
|
|
case SPIRVDebug::TypeArrayDynamic:
|
|
return transTypeArrayDynamic(DebugInst);
|
|
|
|
default:
|
|
llvm_unreachable("Not implemented SPIR-V debug instruction!");
|
|
}
|
|
}
|
|
|
|
DbgInstPtr
|
|
SPIRVToLLVMDbgTran::transDebugIntrinsic(const SPIRVExtInst *DebugInst,
|
|
BasicBlock *BB) {
|
|
auto GetLocalVar = [&](SPIRVId Id) -> std::pair<DILocalVariable *, DebugLoc> {
|
|
auto *LV = transDebugInst<DILocalVariable>(BM->get<SPIRVExtInst>(Id));
|
|
DebugLoc DL = DILocation::get(M->getContext(), LV->getLine(),
|
|
/*Column=*/0, LV->getScope());
|
|
return std::make_pair(LV, DL);
|
|
};
|
|
auto GetValue = [&](SPIRVId Id) -> Value * {
|
|
auto *V = BM->get<SPIRVValue>(Id);
|
|
return SPIRVReader->transValue(V, BB->getParent(), BB);
|
|
};
|
|
auto GetExpression = [&](SPIRVId Id) -> DIExpression * {
|
|
return transDebugInst<DIExpression>(BM->get<SPIRVExtInst>(Id));
|
|
};
|
|
SPIRVWordVec Ops = DebugInst->getArguments();
|
|
switch (DebugInst->getExtOp()) {
|
|
case SPIRVDebug::Scope:
|
|
case SPIRVDebug::NoScope:
|
|
case SPIRVDebug::FunctionDefinition:
|
|
return nullptr;
|
|
case SPIRVDebug::Declare: {
|
|
using namespace SPIRVDebug::Operand::DebugDeclare;
|
|
auto LocalVar = GetLocalVar(Ops[DebugLocalVarIdx]);
|
|
DebugLoc Loc = transDebugScope(DebugInst);
|
|
if (!Loc)
|
|
Loc = LocalVar.second;
|
|
DIBuilder &DIB = getDIBuilder(DebugInst);
|
|
if (getDbgInst<SPIRVDebug::DebugInfoNone>(Ops[VariableIdx])) {
|
|
auto *Null =
|
|
ConstantPointerNull::get(PointerType::get(M->getContext(), 0));
|
|
DbgInstPtr DbgDeclare = DIB.insertDeclare(
|
|
Null, LocalVar.first, GetExpression(Ops[ExpressionIdx]), Loc, BB);
|
|
return DbgDeclare;
|
|
}
|
|
return DIB.insertDeclare(GetValue(Ops[VariableIdx]), LocalVar.first,
|
|
GetExpression(Ops[ExpressionIdx]), Loc,
|
|
BB);
|
|
}
|
|
case SPIRVDebug::Value: {
|
|
using namespace SPIRVDebug::Operand::DebugValue;
|
|
auto LocalVar = GetLocalVar(Ops[DebugLocalVarIdx]);
|
|
Value *Val = GetValue(Ops[ValueIdx]);
|
|
DIExpression *Expr = GetExpression(Ops[ExpressionIdx]);
|
|
DebugLoc Loc = transDebugScope(DebugInst);
|
|
DbgInstPtr DbgValIntr = getDIBuilder(DebugInst).insertDbgValueIntrinsic(
|
|
Val, LocalVar.first, Expr, Loc, BB);
|
|
|
|
std::vector<ValueAsMetadata *> MDs;
|
|
for (size_t I = 0; I != Expr->getNumLocationOperands(); ++I) {
|
|
MDs.emplace_back(ValueAsMetadata::get(Val));
|
|
}
|
|
if (!MDs.empty()) {
|
|
DIArgList *AL = DIArgList::get(M->getContext(), MDs);
|
|
cast<DbgVariableRecord>(cast<DbgRecord *>(DbgValIntr))
|
|
->setRawLocation(AL);
|
|
}
|
|
return DbgValIntr;
|
|
}
|
|
default:
|
|
llvm_unreachable("Unknown debug intrinsic!");
|
|
}
|
|
}
|
|
|
|
DebugLoc SPIRVToLLVMDbgTran::transDebugScope(const SPIRVInstruction *Inst) {
|
|
unsigned Line = 0;
|
|
unsigned Col = 0;
|
|
MDNode *Scope = nullptr;
|
|
MDNode *InlinedAt = nullptr;
|
|
|
|
// If DebugLine and OpLine are both active give DebugLine priority
|
|
if (auto DL = Inst->getDebugLine()) {
|
|
using namespace SPIRVDebug::Operand::DebugLine;
|
|
SPIRVWordVec DebugLineArgs = DL->getArguments();
|
|
Line =
|
|
getConstantValueOrLiteral(DebugLineArgs, StartIdx, DL->getExtSetKind());
|
|
Col = getConstantValueOrLiteral(DebugLineArgs, ColumnStartIdx,
|
|
DL->getExtSetKind());
|
|
} else if (auto L = Inst->getLine()) {
|
|
Line = L->getLine();
|
|
Col = L->getColumn();
|
|
}
|
|
if (SPIRVEntry *S = Inst->getDebugScope()) {
|
|
using namespace SPIRVDebug::Operand::Scope;
|
|
SPIRVExtInst *DbgScope = static_cast<SPIRVExtInst *>(S);
|
|
SPIRVWordVec Ops = DbgScope->getArguments();
|
|
Scope = getScope(BM->getEntry(Ops[ScopeIdx]));
|
|
if (Ops.size() > InlinedAtIdx)
|
|
InlinedAt = transDebugInst(BM->get<SPIRVExtInst>(Ops[InlinedAtIdx]));
|
|
return DILocation::get(M->getContext(), Line, Col, Scope, InlinedAt);
|
|
}
|
|
return DebugLoc();
|
|
}
|
|
|
|
MDNode *SPIRVToLLVMDbgTran::transDebugInlined(const SPIRVExtInst *DebugInst) {
|
|
// There is a Column operand in NonSemantic.Shader.200 spec
|
|
if (DebugInst->getExtSetKind() ==
|
|
SPIRV::SPIRVEIS_NonSemantic_Shader_DebugInfo_200)
|
|
return transDebugInlinedNonSemanticShader200(DebugInst);
|
|
|
|
using namespace SPIRVDebug::Operand::InlinedAt::OpenCL;
|
|
SPIRVWordVec Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
SPIRVWord Line =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
unsigned Col = 0; // DebugInlinedAt instruction has no column operand
|
|
DILocalScope *Scope =
|
|
cast<DILocalScope>(getScope(BM->getEntry(Ops[ScopeIdx])));
|
|
DILocation *InlinedAt = nullptr;
|
|
if (Ops.size() > InlinedIdx) {
|
|
InlinedAt =
|
|
transDebugInst<DILocation>(BM->get<SPIRVExtInst>(Ops[InlinedIdx]));
|
|
}
|
|
return DILocation::getDistinct(M->getContext(), Line, Col, Scope, InlinedAt);
|
|
}
|
|
|
|
MDNode *SPIRVToLLVMDbgTran::transDebugInlinedNonSemanticShader200(
|
|
const SPIRVExtInst *DebugInst) {
|
|
using namespace SPIRVDebug::Operand::InlinedAt::NonSemantic;
|
|
SPIRVWordVec Ops = DebugInst->getArguments();
|
|
assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
|
|
SPIRVWord Line =
|
|
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
|
|
unsigned Col =
|
|
getConstantValueOrLiteral(Ops, ColumnIdx, DebugInst->getExtSetKind());
|
|
DILocalScope *Scope =
|
|
cast<DILocalScope>(getScope(BM->getEntry(Ops[ScopeIdx])));
|
|
DILocation *InlinedAt = nullptr;
|
|
if (Ops.size() > InlinedIdx) {
|
|
InlinedAt =
|
|
transDebugInst<DILocation>(BM->get<SPIRVExtInst>(Ops[InlinedIdx]));
|
|
}
|
|
return DILocation::getDistinct(M->getContext(), Line, Col, Scope, InlinedAt);
|
|
}
|
|
|
|
void SPIRVToLLVMDbgTran::finalize() {
|
|
if (!Enable)
|
|
return;
|
|
for (const auto &Builder : BuilderMap)
|
|
Builder.second->finalize();
|
|
}
|
|
|
|
DIFile *SPIRVToLLVMDbgTran::getFile(const SPIRVId SourceId) {
|
|
using namespace SPIRVDebug::Operand::Source;
|
|
SPIRVExtInst *Source = BM->get<SPIRVExtInst>(SourceId);
|
|
assert(Source->getExtOp() == SPIRVDebug::Source &&
|
|
"DebugSource instruction is expected");
|
|
SPIRVWordVec SourceArgs = Source->getArguments();
|
|
assert(SourceArgs.size() >= MinOperandCount && "Invalid number of operands");
|
|
if (SourceArgs.size() == MinOperandCount)
|
|
return getDIFile(getString(SourceArgs[FileIdx]));
|
|
|
|
if (!isNonSemanticDebugInfo(Source->getExtSetKind())) {
|
|
std::string ChecksumStr =
|
|
getDbgInst<SPIRVDebug::DebugInfoNone>(SourceArgs[TextIdx])
|
|
? ""
|
|
: getString(SourceArgs[TextIdx]);
|
|
return getDIFile(getString(SourceArgs[FileIdx]),
|
|
ParseChecksum(ChecksumStr));
|
|
}
|
|
|
|
std::optional<DIFile::ChecksumInfo<StringRef>> CS;
|
|
SPIRVWord StrIdx = SourceArgs[TextIdx];
|
|
if (Source->getExtSetKind() == SPIRVEIS_NonSemantic_Shader_DebugInfo_200) {
|
|
if (SourceArgs.size() >= MaxOperandCount - 1) {
|
|
// 2 optional parameters are ChecksumKind and ChecksumValue - they should
|
|
// go together
|
|
if (!getDbgInst<SPIRVDebug::DebugInfoNone>(SourceArgs[ChecksumKind]) &&
|
|
!getDbgInst<SPIRVDebug::DebugInfoNone>(SourceArgs[ChecksumValue])) {
|
|
llvm::DIFile::ChecksumKind Kind = SPIRV::DbgChecksumKindMap::rmap(
|
|
static_cast<SPIRVDebug::FileChecksumKind>(
|
|
BM->get<SPIRVConstant>(SourceArgs[ChecksumKind])
|
|
->getZExtIntValue()));
|
|
StringRef Checksum = getString(SourceArgs[ChecksumValue]);
|
|
size_t ChecksumEndPos = Checksum.find_if_not(llvm::isHexDigit);
|
|
CS.emplace(Kind, Checksum.substr(0, ChecksumEndPos));
|
|
}
|
|
}
|
|
|
|
// Among optional parameters - text is always the last one (either 1st or
|
|
// 3rd)
|
|
if (SourceArgs.size() == MaxOperandCount ||
|
|
SourceArgs.size() == MaxOperandCount - 2)
|
|
StrIdx = SourceArgs[TextNonSemIdx];
|
|
else
|
|
StrIdx = SPIRVID_INVALID;
|
|
}
|
|
|
|
return getDIFile(getString(SourceArgs[FileIdx]), CS,
|
|
getStringSourceContinued(StrIdx, Source));
|
|
}
|
|
|
|
void SPIRVToLLVMDbgTran::setBuildIdentifierAndStoragePath() {
|
|
#ifndef NDEBUG
|
|
bool FoundBuildIdentifier{false};
|
|
bool FoundStoragePath{false};
|
|
#endif
|
|
|
|
for (SPIRVExtInst *EI : BM->getDebugInstVec()) {
|
|
if (EI->getExtOp() == SPIRVDebug::BuildIdentifier) {
|
|
using namespace SPIRVDebug::Operand::BuildIdentifier;
|
|
SPIRVWordVec BuildIdentifierArgs = EI->getArguments();
|
|
assert(BuildIdentifierArgs.size() == OperandCount &&
|
|
"Invalid number of operands");
|
|
assert(!FoundBuildIdentifier &&
|
|
"More than one BuildIdentifier instruction not allowed");
|
|
BuildIdentifier = strtoull(
|
|
getString(BuildIdentifierArgs[IdentifierIdx]).c_str(), NULL, 10);
|
|
#ifndef NDEBUG
|
|
FoundBuildIdentifier = true;
|
|
#endif
|
|
} else if (EI->getExtOp() == SPIRVDebug::StoragePath) {
|
|
using namespace SPIRVDebug::Operand::StoragePath;
|
|
SPIRVWordVec StoragePathArgs = EI->getArguments();
|
|
assert(StoragePathArgs.size() == OperandCount &&
|
|
"Invalid number of operands");
|
|
assert(!FoundStoragePath &&
|
|
"More than one StoragePath instruction not allowed");
|
|
StoragePath = getString(StoragePathArgs[PathIdx]);
|
|
#ifndef NDEBUG
|
|
FoundStoragePath = true;
|
|
#endif
|
|
}
|
|
}
|
|
assert(((FoundBuildIdentifier && FoundStoragePath) ||
|
|
(!FoundBuildIdentifier && !FoundStoragePath)) &&
|
|
"BuildIdentifier and StoragePath must both be set or both unset");
|
|
}
|
|
|
|
DIBuilder &SPIRVToLLVMDbgTran::getDIBuilder(const SPIRVExtInst *DebugInst) {
|
|
assert(BuilderMap.size() != 0 && "No debug compile units");
|
|
if (BuilderMap.size() == 1)
|
|
return *BuilderMap.begin()->second;
|
|
while (DebugInst->getExtOp() != SPIRVDebug::CompilationUnit) {
|
|
if (DebugInst->getExtOp() == SPIRVDebug::DebugInfoNone)
|
|
return *BuilderMap.begin()->second;
|
|
const SPIRVWordVec &Ops = DebugInst->getArguments();
|
|
SPIRVWord ParentScopeIdx = 0;
|
|
if (!hasDbgInstParentScopeIdx(DebugInst->getExtOp(), ParentScopeIdx,
|
|
DebugInst->getExtSetKind()))
|
|
return *BuilderMap.begin()->second;
|
|
if (SPIRVEntry *Scope = BM->getEntry(Ops[ParentScopeIdx])) {
|
|
DebugInst = static_cast<SPIRVExtInst *>(Scope);
|
|
continue;
|
|
}
|
|
return *BuilderMap.begin()->second;
|
|
}
|
|
return *BuilderMap[DebugInst->getId()];
|
|
}
|
|
|
|
SPIRVToLLVMDbgTran::SplitFileName::SplitFileName(const std::string &FileName) {
|
|
auto Loc = FileName.find_last_of("/\\");
|
|
if (Loc != std::string::npos) {
|
|
BaseName = FileName.substr(Loc + 1);
|
|
Path = FileName.substr(0, Loc);
|
|
} else {
|
|
BaseName = FileName;
|
|
Path = ".";
|
|
}
|
|
}
|
|
|
|
std::string SPIRVToLLVMDbgTran::findModuleProducer() {
|
|
for (const auto &I : BM->getModuleProcessedVec()) {
|
|
if (I->getProcessStr().find(SPIRVDebug::ProducerPrefix) !=
|
|
std::string::npos) {
|
|
return I->getProcessStr().substr(SPIRVDebug::ProducerPrefix.size());
|
|
}
|
|
}
|
|
return "spirv";
|
|
}
|
|
|
|
std::optional<DIFile::ChecksumInfo<StringRef>>
|
|
SPIRVToLLVMDbgTran::ParseChecksum(StringRef Text) {
|
|
// Example of "Text" variable:
|
|
// "SomeInfo//__CSK_MD5:7bb56387968a9caa6e9e35fff94eaf7b:OtherInfo"
|
|
std::optional<DIFile::ChecksumInfo<StringRef>> CS;
|
|
auto KindPos = Text.find(SPIRVDebug::ChecksumKindPrefx);
|
|
if (KindPos != StringRef::npos) {
|
|
auto ColonPos = Text.find(":", KindPos);
|
|
KindPos += std::string("//__").size();
|
|
auto KindStr = Text.substr(KindPos, ColonPos - KindPos);
|
|
auto Checksum = Text.substr(ColonPos).ltrim(':');
|
|
if (auto Kind = DIFile::getChecksumKind(KindStr)) {
|
|
size_t ChecksumEndPos = Checksum.find_if_not(llvm::isHexDigit);
|
|
CS.emplace(Kind.value(), Checksum.substr(0, ChecksumEndPos));
|
|
}
|
|
}
|
|
return CS;
|
|
}
|
|
|
|
} // namespace SPIRV
|