181ee3855SJustin Bogner //===- DXILPrettyPrinter.cpp - Print resources for textual DXIL -----------===// 2e530a118SChris Bieneman // 3e530a118SChris Bieneman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e530a118SChris Bieneman // See https://llvm.org/LICENSE.txt for license information. 5e530a118SChris Bieneman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e530a118SChris Bieneman // 7e530a118SChris Bieneman //===----------------------------------------------------------------------===// 8e530a118SChris Bieneman 981ee3855SJustin Bogner #include "DXILPrettyPrinter.h" 10e530a118SChris Bieneman #include "DXILResourceAnalysis.h" 11e530a118SChris Bieneman #include "DirectX.h" 12e530a118SChris Bieneman #include "llvm/ADT/StringRef.h" 1387157ab0SJustin Bogner #include "llvm/Analysis/DXILResource.h" 14e530a118SChris Bieneman #include "llvm/IR/PassManager.h" 1587157ab0SJustin Bogner #include "llvm/InitializePasses.h" 16e530a118SChris Bieneman #include "llvm/Pass.h" 1787157ab0SJustin Bogner #include "llvm/Support/FormatAdapters.h" 1858eec851SJustin Bogner #include "llvm/Support/FormatVariadic.h" 19e530a118SChris Bieneman #include "llvm/Support/raw_ostream.h" 20e530a118SChris Bieneman 21e530a118SChris Bieneman using namespace llvm; 22e530a118SChris Bieneman 2387157ab0SJustin Bogner static StringRef getRCName(dxil::ResourceClass RC) { 2487157ab0SJustin Bogner switch (RC) { 2587157ab0SJustin Bogner case dxil::ResourceClass::SRV: 2687157ab0SJustin Bogner return "SRV"; 2787157ab0SJustin Bogner case dxil::ResourceClass::UAV: 2887157ab0SJustin Bogner return "UAV"; 2987157ab0SJustin Bogner case dxil::ResourceClass::CBuffer: 3087157ab0SJustin Bogner return "cbuffer"; 3187157ab0SJustin Bogner case dxil::ResourceClass::Sampler: 3287157ab0SJustin Bogner return "sampler"; 3387157ab0SJustin Bogner } 3487157ab0SJustin Bogner llvm_unreachable("covered switch"); 3587157ab0SJustin Bogner } 3687157ab0SJustin Bogner 3787157ab0SJustin Bogner static StringRef getRCPrefix(dxil::ResourceClass RC) { 3887157ab0SJustin Bogner switch (RC) { 3987157ab0SJustin Bogner case dxil::ResourceClass::SRV: 4087157ab0SJustin Bogner return "t"; 4187157ab0SJustin Bogner case dxil::ResourceClass::UAV: 4287157ab0SJustin Bogner return "u"; 4387157ab0SJustin Bogner case dxil::ResourceClass::CBuffer: 4487157ab0SJustin Bogner return "cb"; 4587157ab0SJustin Bogner case dxil::ResourceClass::Sampler: 4687157ab0SJustin Bogner return "s"; 4787157ab0SJustin Bogner } 4824b6b824SDamyan Pepper llvm_unreachable("covered switch"); 4987157ab0SJustin Bogner } 5087157ab0SJustin Bogner 51*3eca15cbSJustin Bogner static StringRef getFormatName(const dxil::ResourceTypeInfo &RI) { 5287157ab0SJustin Bogner if (RI.isTyped()) { 5387157ab0SJustin Bogner switch (RI.getTyped().ElementTy) { 5487157ab0SJustin Bogner case dxil::ElementType::I1: 5587157ab0SJustin Bogner return "i1"; 5687157ab0SJustin Bogner case dxil::ElementType::I16: 5787157ab0SJustin Bogner return "i16"; 5887157ab0SJustin Bogner case dxil::ElementType::U16: 5987157ab0SJustin Bogner return "u16"; 6087157ab0SJustin Bogner case dxil::ElementType::I32: 6187157ab0SJustin Bogner return "i32"; 6287157ab0SJustin Bogner case dxil::ElementType::U32: 6387157ab0SJustin Bogner return "u32"; 6487157ab0SJustin Bogner case dxil::ElementType::I64: 6587157ab0SJustin Bogner return "i64"; 6687157ab0SJustin Bogner case dxil::ElementType::U64: 6787157ab0SJustin Bogner return "u64"; 6887157ab0SJustin Bogner case dxil::ElementType::F16: 6987157ab0SJustin Bogner return "f16"; 7087157ab0SJustin Bogner case dxil::ElementType::F32: 7187157ab0SJustin Bogner return "f32"; 7287157ab0SJustin Bogner case dxil::ElementType::F64: 7387157ab0SJustin Bogner return "f64"; 7487157ab0SJustin Bogner case dxil::ElementType::SNormF16: 7587157ab0SJustin Bogner return "snorm_f16"; 7687157ab0SJustin Bogner case dxil::ElementType::UNormF16: 7787157ab0SJustin Bogner return "unorm_f16"; 7887157ab0SJustin Bogner case dxil::ElementType::SNormF32: 7987157ab0SJustin Bogner return "snorm_f32"; 8087157ab0SJustin Bogner case dxil::ElementType::UNormF32: 8187157ab0SJustin Bogner return "unorm_f32"; 8287157ab0SJustin Bogner case dxil::ElementType::SNormF64: 8387157ab0SJustin Bogner return "snorm_f64"; 8487157ab0SJustin Bogner case dxil::ElementType::UNormF64: 8587157ab0SJustin Bogner return "unorm_f64"; 8687157ab0SJustin Bogner case dxil::ElementType::PackedS8x32: 8787157ab0SJustin Bogner return "p32i8"; 8887157ab0SJustin Bogner case dxil::ElementType::PackedU8x32: 8987157ab0SJustin Bogner return "p32u8"; 9087157ab0SJustin Bogner case dxil::ElementType::Invalid: 9187157ab0SJustin Bogner llvm_unreachable("Invalid ElementType"); 9287157ab0SJustin Bogner } 9387157ab0SJustin Bogner llvm_unreachable("Unhandled ElementType"); 9487157ab0SJustin Bogner } else if (RI.isStruct()) 9587157ab0SJustin Bogner return "struct"; 9687157ab0SJustin Bogner else if (RI.isCBuffer() || RI.isSampler()) 9787157ab0SJustin Bogner return "NA"; 9887157ab0SJustin Bogner return "byte"; 9987157ab0SJustin Bogner } 10087157ab0SJustin Bogner 10187157ab0SJustin Bogner static StringRef getTextureDimName(dxil::ResourceKind RK) { 10287157ab0SJustin Bogner switch (RK) { 10387157ab0SJustin Bogner case dxil::ResourceKind::Texture1D: 10487157ab0SJustin Bogner return "1d"; 10587157ab0SJustin Bogner case dxil::ResourceKind::Texture2D: 10687157ab0SJustin Bogner return "2d"; 10787157ab0SJustin Bogner case dxil::ResourceKind::Texture3D: 10887157ab0SJustin Bogner return "3d"; 10987157ab0SJustin Bogner case dxil::ResourceKind::TextureCube: 11087157ab0SJustin Bogner return "cube"; 11187157ab0SJustin Bogner case dxil::ResourceKind::Texture1DArray: 11287157ab0SJustin Bogner return "1darray"; 11387157ab0SJustin Bogner case dxil::ResourceKind::Texture2DArray: 11487157ab0SJustin Bogner return "2darray"; 11587157ab0SJustin Bogner case dxil::ResourceKind::TextureCubeArray: 11687157ab0SJustin Bogner return "cubearray"; 11787157ab0SJustin Bogner case dxil::ResourceKind::TBuffer: 11887157ab0SJustin Bogner return "tbuffer"; 11987157ab0SJustin Bogner case dxil::ResourceKind::FeedbackTexture2D: 12087157ab0SJustin Bogner return "fbtex2d"; 12187157ab0SJustin Bogner case dxil::ResourceKind::FeedbackTexture2DArray: 12287157ab0SJustin Bogner return "fbtex2darray"; 12387157ab0SJustin Bogner case dxil::ResourceKind::Texture2DMS: 12487157ab0SJustin Bogner return "2dMS"; 12587157ab0SJustin Bogner case dxil::ResourceKind::Texture2DMSArray: 12687157ab0SJustin Bogner return "2darrayMS"; 12787157ab0SJustin Bogner case dxil::ResourceKind::Invalid: 12887157ab0SJustin Bogner case dxil::ResourceKind::NumEntries: 12987157ab0SJustin Bogner case dxil::ResourceKind::CBuffer: 13087157ab0SJustin Bogner case dxil::ResourceKind::RawBuffer: 13187157ab0SJustin Bogner case dxil::ResourceKind::Sampler: 13287157ab0SJustin Bogner case dxil::ResourceKind::StructuredBuffer: 13387157ab0SJustin Bogner case dxil::ResourceKind::TypedBuffer: 13487157ab0SJustin Bogner case dxil::ResourceKind::RTAccelerationStructure: 13587157ab0SJustin Bogner llvm_unreachable("Invalid ResourceKind for texture"); 13687157ab0SJustin Bogner } 13787157ab0SJustin Bogner llvm_unreachable("Unhandled ResourceKind"); 13887157ab0SJustin Bogner } 13987157ab0SJustin Bogner 14087157ab0SJustin Bogner namespace { 14187157ab0SJustin Bogner struct FormatResourceDimension 142*3eca15cbSJustin Bogner : public llvm::FormatAdapter<const dxil::ResourceTypeInfo &> { 143*3eca15cbSJustin Bogner explicit FormatResourceDimension(const dxil::ResourceTypeInfo &RI) 144*3eca15cbSJustin Bogner : llvm::FormatAdapter<const dxil::ResourceTypeInfo &>(RI) {} 14587157ab0SJustin Bogner 14687157ab0SJustin Bogner void format(llvm::raw_ostream &OS, StringRef Style) override { 14787157ab0SJustin Bogner dxil::ResourceKind RK = Item.getResourceKind(); 14887157ab0SJustin Bogner switch (RK) { 14987157ab0SJustin Bogner default: { 15087157ab0SJustin Bogner OS << getTextureDimName(RK); 15187157ab0SJustin Bogner if (Item.isMultiSample()) 152482237e8SJustin Bogner OS << Item.getMultiSampleCount(); 15387157ab0SJustin Bogner break; 15487157ab0SJustin Bogner } 15587157ab0SJustin Bogner case dxil::ResourceKind::RawBuffer: 15687157ab0SJustin Bogner case dxil::ResourceKind::StructuredBuffer: 15787157ab0SJustin Bogner if (!Item.isUAV()) 15887157ab0SJustin Bogner OS << "r/o"; 15987157ab0SJustin Bogner else if (Item.getUAV().HasCounter) 16087157ab0SJustin Bogner OS << "r/w+cnt"; 16187157ab0SJustin Bogner else 16287157ab0SJustin Bogner OS << "r/w"; 16387157ab0SJustin Bogner break; 16487157ab0SJustin Bogner case dxil::ResourceKind::TypedBuffer: 16587157ab0SJustin Bogner OS << "buf"; 16687157ab0SJustin Bogner break; 16787157ab0SJustin Bogner case dxil::ResourceKind::RTAccelerationStructure: 16887157ab0SJustin Bogner // TODO: dxc would print "ras" here. Can/should this happen? 16987157ab0SJustin Bogner llvm_unreachable("RTAccelerationStructure printing is not implemented"); 17087157ab0SJustin Bogner } 17187157ab0SJustin Bogner } 17287157ab0SJustin Bogner }; 17387157ab0SJustin Bogner 17487157ab0SJustin Bogner struct FormatBindingID 175*3eca15cbSJustin Bogner : public llvm::FormatAdapter<const dxil::ResourceBindingInfo &> { 176*3eca15cbSJustin Bogner dxil::ResourceClass RC; 177*3eca15cbSJustin Bogner 178*3eca15cbSJustin Bogner explicit FormatBindingID(const dxil::ResourceBindingInfo &RBI, 179*3eca15cbSJustin Bogner const dxil::ResourceTypeInfo &RTI) 180*3eca15cbSJustin Bogner : llvm::FormatAdapter<const dxil::ResourceBindingInfo &>(RBI), 181*3eca15cbSJustin Bogner RC(RTI.getResourceClass()) {} 18287157ab0SJustin Bogner 18387157ab0SJustin Bogner void format(llvm::raw_ostream &OS, StringRef Style) override { 184*3eca15cbSJustin Bogner OS << getRCPrefix(RC).upper() << Item.getBinding().RecordID; 18587157ab0SJustin Bogner } 18687157ab0SJustin Bogner }; 18787157ab0SJustin Bogner 18887157ab0SJustin Bogner struct FormatBindingLocation 189*3eca15cbSJustin Bogner : public llvm::FormatAdapter<const dxil::ResourceBindingInfo &> { 190*3eca15cbSJustin Bogner dxil::ResourceClass RC; 191*3eca15cbSJustin Bogner 192*3eca15cbSJustin Bogner explicit FormatBindingLocation(const dxil::ResourceBindingInfo &RBI, 193*3eca15cbSJustin Bogner const dxil::ResourceTypeInfo &RTI) 194*3eca15cbSJustin Bogner : llvm::FormatAdapter<const dxil::ResourceBindingInfo &>(RBI), 195*3eca15cbSJustin Bogner RC(RTI.getResourceClass()) {} 19687157ab0SJustin Bogner 19787157ab0SJustin Bogner void format(llvm::raw_ostream &OS, StringRef Style) override { 19887157ab0SJustin Bogner const auto &Binding = Item.getBinding(); 199*3eca15cbSJustin Bogner OS << getRCPrefix(RC) << Binding.LowerBound; 20087157ab0SJustin Bogner if (Binding.Space) 20187157ab0SJustin Bogner OS << ",space" << Binding.Space; 20287157ab0SJustin Bogner } 20387157ab0SJustin Bogner }; 20487157ab0SJustin Bogner 20587157ab0SJustin Bogner struct FormatBindingSize 206*3eca15cbSJustin Bogner : public llvm::FormatAdapter<const dxil::ResourceBindingInfo &> { 207*3eca15cbSJustin Bogner explicit FormatBindingSize(const dxil::ResourceBindingInfo &RI) 208*3eca15cbSJustin Bogner : llvm::FormatAdapter<const dxil::ResourceBindingInfo &>(RI) {} 20987157ab0SJustin Bogner 21087157ab0SJustin Bogner void format(llvm::raw_ostream &OS, StringRef Style) override { 21187157ab0SJustin Bogner uint32_t Size = Item.getBinding().Size; 21287157ab0SJustin Bogner if (Size == std::numeric_limits<uint32_t>::max()) 21387157ab0SJustin Bogner OS << "unbounded"; 21487157ab0SJustin Bogner else 21587157ab0SJustin Bogner OS << Size; 21687157ab0SJustin Bogner } 21787157ab0SJustin Bogner }; 21887157ab0SJustin Bogner 21987157ab0SJustin Bogner } // namespace 22087157ab0SJustin Bogner 221*3eca15cbSJustin Bogner static void prettyPrintResources(raw_ostream &OS, const DXILBindingMap &DBM, 222*3eca15cbSJustin Bogner DXILResourceTypeMap &DRTM, 22381ee3855SJustin Bogner const dxil::Resources &MDResources) { 22458eec851SJustin Bogner // Column widths are arbitrary but match the widths DXC uses. 22558eec851SJustin Bogner OS << ";\n; Resource Bindings:\n;\n"; 22687157ab0SJustin Bogner OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,9}\n", "Name", 22758eec851SJustin Bogner "Type", "Format", "Dim", "ID", "HLSL Bind", "Count"); 22858eec851SJustin Bogner OS << formatv( 22987157ab0SJustin Bogner "; {0,-+30} {1,-+10} {2,-+7} {3,-+11} {4,-+7} {5,-+14} {6,-+9}\n", "", "", 23087157ab0SJustin Bogner "", "", "", "", ""); 23187157ab0SJustin Bogner 23287157ab0SJustin Bogner // TODO: Do we want to sort these by binding or something like that? 233*3eca15cbSJustin Bogner for (const dxil::ResourceBindingInfo &RBI : DBM) { 234*3eca15cbSJustin Bogner const dxil::ResourceTypeInfo &RTI = DRTM[RBI.getHandleTy()]; 235*3eca15cbSJustin Bogner 236*3eca15cbSJustin Bogner dxil::ResourceClass RC = RTI.getResourceClass(); 23787157ab0SJustin Bogner assert((RC != dxil::ResourceClass::CBuffer || !MDResources.hasCBuffers()) && 23887157ab0SJustin Bogner "Old and new cbuffer representations can't coexist"); 23987157ab0SJustin Bogner assert((RC != dxil::ResourceClass::UAV || !MDResources.hasUAVs()) && 24087157ab0SJustin Bogner "Old and new UAV representations can't coexist"); 24187157ab0SJustin Bogner 242*3eca15cbSJustin Bogner StringRef Name(RBI.getName()); 24387157ab0SJustin Bogner StringRef Type(getRCName(RC)); 244*3eca15cbSJustin Bogner StringRef Format(getFormatName(RTI)); 245*3eca15cbSJustin Bogner FormatResourceDimension Dim(RTI); 246*3eca15cbSJustin Bogner FormatBindingID ID(RBI, RTI); 247*3eca15cbSJustin Bogner FormatBindingLocation Bind(RBI, RTI); 248*3eca15cbSJustin Bogner FormatBindingSize Count(RBI); 24987157ab0SJustin Bogner OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,9}\n", Name, 25087157ab0SJustin Bogner Type, Format, Dim, ID, Bind, Count); 25187157ab0SJustin Bogner } 25258eec851SJustin Bogner 25358eec851SJustin Bogner if (MDResources.hasCBuffers()) 25458eec851SJustin Bogner MDResources.printCBuffers(OS); 25558eec851SJustin Bogner if (MDResources.hasUAVs()) 25658eec851SJustin Bogner MDResources.printUAVs(OS); 25758eec851SJustin Bogner 25858eec851SJustin Bogner OS << ";\n"; 25981ee3855SJustin Bogner } 26081ee3855SJustin Bogner 26181ee3855SJustin Bogner PreservedAnalyses DXILPrettyPrinterPass::run(Module &M, 26281ee3855SJustin Bogner ModuleAnalysisManager &MAM) { 263*3eca15cbSJustin Bogner const DXILBindingMap &DBM = MAM.getResult<DXILResourceBindingAnalysis>(M); 264*3eca15cbSJustin Bogner DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M); 26581ee3855SJustin Bogner const dxil::Resources &MDResources = MAM.getResult<DXILResourceMDAnalysis>(M); 266*3eca15cbSJustin Bogner prettyPrintResources(OS, DBM, DRTM, MDResources); 26781ee3855SJustin Bogner return PreservedAnalyses::all(); 26881ee3855SJustin Bogner } 26981ee3855SJustin Bogner 270e530a118SChris Bieneman namespace { 27181ee3855SJustin Bogner class DXILPrettyPrinterLegacy : public llvm::ModulePass { 272e530a118SChris Bieneman raw_ostream &OS; // raw_ostream to print to. 273e530a118SChris Bieneman 274e530a118SChris Bieneman public: 275e530a118SChris Bieneman static char ID; 27681ee3855SJustin Bogner DXILPrettyPrinterLegacy() : ModulePass(ID), OS(dbgs()) { 27781ee3855SJustin Bogner initializeDXILPrettyPrinterLegacyPass(*PassRegistry::getPassRegistry()); 278e530a118SChris Bieneman } 279e530a118SChris Bieneman 28081ee3855SJustin Bogner explicit DXILPrettyPrinterLegacy(raw_ostream &O) : ModulePass(ID), OS(O) { 28181ee3855SJustin Bogner initializeDXILPrettyPrinterLegacyPass(*PassRegistry::getPassRegistry()); 282e530a118SChris Bieneman } 283e530a118SChris Bieneman 284e530a118SChris Bieneman StringRef getPassName() const override { 285e530a118SChris Bieneman return "DXIL Metadata Pretty Printer"; 286e530a118SChris Bieneman } 287e530a118SChris Bieneman 288e530a118SChris Bieneman bool runOnModule(Module &M) override; 289e530a118SChris Bieneman void getAnalysisUsage(AnalysisUsage &AU) const override { 290e530a118SChris Bieneman AU.setPreservesAll(); 291*3eca15cbSJustin Bogner AU.addRequired<DXILResourceTypeWrapperPass>(); 292*3eca15cbSJustin Bogner AU.addRequired<DXILResourceBindingWrapperPass>(); 2931c5f6cfcSJustin Bogner AU.addRequired<DXILResourceMDWrapper>(); 294e530a118SChris Bieneman } 295e530a118SChris Bieneman }; 296e530a118SChris Bieneman } // namespace 297e530a118SChris Bieneman 29881ee3855SJustin Bogner char DXILPrettyPrinterLegacy::ID = 0; 29981ee3855SJustin Bogner INITIALIZE_PASS_BEGIN(DXILPrettyPrinterLegacy, "dxil-pretty-printer", 300e530a118SChris Bieneman "DXIL Metadata Pretty Printer", true, true) 301*3eca15cbSJustin Bogner INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass) 302*3eca15cbSJustin Bogner INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass) 3031c5f6cfcSJustin Bogner INITIALIZE_PASS_DEPENDENCY(DXILResourceMDWrapper) 30481ee3855SJustin Bogner INITIALIZE_PASS_END(DXILPrettyPrinterLegacy, "dxil-pretty-printer", 305e530a118SChris Bieneman "DXIL Metadata Pretty Printer", true, true) 306e530a118SChris Bieneman 30781ee3855SJustin Bogner bool DXILPrettyPrinterLegacy::runOnModule(Module &M) { 308*3eca15cbSJustin Bogner const DXILBindingMap &DBM = 309*3eca15cbSJustin Bogner getAnalysis<DXILResourceBindingWrapperPass>().getBindingMap(); 310*3eca15cbSJustin Bogner DXILResourceTypeMap &DRTM = 311*3eca15cbSJustin Bogner getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap(); 3121c5f6cfcSJustin Bogner dxil::Resources &Res = getAnalysis<DXILResourceMDWrapper>().getDXILResource(); 313*3eca15cbSJustin Bogner prettyPrintResources(OS, DBM, DRTM, Res); 314e530a118SChris Bieneman return false; 315e530a118SChris Bieneman } 316e530a118SChris Bieneman 31781ee3855SJustin Bogner ModulePass *llvm::createDXILPrettyPrinterLegacyPass(raw_ostream &OS) { 31881ee3855SJustin Bogner return new DXILPrettyPrinterLegacy(OS); 319e530a118SChris Bieneman } 320