xref: /llvm-project/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp (revision 3eca15cbb9888a992749ddd24f0fb666dad733bf)
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