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