304 lines · cpp
1//===- DXILPrettyPrinter.cpp - Print resources for textual DXIL -----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "DXILPrettyPrinter.h"10#include "DirectX.h"11#include "llvm/ADT/StringRef.h"12#include "llvm/Analysis/DXILResource.h"13#include "llvm/IR/PassManager.h"14#include "llvm/InitializePasses.h"15#include "llvm/Pass.h"16#include "llvm/Support/FormatAdapters.h"17#include "llvm/Support/FormatVariadic.h"18#include "llvm/Support/raw_ostream.h"19 20using namespace llvm;21 22static StringRef getRCName(dxil::ResourceClass RC) {23 switch (RC) {24 case dxil::ResourceClass::SRV:25 return "texture";26 case dxil::ResourceClass::UAV:27 return "UAV";28 case dxil::ResourceClass::CBuffer:29 return "cbuffer";30 case dxil::ResourceClass::Sampler:31 return "sampler";32 }33 llvm_unreachable("covered switch");34}35 36static StringRef getRCPrefix(dxil::ResourceClass RC) {37 switch (RC) {38 case dxil::ResourceClass::SRV:39 return "t";40 case dxil::ResourceClass::UAV:41 return "u";42 case dxil::ResourceClass::CBuffer:43 return "cb";44 case dxil::ResourceClass::Sampler:45 return "s";46 }47 llvm_unreachable("covered switch");48}49 50static StringRef getFormatName(const dxil::ResourceTypeInfo &RI) {51 if (RI.isTyped()) {52 switch (RI.getTyped().DXILStorageTy) {53 case dxil::ElementType::I1:54 return "i1";55 case dxil::ElementType::I16:56 return "i16";57 case dxil::ElementType::U16:58 return "u16";59 case dxil::ElementType::I32:60 return "i32";61 case dxil::ElementType::U32:62 return "u32";63 case dxil::ElementType::I64:64 return "i64";65 case dxil::ElementType::U64:66 return "u64";67 case dxil::ElementType::F16:68 return "f16";69 case dxil::ElementType::F32:70 return "f32";71 case dxil::ElementType::F64:72 return "f64";73 case dxil::ElementType::SNormF16:74 return "snorm_f16";75 case dxil::ElementType::UNormF16:76 return "unorm_f16";77 case dxil::ElementType::SNormF32:78 return "snorm_f32";79 case dxil::ElementType::UNormF32:80 return "unorm_f32";81 case dxil::ElementType::SNormF64:82 return "snorm_f64";83 case dxil::ElementType::UNormF64:84 return "unorm_f64";85 case dxil::ElementType::PackedS8x32:86 return "p32i8";87 case dxil::ElementType::PackedU8x32:88 return "p32u8";89 case dxil::ElementType::Invalid:90 llvm_unreachable("Invalid ElementType");91 }92 llvm_unreachable("Unhandled ElementType");93 } else if (RI.isStruct())94 return "struct";95 else if (RI.isCBuffer() || RI.isSampler())96 return "NA";97 return "byte";98}99 100static StringRef getTextureDimName(dxil::ResourceKind RK) {101 switch (RK) {102 case dxil::ResourceKind::Texture1D:103 return "1d";104 case dxil::ResourceKind::Texture2D:105 return "2d";106 case dxil::ResourceKind::Texture3D:107 return "3d";108 case dxil::ResourceKind::TextureCube:109 return "cube";110 case dxil::ResourceKind::Texture1DArray:111 return "1darray";112 case dxil::ResourceKind::Texture2DArray:113 return "2darray";114 case dxil::ResourceKind::TextureCubeArray:115 return "cubearray";116 case dxil::ResourceKind::TBuffer:117 return "tbuffer";118 case dxil::ResourceKind::FeedbackTexture2D:119 return "fbtex2d";120 case dxil::ResourceKind::FeedbackTexture2DArray:121 return "fbtex2darray";122 case dxil::ResourceKind::Texture2DMS:123 return "2dMS";124 case dxil::ResourceKind::Texture2DMSArray:125 return "2darrayMS";126 case dxil::ResourceKind::Invalid:127 case dxil::ResourceKind::NumEntries:128 case dxil::ResourceKind::CBuffer:129 case dxil::ResourceKind::RawBuffer:130 case dxil::ResourceKind::Sampler:131 case dxil::ResourceKind::StructuredBuffer:132 case dxil::ResourceKind::TypedBuffer:133 case dxil::ResourceKind::RTAccelerationStructure:134 llvm_unreachable("Invalid ResourceKind for texture");135 }136 llvm_unreachable("Unhandled ResourceKind");137}138 139namespace {140struct FormatResourceDimension141 : public llvm::FormatAdapter<const dxil::ResourceTypeInfo &> {142 FormatResourceDimension(const dxil::ResourceTypeInfo &RI, bool HasCounter)143 : llvm::FormatAdapter<const dxil::ResourceTypeInfo &>(RI),144 HasCounter(HasCounter) {}145 146 bool HasCounter;147 148 void format(llvm::raw_ostream &OS, StringRef Style) override {149 dxil::ResourceKind RK = Item.getResourceKind();150 switch (RK) {151 default: {152 OS << getTextureDimName(RK);153 if (Item.isMultiSample())154 OS << Item.getMultiSampleCount();155 break;156 }157 case dxil::ResourceKind::RawBuffer:158 case dxil::ResourceKind::StructuredBuffer:159 if (!Item.isUAV())160 OS << "r/o";161 else if (HasCounter)162 OS << "r/w+cnt";163 else164 OS << "r/w";165 break;166 case dxil::ResourceKind::TypedBuffer:167 OS << "buf";168 break;169 case dxil::ResourceKind::CBuffer:170 OS << "NA";171 break;172 case dxil::ResourceKind::RTAccelerationStructure:173 // TODO: dxc would print "ras" here. Can/should this happen?174 llvm_unreachable("RTAccelerationStructure printing is not implemented");175 }176 }177};178 179struct FormatBindingID180 : public llvm::FormatAdapter<const dxil::ResourceInfo &> {181 dxil::ResourceClass RC;182 183 explicit FormatBindingID(const dxil::ResourceInfo &RI,184 const dxil::ResourceTypeInfo &RTI)185 : llvm::FormatAdapter<const dxil::ResourceInfo &>(RI),186 RC(RTI.getResourceClass()) {}187 188 void format(llvm::raw_ostream &OS, StringRef Style) override {189 OS << getRCPrefix(RC).upper() << Item.getBinding().RecordID;190 }191};192 193struct FormatBindingLocation194 : public llvm::FormatAdapter<const dxil::ResourceInfo &> {195 dxil::ResourceClass RC;196 197 explicit FormatBindingLocation(const dxil::ResourceInfo &RI,198 const dxil::ResourceTypeInfo &RTI)199 : llvm::FormatAdapter<const dxil::ResourceInfo &>(RI),200 RC(RTI.getResourceClass()) {}201 202 void format(llvm::raw_ostream &OS, StringRef Style) override {203 const auto &Binding = Item.getBinding();204 OS << getRCPrefix(RC) << Binding.LowerBound;205 if (Binding.Space)206 OS << ",space" << Binding.Space;207 }208};209 210struct FormatBindingSize211 : public llvm::FormatAdapter<const dxil::ResourceInfo &> {212 explicit FormatBindingSize(const dxil::ResourceInfo &RI)213 : llvm::FormatAdapter<const dxil::ResourceInfo &>(RI) {}214 215 void format(llvm::raw_ostream &OS, StringRef Style) override {216 uint32_t Size = Item.getBinding().Size;217 if (Size == std::numeric_limits<uint32_t>::max())218 OS << "unbounded";219 else220 OS << Size;221 }222};223 224} // namespace225 226static void prettyPrintResources(raw_ostream &OS, const DXILResourceMap &DRM,227 DXILResourceTypeMap &DRTM) {228 // Column widths are arbitrary but match the widths DXC uses.229 OS << ";\n; Resource Bindings:\n;\n";230 OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,9}\n", "Name",231 "Type", "Format", "Dim", "ID", "HLSL Bind", "Count");232 OS << formatv(233 "; {0,-+30} {1,-+10} {2,-+7} {3,-+11} {4,-+7} {5,-+14} {6,-+9}\n", "", "",234 "", "", "", "", "");235 236 // TODO: Do we want to sort these by binding or something like that?237 for (const dxil::ResourceInfo &RI : DRM) {238 const dxil::ResourceTypeInfo &RTI = DRTM[RI.getHandleTy()];239 240 dxil::ResourceClass RC = RTI.getResourceClass();241 StringRef Name(RI.getName());242 StringRef Type(getRCName(RC));243 StringRef Format(getFormatName(RTI));244 FormatResourceDimension Dim(RTI, RI.hasCounter());245 FormatBindingID ID(RI, RTI);246 FormatBindingLocation Bind(RI, RTI);247 FormatBindingSize Count(RI);248 OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,9}\n", Name,249 Type, Format, Dim, ID, Bind, Count);250 }251 OS << ";\n";252}253 254PreservedAnalyses DXILPrettyPrinterPass::run(Module &M,255 ModuleAnalysisManager &MAM) {256 const DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);257 DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M);258 prettyPrintResources(OS, DRM, DRTM);259 return PreservedAnalyses::all();260}261 262namespace {263class DXILPrettyPrinterLegacy : public llvm::ModulePass {264 raw_ostream &OS; // raw_ostream to print to.265 266public:267 static char ID;268 269 explicit DXILPrettyPrinterLegacy(raw_ostream &O) : ModulePass(ID), OS(O) {}270 271 StringRef getPassName() const override {272 return "DXIL Metadata Pretty Printer";273 }274 275 bool runOnModule(Module &M) override;276 void getAnalysisUsage(AnalysisUsage &AU) const override {277 AU.setPreservesAll();278 AU.addRequired<DXILResourceTypeWrapperPass>();279 AU.addRequired<DXILResourceWrapperPass>();280 }281};282} // namespace283 284char DXILPrettyPrinterLegacy::ID = 0;285INITIALIZE_PASS_BEGIN(DXILPrettyPrinterLegacy, "dxil-pretty-printer",286 "DXIL Metadata Pretty Printer", true, true)287INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)288INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)289INITIALIZE_PASS_END(DXILPrettyPrinterLegacy, "dxil-pretty-printer",290 "DXIL Metadata Pretty Printer", true, true)291 292bool DXILPrettyPrinterLegacy::runOnModule(Module &M) {293 const DXILResourceMap &DRM =294 getAnalysis<DXILResourceWrapperPass>().getResourceMap();295 DXILResourceTypeMap &DRTM =296 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();297 prettyPrintResources(OS, DRM, DRTM);298 return false;299}300 301ModulePass *llvm::createDXILPrettyPrinterLegacyPass(raw_ostream &OS) {302 return new DXILPrettyPrinterLegacy(OS);303}304