blob: c7c99cf7638c4ad47cc95c1cccb751b83b30ecf3 [file] [edit]
///////////////////////////////////////////////////////////////////////////////
// //
// PixPassHelpers.cpp
// // Copyright (C) Microsoft Corporation. All rights reserved. // This file is
// distributed under the University of Illinois Open Source // License. See
// LICENSE.TXT for details. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "dxc/DXIL/DxilFunctionProps.h"
#include "dxc/DXIL/DxilInstructions.h"
#include "dxc/DXIL/DxilModule.h"
#include "dxc/DXIL/DxilOperations.h"
#include "dxc/DXIL/DxilResourceBinding.h"
#include "dxc/DXIL/DxilResourceProperties.h"
#include "dxc/DxilRootSignature/DxilRootSignature.h"
#include "dxc/HLSL/DxilSpanAllocator.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include "PixPassHelpers.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/WinIncludes.h"
#include "dxc/dxcapi.h"
#ifdef PIX_DEBUG_DUMP_HELPER
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include <iostream>
#endif
using namespace llvm;
using namespace hlsl;
namespace PIXPassHelpers {
static void FindRayQueryHandlesFromUse(Value *U,
SmallPtrSetImpl<Value *> &Handles) {
if (Handles.insert(U).second) {
auto RayQueryHandleUses = U->uses();
for (Use &Use : RayQueryHandleUses) {
iterator_range<Value::user_iterator> Users = Use->users();
for (User *User : Users) {
if (isa<PHINode>(User) || isa<SelectInst>(User))
FindRayQueryHandlesFromUse(User, Handles);
}
}
}
}
void FindRayQueryHandlesForFunction(llvm::Function *F,
SmallPtrSetImpl<Value *> &RayQueryHandles) {
auto &blocks = F->getBasicBlockList();
if (!blocks.empty()) {
for (auto &block : blocks) {
for (auto &instruction : block) {
if (hlsl::OP::IsDxilOpFuncCallInst(
&instruction, hlsl::OP::OpCode::AllocateRayQuery)) {
FindRayQueryHandlesFromUse(&instruction, RayQueryHandles);
}
}
}
}
}
static bool IsDynamicResourceShaderModel(DxilModule &DM) {
return DM.GetShaderModel()->IsSMAtLeast(6, 6);
}
static bool ShaderModelRequiresAnnotateHandle(DxilModule &DM) {
return DM.GetShaderModel()->IsSMAtLeast(6, 6);
}
static char const *RawUAVType() { return "struct.RWByteAddressBuffer"; }
static char const *ShaderModelHandleTypeName(DxilModule &DM) {
// Prior to sm6.6, lib handles were typed after the resource they denote.
// In 6.6 and after, and in all non-lib shader models,
// all handles are dx.types.Handle.
if (!DM.GetShaderModel()->IsLib() || DM.GetShaderModel()->IsSM66Plus())
return "dx.types.Handle";
return RawUAVType();
}
llvm::CallInst *CreateHandleForResource(hlsl::DxilModule &DM,
llvm::IRBuilder<> &Builder,
hlsl::DxilResourceBase *resource,
const char *name) {
OP *HlslOP = DM.GetOP();
LLVMContext &Ctx = DM.GetModule()->getContext();
DXIL::ResourceClass resourceClass = resource->GetClass();
auto const *shaderModel = DM.GetShaderModel();
Type *resourceHandleType =
DM.GetModule()->getTypeByName(ShaderModelHandleTypeName(DM));
if (shaderModel->IsLib()) {
llvm::Constant *object = resource->GetGlobalSymbol();
Value *load = Builder.CreateLoad(object, resourceHandleType);
llvm::cast<LoadInst>(load)->setAlignment(4);
llvm::cast<LoadInst>(load)->setVolatile(false);
Function *CreateHandleForLibOpFunc =
HlslOP->GetOpFunc(DXIL::OpCode::CreateHandleForLib, load->getType());
Constant *CreateHandleForLibOpcodeArg =
HlslOP->GetU32Const((unsigned)DXIL::OpCode::CreateHandleForLib);
auto *handle = Builder.CreateCall(CreateHandleForLibOpFunc,
{CreateHandleForLibOpcodeArg, load});
if (ShaderModelRequiresAnnotateHandle(DM)) {
Function *annotHandleFn =
HlslOP->GetOpFunc(DXIL::OpCode::AnnotateHandle, Type::getVoidTy(Ctx));
Value *annotHandleArg =
HlslOP->GetI32Const((unsigned)DXIL::OpCode::AnnotateHandle);
DxilResourceProperties RP =
resource_helper::loadPropsFromResourceBase(resource);
Type *resPropertyTy = HlslOP->GetResourcePropertiesType();
Value *propertiesV = resource_helper::getAsConstant(RP, resPropertyTy,
*DM.GetShaderModel());
return Builder.CreateCall(annotHandleFn,
{annotHandleArg, handle, propertiesV});
} else {
return handle;
}
} else if (IsDynamicResourceShaderModel(DM)) {
Function *CreateHandleFromBindingOpFunc = HlslOP->GetOpFunc(
DXIL::OpCode::CreateHandleFromBinding, Type::getVoidTy(Ctx));
Constant *CreateHandleFromBindingOpcodeArg =
HlslOP->GetU32Const((unsigned)DXIL::OpCode::CreateHandleFromBinding);
DxilResourceBinding binding =
resource_helper::loadBindingFromResourceBase(resource);
Value *bindingV = resource_helper::getAsConstant(
binding, HlslOP->GetResourceBindingType(), *DM.GetShaderModel());
Value *registerIndex = HlslOP->GetU32Const(0);
Value *isUniformRes = HlslOP->GetI1Const(0);
Value *createHandleFromBindingArgs[] = {CreateHandleFromBindingOpcodeArg,
bindingV, registerIndex,
isUniformRes};
auto *handle = Builder.CreateCall(CreateHandleFromBindingOpFunc,
createHandleFromBindingArgs, name);
Function *annotHandleFn =
HlslOP->GetOpFunc(DXIL::OpCode::AnnotateHandle, Type::getVoidTy(Ctx));
Value *annotHandleArg =
HlslOP->GetI32Const((unsigned)DXIL::OpCode::AnnotateHandle);
DxilResourceProperties RP =
resource_helper::loadPropsFromResourceBase(resource);
Type *resPropertyTy = HlslOP->GetResourcePropertiesType();
Value *propertiesV =
resource_helper::getAsConstant(RP, resPropertyTy, *DM.GetShaderModel());
return Builder.CreateCall(annotHandleFn,
{annotHandleArg, handle, propertiesV});
} else {
Function *CreateHandleOpFunc =
HlslOP->GetOpFunc(DXIL::OpCode::CreateHandle, Type::getVoidTy(Ctx));
Constant *CreateHandleOpcodeArg =
HlslOP->GetU32Const((unsigned)DXIL::OpCode::CreateHandle);
Constant *ClassArg = HlslOP->GetI8Const(
static_cast<std::underlying_type<DxilResourceBase::Class>::type>(
resourceClass));
Constant *MetaDataArg = HlslOP->GetU32Const(resource->GetID());
Constant *IndexArg = HlslOP->GetU32Const(0);
Constant *FalseArg =
HlslOP->GetI1Const(0); // non-uniform resource index: false
return Builder.CreateCall(
CreateHandleOpFunc,
{CreateHandleOpcodeArg, ClassArg, MetaDataArg, IndexArg, FalseArg},
name);
}
}
static std::vector<uint8_t> SerializeRootSignatureToVector(
DxilVersionedRootSignatureDesc const *rootSignature) {
CComPtr<IDxcBlob> serializedRootSignature;
CComPtr<IDxcBlobEncoding> errorBlob;
constexpr bool allowReservedRegisterSpace = true;
SerializeRootSignature(rootSignature, &serializedRootSignature, &errorBlob,
allowReservedRegisterSpace);
std::vector<uint8_t> ret;
auto const *serializedData = reinterpret_cast<const uint8_t *>(
serializedRootSignature->GetBufferPointer());
ret.assign(serializedData,
serializedData + serializedRootSignature->GetBufferSize());
return ret;
}
constexpr uint32_t toolsRegisterSpace = static_cast<uint32_t>(-2);
constexpr uint32_t toolsUAVRegister = 0;
template <typename RootSigDesc, typename RootParameterDesc>
void ExtendRootSig(RootSigDesc &rootSigDesc) {
auto *existingParams = rootSigDesc.pParameters;
for (uint32_t i = 0; i < rootSigDesc.NumParameters; ++i) {
if (rootSigDesc.pParameters[i].ParameterType ==
DxilRootParameterType::UAV) {
if (rootSigDesc.pParameters[i].Descriptor.RegisterSpace ==
toolsRegisterSpace &&
rootSigDesc.pParameters[i].Descriptor.ShaderRegister ==
toolsUAVRegister) {
// Already added
return;
}
}
}
auto *newParams = new RootParameterDesc[rootSigDesc.NumParameters + 1];
if (existingParams != nullptr) {
memcpy(newParams, existingParams,
rootSigDesc.NumParameters * sizeof(RootParameterDesc));
delete[] existingParams;
}
rootSigDesc.pParameters = newParams;
rootSigDesc.pParameters[rootSigDesc.NumParameters].ParameterType =
DxilRootParameterType::UAV;
rootSigDesc.pParameters[rootSigDesc.NumParameters].Descriptor.RegisterSpace =
toolsRegisterSpace;
rootSigDesc.pParameters[rootSigDesc.NumParameters].Descriptor.ShaderRegister =
toolsUAVRegister;
rootSigDesc.pParameters[rootSigDesc.NumParameters].ShaderVisibility =
DxilShaderVisibility::All;
rootSigDesc.NumParameters++;
}
static std::vector<uint8_t> AddUAVParamterToRootSignature(const void *Data,
uint32_t Size) {
DxilVersionedRootSignature rootSignature;
DeserializeRootSignature(Data, Size, rootSignature.get_address_of());
auto *rs = rootSignature.get_mutable();
switch (rootSignature->Version) {
case DxilRootSignatureVersion::Version_1_0:
ExtendRootSig<DxilRootSignatureDesc, DxilRootParameter>(rs->Desc_1_0);
break;
case DxilRootSignatureVersion::Version_1_1:
ExtendRootSig<DxilRootSignatureDesc1, DxilRootParameter1>(rs->Desc_1_1);
rs->Desc_1_1.pParameters[rs->Desc_1_1.NumParameters - 1].Descriptor.Flags =
hlsl::DxilRootDescriptorFlags::None;
break;
}
return SerializeRootSignatureToVector(rs);
}
static void AddUAVToShaderAttributeRootSignature(DxilModule &DM) {
auto rs = DM.GetSerializedRootSignature();
if (!rs.empty()) {
std::vector<uint8_t> asVector = AddUAVParamterToRootSignature(
rs.data(), static_cast<uint32_t>(rs.size()));
DM.ResetSerializedRootSignature(asVector);
}
}
static void AddUAVToDxilDefinedGlobalRootSignatures(DxilModule &DM) {
auto *subObjects = DM.GetSubobjects();
if (subObjects != nullptr) {
for (auto const &subObject : subObjects->GetSubobjects()) {
if (subObject.second->GetKind() ==
DXIL::SubobjectKind::GlobalRootSignature) {
const void *Data = nullptr;
uint32_t Size = 0;
constexpr bool notALocalRS = false;
if (subObject.second->GetRootSignature(notALocalRS, Data, Size,
nullptr)) {
auto extendedRootSig = AddUAVParamterToRootSignature(Data, Size);
auto rootSignatureSubObjectName = subObject.first;
subObjects->RemoveSubobject(rootSignatureSubObjectName);
subObjects->CreateRootSignature(
rootSignatureSubObjectName, notALocalRS, extendedRootSig.data(),
static_cast<uint32_t>(extendedRootSig.size()));
break;
}
}
}
}
}
// Set up a UAV with structure of a single int
hlsl::DxilResource *CreateGlobalUAVResource(hlsl::DxilModule &DM,
unsigned int hlslBindIndex,
const char *name) {
LLVMContext &Ctx = DM.GetModule()->getContext();
const char *PIXStructTypeName = ShaderModelHandleTypeName(DM);
llvm::StructType *UAVStructTy =
DM.GetModule()->getTypeByName(PIXStructTypeName);
if (UAVStructTy == nullptr) {
SmallVector<llvm::Type *, 1> Elements{Type::getInt32Ty(Ctx)};
UAVStructTy = llvm::StructType::create(Elements, PIXStructTypeName);
}
// Since this function should only be called once per module,
// we can modify the root sig at the same time:
AddUAVToDxilDefinedGlobalRootSignatures(DM);
AddUAVToShaderAttributeRootSignature(DM);
unsigned int Id = static_cast<unsigned int>(DM.GetUAVs().size());
std::unique_ptr<DxilResource> pUAV = llvm::make_unique<DxilResource>();
pUAV->SetID(Id);
auto const *shaderModel = DM.GetShaderModel();
std::string PixUavName = "PIXUAV" + std::to_string(hlslBindIndex);
if (shaderModel->IsLib()) {
auto *Global =
DM.GetModule()->getOrInsertGlobal(PixUavName.c_str(), UAVStructTy);
GlobalVariable *NewGV = cast<GlobalVariable>(Global);
NewGV->setConstant(true);
NewGV->setLinkage(GlobalValue::ExternalLinkage);
NewGV->setThreadLocal(false);
NewGV->setAlignment(4);
pUAV->SetGlobalSymbol(NewGV);
} else {
pUAV->SetGlobalSymbol(UndefValue::get(UAVStructTy->getPointerTo()));
}
pUAV->SetGlobalName(name);
pUAV->SetRW(true); // sets UAV class
pUAV->SetSpaceID(
(unsigned int)-2); // This is the reserved-for-tools register space
pUAV->SetSampleCount(0); // This is what compiler generates for a raw UAV
pUAV->SetGloballyCoherent(false);
pUAV->SetReorderCoherent(false);
pUAV->SetHasCounter(false);
pUAV->SetCompType(
CompType::getInvalid()); // This is what compiler generates for a raw UAV
pUAV->SetLowerBound(hlslBindIndex);
pUAV->SetRangeSize(1);
pUAV->SetElementStride(1);
pUAV->SetKind(DXIL::ResourceKind::RawBuffer);
auto HLSLType = DM.GetModule()->getTypeByName(RawUAVType());
if (HLSLType == nullptr) {
SmallVector<llvm::Type *, 1> Elements{Type::getInt32Ty(Ctx)};
HLSLType = llvm::StructType::create(Elements, RawUAVType());
}
pUAV->SetHLSLType(HLSLType->getPointerTo());
auto pAnnotation = DM.GetTypeSystem().GetStructAnnotation(UAVStructTy);
if (pAnnotation == nullptr) {
pAnnotation = DM.GetTypeSystem().AddStructAnnotation(UAVStructTy);
pAnnotation->GetFieldAnnotation(0).SetCBufferOffset(0);
pAnnotation->GetFieldAnnotation(0).SetCompType(
hlsl::DXIL::ComponentType::I32);
pAnnotation->GetFieldAnnotation(0).SetFieldName("count");
}
auto *ret = pUAV.get();
DM.AddUAV(std::move(pUAV));
return ret;
}
// Set up a UAV with structure of a single int
llvm::CallInst *CreateUAVOnceForModule(hlsl::DxilModule &DM,
llvm::IRBuilder<> &Builder,
unsigned int hlslBindIndex,
const char *name) {
auto uav = CreateGlobalUAVResource(DM, hlslBindIndex, name);
auto *handle = CreateHandleForResource(DM, Builder, uav, name);
return handle;
}
llvm::Function *GetEntryFunction(hlsl::DxilModule &DM) {
if (DM.GetEntryFunction() != nullptr) {
return DM.GetEntryFunction();
}
return DM.GetPatchConstantFunction();
}
std::vector<llvm::Function *>
GetAllInstrumentableFunctions(hlsl::DxilModule &DM) {
std::vector<llvm::Function *> ret;
for (llvm::Function &F : DM.GetModule()->functions()) {
if (F.isDeclaration() || F.isIntrinsic() || hlsl::OP::IsDxilOpFunc(&F))
continue;
if (F.getBasicBlockList().empty())
continue;
ret.push_back(&F);
}
return ret;
}
hlsl::DXIL::ShaderKind GetFunctionShaderKind(hlsl::DxilModule &DM,
llvm::Function *fn) {
hlsl::DXIL::ShaderKind shaderKind = hlsl::DXIL::ShaderKind::Invalid;
if (!DM.HasDxilFunctionProps(fn)) {
auto ShaderModel = DM.GetShaderModel();
shaderKind = ShaderModel->GetKind();
} else {
hlsl::DxilFunctionProps const &props = DM.GetDxilFunctionProps(fn);
shaderKind = props.shaderKind;
}
return shaderKind;
}
std::vector<llvm::BasicBlock *> GetAllBlocks(hlsl::DxilModule &DM) {
std::vector<llvm::BasicBlock *> ret;
auto entryPoints = DM.GetExportedFunctions();
for (auto &fn : entryPoints) {
auto &blocks = fn->getBasicBlockList();
for (auto &block : blocks) {
ret.push_back(&block);
}
}
return ret;
}
ExpandedStruct ExpandStructType(LLVMContext &Ctx,
Type *OriginalPayloadStructType) {
SmallVector<Type *, 16> Elements;
for (unsigned int i = 0;
i < OriginalPayloadStructType->getStructNumElements(); ++i) {
Elements.push_back(OriginalPayloadStructType->getStructElementType(i));
}
Elements.push_back(Type::getInt32Ty(Ctx));
Elements.push_back(Type::getInt32Ty(Ctx));
Elements.push_back(Type::getInt32Ty(Ctx));
ExpandedStruct ret;
ret.ExpandedPayloadStructType =
StructType::create(Ctx, Elements, "PIX_AS2MS_Expanded_Type");
ret.ExpandedPayloadStructPtrType =
ret.ExpandedPayloadStructType->getPointerTo();
return ret;
}
void ReplaceAllUsesOfInstructionWithNewValueAndDeleteInstruction(
Instruction *Instr, Value *newValue, Type *newType) {
std::vector<Value *> users;
for (auto u = Instr->user_begin(); u != Instr->user_end(); ++u) {
users.push_back(*u);
}
for (auto user : users) {
if (auto *instruction = llvm::cast<Instruction>(user)) {
for (unsigned int i = 0; i < instruction->getNumOperands(); ++i) {
auto *Operand = instruction->getOperand(i);
if (Operand == Instr) {
instruction->setOperand(i, newValue);
}
}
if (llvm::isa<GetElementPtrInst>(instruction)) {
auto *GEP = llvm::cast<GetElementPtrInst>(instruction);
GEP->setSourceElementType(newType);
} else if (hlsl::OP::IsDxilOpFuncCallInst(
instruction, hlsl::OP::OpCode::DispatchMesh)) {
DxilModule &DM = instruction->getModule()->GetOrCreateDxilModule();
OP *HlslOP = DM.GetOP();
DxilInst_DispatchMesh DispatchMesh(instruction);
IRBuilder<> B(instruction);
SmallVector<Value *, 5> args;
args.push_back(
HlslOP->GetU32Const((unsigned)hlsl::OP::OpCode::DispatchMesh));
args.push_back(DispatchMesh.get_threadGroupCountX());
args.push_back(DispatchMesh.get_threadGroupCountY());
args.push_back(DispatchMesh.get_threadGroupCountZ());
args.push_back(newValue);
B.CreateCall(HlslOP->GetOpFunc(DXIL::OpCode::DispatchMesh,
newType->getPointerTo()),
args);
instruction->removeFromParent();
delete instruction;
}
}
}
Instr->removeFromParent();
delete Instr;
}
unsigned int FindOrAddSV_Position(hlsl::DxilModule &DM,
unsigned UpStreamSVPosRow) {
hlsl::DxilSignature &InputSignature = DM.GetInputSignature();
auto &InputElements = InputSignature.GetElements();
auto Existing_SV_Position =
std::find_if(InputElements.begin(), InputElements.end(),
[](const std::unique_ptr<DxilSignatureElement> &Element) {
return Element->GetSemantic()->GetKind() ==
hlsl::DXIL::SemanticKind::Position;
});
// SV_Position, if present, has to have full mask, so we needn't worry
// about the shader having selected components that don't include x or y.
// If not present, we add it.
if (Existing_SV_Position == InputElements.end()) {
unsigned int StartColumn = 0;
unsigned int RowCount = 1;
unsigned int ColumnCount = 4;
auto Added_SV_Position =
llvm::make_unique<DxilSignatureElement>(DXIL::SigPointKind::PSIn);
Added_SV_Position->Initialize("Position", hlsl::CompType::getF32(),
hlsl::DXIL::InterpolationMode::Linear,
RowCount, ColumnCount, UpStreamSVPosRow,
StartColumn);
Added_SV_Position->AppendSemanticIndex(0);
Added_SV_Position->SetKind(hlsl::DXIL::SemanticKind::Position);
// AppendElement sets the element's ID by default
auto index = InputSignature.AppendElement(std::move(Added_SV_Position));
return InputElements[index]->GetID();
} else {
return Existing_SV_Position->get()->GetID();
}
}
void ForEachDynamicallyIndexedResource(
hlsl::DxilModule &DM,
const std::function<bool(bool, Instruction *, Value *)> &Visitor) {
OP *HlslOP = DM.GetOP();
LLVMContext &Ctx = DM.GetModule()->getContext();
for (llvm::Function &F : DM.GetModule()->functions()) {
if (F.isDeclaration() && !F.use_empty() && OP::IsDxilOpFunc(&F)) {
if (F.hasName()) {
if (F.getName().find("createHandleForLib") != StringRef::npos) {
auto FunctionUses = F.uses();
for (auto FI = FunctionUses.begin(); FI != FunctionUses.end();) {
auto &FunctionUse = *FI++;
auto FunctionUser = FunctionUse.getUser();
auto instruction = cast<Instruction>(FunctionUser);
Value *resourceLoad = instruction->getOperand(
DXIL::OperandIndex::kCreateHandleForLibResOpIdx);
if (auto *load = cast<LoadInst>(resourceLoad)) {
auto *resOrGep = load->getOperand(0);
if (auto *gep = dyn_cast<GetElementPtrInst>(resOrGep)) {
if (!Visitor(DxilMDHelper::IsMarkedNonUniform(gep), load,
gep->getOperand(2))) {
return;
}
}
}
}
}
}
}
}
auto CreateHandleFn =
HlslOP->GetOpFunc(DXIL::OpCode::CreateHandle, Type::getVoidTy(Ctx));
for (auto FI = CreateHandleFn->user_begin();
FI != CreateHandleFn->user_end();) {
auto *FunctionUser = *FI++;
auto instruction = cast<Instruction>(FunctionUser);
Value *index =
instruction->getOperand(DXIL::OperandIndex::kCreateHandleResIndexOpIdx);
if (!isa<Constant>(index)) {
const DxilInst_CreateHandle createHandle(instruction);
if (!Visitor(createHandle.get_nonUniformIndex_val(), instruction,
index)) {
return;
}
}
}
auto CreateHandleFromBindingFn = HlslOP->GetOpFunc(
DXIL::OpCode::CreateHandleFromBinding, Type::getVoidTy(Ctx));
for (auto FI = CreateHandleFromBindingFn->user_begin();
FI != CreateHandleFromBindingFn->user_end();) {
auto *FunctionUser = *FI++;
auto instruction = cast<Instruction>(FunctionUser);
Value *index = instruction->getOperand(
DXIL::OperandIndex::kCreateHandleFromBindingResIndexOpIdx);
if (!isa<Constant>(index)) {
const DxilInst_CreateHandleFromBinding createHandle(instruction);
if (!Visitor(createHandle.get_nonUniformIndex_val(), instruction,
index)) {
return;
}
}
}
auto CreateHandleFromHeapFn = HlslOP->GetOpFunc(
DXIL::OpCode::CreateHandleFromHeap, Type::getVoidTy(Ctx));
for (auto FI = CreateHandleFromHeapFn->user_begin();
FI != CreateHandleFromHeapFn->user_end();) {
auto *FunctionUser = *FI++;
auto instruction = cast<Instruction>(FunctionUser);
Value *index = instruction->getOperand(
DXIL::OperandIndex::kCreateHandleFromHeapHeapIndexOpIdx);
if (!isa<Constant>(index)) {
const DxilInst_CreateHandleFromHeap createHandle(instruction);
if (!Visitor(createHandle.get_nonUniformIndex_val(), instruction,
index)) {
return;
}
}
}
}
#ifdef PIX_DEBUG_DUMP_HELPER
static int g_logIndent = 0;
void IncreaseLogIndent() { g_logIndent++; }
void DecreaseLogIndent() { --g_logIndent; }
void Log(const char *format, ...) {
va_list argumentPointer;
va_start(argumentPointer, format);
char buffer[512];
vsnprintf(buffer, _countof(buffer), format, argumentPointer);
va_end(argumentPointer);
for (int i = 0; i < g_logIndent; ++i) {
OutputDebugFormatA(" ");
}
OutputDebugFormatA(buffer);
OutputDebugFormatA("\n");
}
void LogPartialLine(const char *format, ...) {
va_list argumentPointer;
va_start(argumentPointer, format);
char buffer[512];
vsnprintf(buffer, _countof(buffer), format, argumentPointer);
va_end(argumentPointer);
for (int i = 0; i < g_logIndent; ++i) {
OutputDebugFormatA(" ");
}
OutputDebugFormatA(buffer);
}
static llvm::DIType const *DITypePeelTypeAlias(llvm::DIType const *Ty) {
if (auto *DerivedTy = llvm::dyn_cast<llvm::DIDerivedType>(Ty)) {
const llvm::DITypeIdentifierMap EmptyMap;
switch (DerivedTy->getTag()) {
case llvm::dwarf::DW_TAG_restrict_type:
case llvm::dwarf::DW_TAG_reference_type:
case llvm::dwarf::DW_TAG_const_type:
case llvm::dwarf::DW_TAG_typedef:
case llvm::dwarf::DW_TAG_pointer_type:
case llvm::dwarf::DW_TAG_member:
return DITypePeelTypeAlias(DerivedTy->getBaseType().resolve(EmptyMap));
}
}
return Ty;
}
void DumpArrayType(llvm::DICompositeType const *Ty);
void DumpStructType(llvm::DICompositeType const *Ty);
void DumpFullType(llvm::DIType const *type) {
auto *Ty = DITypePeelTypeAlias(type);
const llvm::DITypeIdentifierMap EmptyMap;
if (auto *DerivedTy = llvm::dyn_cast<llvm::DIDerivedType>(Ty)) {
switch (DerivedTy->getTag()) {
default:
assert(!"Unhandled DIDerivedType");
std::abort();
return;
case llvm::dwarf::DW_TAG_arg_variable: // "this" pointer
case llvm::dwarf::DW_TAG_pointer_type: // "this" pointer
case llvm::dwarf::DW_TAG_restrict_type:
case llvm::dwarf::DW_TAG_reference_type:
case llvm::dwarf::DW_TAG_const_type:
case llvm::dwarf::DW_TAG_typedef:
case llvm::dwarf::DW_TAG_inheritance:
DumpFullType(DerivedTy->getBaseType().resolve(EmptyMap));
return;
case llvm::dwarf::DW_TAG_member: {
Log("Member variable");
ScopedIndenter indent;
DumpFullType(DerivedTy->getBaseType().resolve(EmptyMap));
}
return;
case llvm::dwarf::DW_TAG_subroutine_type:
std::abort();
return;
}
} else if (auto *CompositeTy = llvm::dyn_cast<llvm::DICompositeType>(Ty)) {
switch (CompositeTy->getTag()) {
default:
assert(!"Unhandled DICompositeType");
std::abort();
return;
case llvm::dwarf::DW_TAG_array_type:
DumpArrayType(CompositeTy);
return;
case llvm::dwarf::DW_TAG_structure_type:
case llvm::dwarf::DW_TAG_class_type:
DumpStructType(CompositeTy);
return;
case llvm::dwarf::DW_TAG_enumeration_type:
// enum base type is int:
std::abort();
return;
}
} else if (auto *BasicTy = llvm::dyn_cast<llvm::DIBasicType>(Ty)) {
Log("%d: %s", BasicTy->getOffsetInBits(), BasicTy->getName().str().c_str());
return;
} else {
std::abort();
}
}
static unsigned NumArrayElements(llvm::DICompositeType const *Array) {
if (Array->getElements().size() == 0) {
return 0;
}
unsigned NumElements = 1;
for (llvm::DINode *N : Array->getElements()) {
if (auto *Subrange = llvm::dyn_cast<llvm::DISubrange>(N)) {
NumElements *= Subrange->getCount();
} else {
assert(!"Unhandled array element");
return 0;
}
}
return NumElements;
}
void DumpArrayType(llvm::DICompositeType const *Ty) {
unsigned NumElements = NumArrayElements(Ty);
Log("Array %s: size: %d", Ty->getName().str().c_str(), NumElements);
if (NumElements == 0) {
std::abort();
return;
}
const llvm::DITypeIdentifierMap EmptyMap;
llvm::DIType *ElementTy = Ty->getBaseType().resolve(EmptyMap);
ScopedIndenter indent;
DumpFullType(ElementTy);
}
void DumpStructType(llvm::DICompositeType const *Ty) {
Log("Struct %s", Ty->getName().str().c_str());
ScopedIndenter indent;
auto Elements = Ty->getElements();
if (Elements.begin() == Elements.end()) {
Log("Resource member: size %d", Ty->getSizeInBits());
return;
}
for (auto *Element : Elements) {
switch (Element->getTag()) {
case llvm::dwarf::DW_TAG_member: {
if (auto *Member = llvm::dyn_cast<llvm::DIDerivedType>(Element)) {
DumpFullType(Member);
break;
}
assert(!"member is not a Member");
std::abort();
return;
}
case llvm::dwarf::DW_TAG_subprogram: {
if (auto *SubProgram = llvm::dyn_cast<llvm::DISubprogram>(Element)) {
Log("Member function %s", SubProgram->getName().str().c_str());
continue;
}
assert(!"DISubprogram not understood");
std::abort();
return;
}
case llvm::dwarf::DW_TAG_inheritance: {
if (auto *Member = llvm::dyn_cast<llvm::DIDerivedType>(Element)) {
DumpFullType(Member);
} else {
std::abort();
}
continue;
}
default:
assert(!"Unhandled field type in DIStructType");
std::abort();
}
}
}
#endif
} // namespace PIXPassHelpers