llvm-project/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp
Justin Bogner 3eca15cbb9
[DirectX] Split resource info into type and binding info. NFC (#119773)
This splits the DXILResourceAnalysis pass into TypeAnalysis and
BindingAnalysis passes. The type analysis pass is made immutable and
populated lazily so that it can be used earlier in the pipeline without
needing to carefully maintain the invariants of the binding analysis.

Fixes #118400
2024-12-18 09:02:28 -07:00

320 lines
10 KiB
C++

//===- DXILPrettyPrinter.cpp - Print resources for textual DXIL -----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "DXILPrettyPrinter.h"
#include "DXILResourceAnalysis.h"
#include "DirectX.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/DXILResource.h"
#include "llvm/IR/PassManager.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
static StringRef getRCName(dxil::ResourceClass RC) {
switch (RC) {
case dxil::ResourceClass::SRV:
return "SRV";
case dxil::ResourceClass::UAV:
return "UAV";
case dxil::ResourceClass::CBuffer:
return "cbuffer";
case dxil::ResourceClass::Sampler:
return "sampler";
}
llvm_unreachable("covered switch");
}
static StringRef getRCPrefix(dxil::ResourceClass RC) {
switch (RC) {
case dxil::ResourceClass::SRV:
return "t";
case dxil::ResourceClass::UAV:
return "u";
case dxil::ResourceClass::CBuffer:
return "cb";
case dxil::ResourceClass::Sampler:
return "s";
}
llvm_unreachable("covered switch");
}
static StringRef getFormatName(const dxil::ResourceTypeInfo &RI) {
if (RI.isTyped()) {
switch (RI.getTyped().ElementTy) {
case dxil::ElementType::I1:
return "i1";
case dxil::ElementType::I16:
return "i16";
case dxil::ElementType::U16:
return "u16";
case dxil::ElementType::I32:
return "i32";
case dxil::ElementType::U32:
return "u32";
case dxil::ElementType::I64:
return "i64";
case dxil::ElementType::U64:
return "u64";
case dxil::ElementType::F16:
return "f16";
case dxil::ElementType::F32:
return "f32";
case dxil::ElementType::F64:
return "f64";
case dxil::ElementType::SNormF16:
return "snorm_f16";
case dxil::ElementType::UNormF16:
return "unorm_f16";
case dxil::ElementType::SNormF32:
return "snorm_f32";
case dxil::ElementType::UNormF32:
return "unorm_f32";
case dxil::ElementType::SNormF64:
return "snorm_f64";
case dxil::ElementType::UNormF64:
return "unorm_f64";
case dxil::ElementType::PackedS8x32:
return "p32i8";
case dxil::ElementType::PackedU8x32:
return "p32u8";
case dxil::ElementType::Invalid:
llvm_unreachable("Invalid ElementType");
}
llvm_unreachable("Unhandled ElementType");
} else if (RI.isStruct())
return "struct";
else if (RI.isCBuffer() || RI.isSampler())
return "NA";
return "byte";
}
static StringRef getTextureDimName(dxil::ResourceKind RK) {
switch (RK) {
case dxil::ResourceKind::Texture1D:
return "1d";
case dxil::ResourceKind::Texture2D:
return "2d";
case dxil::ResourceKind::Texture3D:
return "3d";
case dxil::ResourceKind::TextureCube:
return "cube";
case dxil::ResourceKind::Texture1DArray:
return "1darray";
case dxil::ResourceKind::Texture2DArray:
return "2darray";
case dxil::ResourceKind::TextureCubeArray:
return "cubearray";
case dxil::ResourceKind::TBuffer:
return "tbuffer";
case dxil::ResourceKind::FeedbackTexture2D:
return "fbtex2d";
case dxil::ResourceKind::FeedbackTexture2DArray:
return "fbtex2darray";
case dxil::ResourceKind::Texture2DMS:
return "2dMS";
case dxil::ResourceKind::Texture2DMSArray:
return "2darrayMS";
case dxil::ResourceKind::Invalid:
case dxil::ResourceKind::NumEntries:
case dxil::ResourceKind::CBuffer:
case dxil::ResourceKind::RawBuffer:
case dxil::ResourceKind::Sampler:
case dxil::ResourceKind::StructuredBuffer:
case dxil::ResourceKind::TypedBuffer:
case dxil::ResourceKind::RTAccelerationStructure:
llvm_unreachable("Invalid ResourceKind for texture");
}
llvm_unreachable("Unhandled ResourceKind");
}
namespace {
struct FormatResourceDimension
: public llvm::FormatAdapter<const dxil::ResourceTypeInfo &> {
explicit FormatResourceDimension(const dxil::ResourceTypeInfo &RI)
: llvm::FormatAdapter<const dxil::ResourceTypeInfo &>(RI) {}
void format(llvm::raw_ostream &OS, StringRef Style) override {
dxil::ResourceKind RK = Item.getResourceKind();
switch (RK) {
default: {
OS << getTextureDimName(RK);
if (Item.isMultiSample())
OS << Item.getMultiSampleCount();
break;
}
case dxil::ResourceKind::RawBuffer:
case dxil::ResourceKind::StructuredBuffer:
if (!Item.isUAV())
OS << "r/o";
else if (Item.getUAV().HasCounter)
OS << "r/w+cnt";
else
OS << "r/w";
break;
case dxil::ResourceKind::TypedBuffer:
OS << "buf";
break;
case dxil::ResourceKind::RTAccelerationStructure:
// TODO: dxc would print "ras" here. Can/should this happen?
llvm_unreachable("RTAccelerationStructure printing is not implemented");
}
}
};
struct FormatBindingID
: public llvm::FormatAdapter<const dxil::ResourceBindingInfo &> {
dxil::ResourceClass RC;
explicit FormatBindingID(const dxil::ResourceBindingInfo &RBI,
const dxil::ResourceTypeInfo &RTI)
: llvm::FormatAdapter<const dxil::ResourceBindingInfo &>(RBI),
RC(RTI.getResourceClass()) {}
void format(llvm::raw_ostream &OS, StringRef Style) override {
OS << getRCPrefix(RC).upper() << Item.getBinding().RecordID;
}
};
struct FormatBindingLocation
: public llvm::FormatAdapter<const dxil::ResourceBindingInfo &> {
dxil::ResourceClass RC;
explicit FormatBindingLocation(const dxil::ResourceBindingInfo &RBI,
const dxil::ResourceTypeInfo &RTI)
: llvm::FormatAdapter<const dxil::ResourceBindingInfo &>(RBI),
RC(RTI.getResourceClass()) {}
void format(llvm::raw_ostream &OS, StringRef Style) override {
const auto &Binding = Item.getBinding();
OS << getRCPrefix(RC) << Binding.LowerBound;
if (Binding.Space)
OS << ",space" << Binding.Space;
}
};
struct FormatBindingSize
: public llvm::FormatAdapter<const dxil::ResourceBindingInfo &> {
explicit FormatBindingSize(const dxil::ResourceBindingInfo &RI)
: llvm::FormatAdapter<const dxil::ResourceBindingInfo &>(RI) {}
void format(llvm::raw_ostream &OS, StringRef Style) override {
uint32_t Size = Item.getBinding().Size;
if (Size == std::numeric_limits<uint32_t>::max())
OS << "unbounded";
else
OS << Size;
}
};
} // namespace
static void prettyPrintResources(raw_ostream &OS, const DXILBindingMap &DBM,
DXILResourceTypeMap &DRTM,
const dxil::Resources &MDResources) {
// Column widths are arbitrary but match the widths DXC uses.
OS << ";\n; Resource Bindings:\n;\n";
OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,9}\n", "Name",
"Type", "Format", "Dim", "ID", "HLSL Bind", "Count");
OS << formatv(
"; {0,-+30} {1,-+10} {2,-+7} {3,-+11} {4,-+7} {5,-+14} {6,-+9}\n", "", "",
"", "", "", "", "");
// TODO: Do we want to sort these by binding or something like that?
for (const dxil::ResourceBindingInfo &RBI : DBM) {
const dxil::ResourceTypeInfo &RTI = DRTM[RBI.getHandleTy()];
dxil::ResourceClass RC = RTI.getResourceClass();
assert((RC != dxil::ResourceClass::CBuffer || !MDResources.hasCBuffers()) &&
"Old and new cbuffer representations can't coexist");
assert((RC != dxil::ResourceClass::UAV || !MDResources.hasUAVs()) &&
"Old and new UAV representations can't coexist");
StringRef Name(RBI.getName());
StringRef Type(getRCName(RC));
StringRef Format(getFormatName(RTI));
FormatResourceDimension Dim(RTI);
FormatBindingID ID(RBI, RTI);
FormatBindingLocation Bind(RBI, RTI);
FormatBindingSize Count(RBI);
OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,9}\n", Name,
Type, Format, Dim, ID, Bind, Count);
}
if (MDResources.hasCBuffers())
MDResources.printCBuffers(OS);
if (MDResources.hasUAVs())
MDResources.printUAVs(OS);
OS << ";\n";
}
PreservedAnalyses DXILPrettyPrinterPass::run(Module &M,
ModuleAnalysisManager &MAM) {
const DXILBindingMap &DBM = MAM.getResult<DXILResourceBindingAnalysis>(M);
DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M);
const dxil::Resources &MDResources = MAM.getResult<DXILResourceMDAnalysis>(M);
prettyPrintResources(OS, DBM, DRTM, MDResources);
return PreservedAnalyses::all();
}
namespace {
class DXILPrettyPrinterLegacy : public llvm::ModulePass {
raw_ostream &OS; // raw_ostream to print to.
public:
static char ID;
DXILPrettyPrinterLegacy() : ModulePass(ID), OS(dbgs()) {
initializeDXILPrettyPrinterLegacyPass(*PassRegistry::getPassRegistry());
}
explicit DXILPrettyPrinterLegacy(raw_ostream &O) : ModulePass(ID), OS(O) {
initializeDXILPrettyPrinterLegacyPass(*PassRegistry::getPassRegistry());
}
StringRef getPassName() const override {
return "DXIL Metadata Pretty Printer";
}
bool runOnModule(Module &M) override;
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
AU.addRequired<DXILResourceTypeWrapperPass>();
AU.addRequired<DXILResourceBindingWrapperPass>();
AU.addRequired<DXILResourceMDWrapper>();
}
};
} // namespace
char DXILPrettyPrinterLegacy::ID = 0;
INITIALIZE_PASS_BEGIN(DXILPrettyPrinterLegacy, "dxil-pretty-printer",
"DXIL Metadata Pretty Printer", true, true)
INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DXILResourceMDWrapper)
INITIALIZE_PASS_END(DXILPrettyPrinterLegacy, "dxil-pretty-printer",
"DXIL Metadata Pretty Printer", true, true)
bool DXILPrettyPrinterLegacy::runOnModule(Module &M) {
const DXILBindingMap &DBM =
getAnalysis<DXILResourceBindingWrapperPass>().getBindingMap();
DXILResourceTypeMap &DRTM =
getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
dxil::Resources &Res = getAnalysis<DXILResourceMDWrapper>().getDXILResource();
prettyPrintResources(OS, DBM, DRTM, Res);
return false;
}
ModulePass *llvm::createDXILPrettyPrinterLegacyPass(raw_ostream &OS) {
return new DXILPrettyPrinterLegacy(OS);
}