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