xref: /freebsd/contrib/llvm-project/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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 "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 
20 using namespace llvm;
21 
22 static 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 
36 static 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 
50 static StringRef getFormatName(const dxil::ResourceTypeInfo &RI) {
51   if (RI.isTyped()) {
52     switch (RI.getTyped().ElementTy) {
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 
100 static 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 
139 namespace {
140 struct FormatResourceDimension
141     : 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       else
164         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 
179 struct FormatBindingID
180     : 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 
193 struct FormatBindingLocation
194     : 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 
210 struct FormatBindingSize
211     : 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     else
220       OS << Size;
221   }
222 };
223 
224 } // namespace
225 
226 static 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 
254 PreservedAnalyses 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 
262 namespace {
263 class DXILPrettyPrinterLegacy : public llvm::ModulePass {
264   raw_ostream &OS; // raw_ostream to print to.
265 
266 public:
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 } // namespace
283 
284 char DXILPrettyPrinterLegacy::ID = 0;
285 INITIALIZE_PASS_BEGIN(DXILPrettyPrinterLegacy, "dxil-pretty-printer",
286                       "DXIL Metadata Pretty Printer", true, true)
287 INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
288 INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)
289 INITIALIZE_PASS_END(DXILPrettyPrinterLegacy, "dxil-pretty-printer",
290                     "DXIL Metadata Pretty Printer", true, true)
291 
292 bool 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 
301 ModulePass *llvm::createDXILPrettyPrinterLegacyPass(raw_ostream &OS) {
302   return new DXILPrettyPrinterLegacy(OS);
303 }
304