LLVM 23.0.0git
DXILPrettyPrinter.cpp
Go to the documentation of this file.
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"
12#include "llvm/ADT/StringRef.h"
15#include "llvm/IR/DebugInfo.h"
16#include "llvm/IR/Metadata.h"
17#include "llvm/IR/Module.h"
19#include "llvm/IR/PassManager.h"
21#include "llvm/Pass.h"
26
27using namespace llvm;
28using namespace llvm::dxil;
29
31 switch (RC) {
33 return "texture";
35 return "UAV";
37 return "cbuffer";
39 return "sampler";
40 }
41 llvm_unreachable("covered switch");
42}
43
45 switch (RC) {
47 return "t";
49 return "u";
51 return "cb";
53 return "s";
54 }
55 llvm_unreachable("covered switch");
56}
57
59 if (RI.isTyped()) {
60 switch (RI.getTyped().DXILStorageTy) {
62 return "i1";
64 return "i16";
66 return "u16";
68 return "i32";
70 return "u32";
72 return "i64";
74 return "u64";
76 return "f16";
78 return "f32";
80 return "f64";
82 return "snorm_f16";
84 return "unorm_f16";
86 return "snorm_f32";
88 return "unorm_f32";
90 return "snorm_f64";
92 return "unorm_f64";
94 return "p32i8";
96 return "p32u8";
98 llvm_unreachable("Invalid ElementType");
99 }
100 llvm_unreachable("Unhandled ElementType");
101 } else if (RI.isStruct())
102 return "struct";
103 else if (RI.isCBuffer() || RI.isSampler())
104 return "NA";
105 return "byte";
106}
107
109 switch (RK) {
111 return "1d";
113 return "2d";
115 return "3d";
117 return "cube";
119 return "1darray";
121 return "2darray";
123 return "cubearray";
125 return "tbuffer";
127 return "fbtex2d";
129 return "fbtex2darray";
131 return "2dMS";
133 return "2darrayMS";
142 llvm_unreachable("Invalid ResourceKind for texture");
143 }
144 llvm_unreachable("Unhandled ResourceKind");
145}
146
147namespace {
148struct FormatResourceDimension
149 : public llvm::FormatAdapter<const dxil::ResourceTypeInfo &> {
150 FormatResourceDimension(const dxil::ResourceTypeInfo &RI, bool HasCounter)
151 : llvm::FormatAdapter<const dxil::ResourceTypeInfo &>(RI),
152 HasCounter(HasCounter) {}
153
154 bool HasCounter;
155
156 void format(llvm::raw_ostream &OS, StringRef Style) override {
157 dxil::ResourceKind RK = Item.getResourceKind();
158 switch (RK) {
159 default: {
160 OS << getTextureDimName(RK);
161 if (Item.isMultiSample())
162 OS << Item.getMultiSampleCount();
163 break;
164 }
165 case dxil::ResourceKind::RawBuffer:
166 case dxil::ResourceKind::StructuredBuffer:
167 if (!Item.isUAV())
168 OS << "r/o";
169 else if (HasCounter)
170 OS << "r/w+cnt";
171 else
172 OS << "r/w";
173 break;
174 case dxil::ResourceKind::TypedBuffer:
175 OS << "buf";
176 break;
177 case dxil::ResourceKind::CBuffer:
178 OS << "NA";
179 break;
180 case dxil::ResourceKind::RTAccelerationStructure:
181 // TODO: dxc would print "ras" here. Can/should this happen?
182 llvm_unreachable("RTAccelerationStructure printing is not implemented");
183 }
184 }
185};
186
187struct FormatBindingID
188 : public llvm::FormatAdapter<const dxil::ResourceInfo &> {
190
191 explicit FormatBindingID(const dxil::ResourceInfo &RI,
192 const dxil::ResourceTypeInfo &RTI)
193 : llvm::FormatAdapter<const dxil::ResourceInfo &>(RI),
194 RC(RTI.getResourceClass()) {}
195
196 void format(llvm::raw_ostream &OS, StringRef Style) override {
197 OS << getRCPrefix(RC).upper() << Item.getBinding().RecordID;
198 }
199};
200
201struct FormatBindingLocation
202 : public llvm::FormatAdapter<const dxil::ResourceInfo &> {
204
205 explicit FormatBindingLocation(const dxil::ResourceInfo &RI,
206 const dxil::ResourceTypeInfo &RTI)
207 : llvm::FormatAdapter<const dxil::ResourceInfo &>(RI),
208 RC(RTI.getResourceClass()) {}
209
210 void format(llvm::raw_ostream &OS, StringRef Style) override {
211 const auto &Binding = Item.getBinding();
212 OS << getRCPrefix(RC) << Binding.LowerBound;
213 if (Binding.Space)
214 OS << ",space" << Binding.Space;
215 }
216};
217
218struct FormatBindingSize
219 : public llvm::FormatAdapter<const dxil::ResourceInfo &> {
220 explicit FormatBindingSize(const dxil::ResourceInfo &RI)
221 : llvm::FormatAdapter<const dxil::ResourceInfo &>(RI) {}
222
223 void format(llvm::raw_ostream &OS, StringRef Style) override {
224 uint32_t Size = Item.getBinding().Size;
225 if (Size == 0)
226 OS << "unbounded";
227 else
228 OS << Size;
229 }
230};
231
232} // namespace
233
235 DXILResourceTypeMap &DRTM) {
236 // Column widths are arbitrary but match the widths DXC uses.
237 OS << ";\n; Resource Bindings:\n;\n";
238 OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,9}\n", "Name",
239 "Type", "Format", "Dim", "ID", "HLSL Bind", "Count");
240 OS << formatv(
241 "; {0,-+30} {1,-+10} {2,-+7} {3,-+11} {4,-+7} {5,-+14} {6,-+9}\n", "", "",
242 "", "", "", "", "");
243
244 // TODO: Do we want to sort these by binding or something like that?
245 for (const dxil::ResourceInfo &RI : DRM) {
246 const dxil::ResourceTypeInfo &RTI = DRTM[RI.getHandleTy()];
247
249 StringRef Name(RI.getName());
252 FormatResourceDimension Dim(RTI, RI.hasCounter());
253 FormatBindingID ID(RI, RTI);
254 FormatBindingLocation Bind(RI, RTI);
255 FormatBindingSize Count(RI);
256 OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,9}\n", Name,
257 Type, Format, Dim, ID, Bind, Count);
258 }
259 OS << ";\n";
260}
261
262namespace {
263class DXILAssemblyAnnotationWriter : public llvm::AssemblyAnnotationWriter {
264private:
265 ModuleSlotTracker &MST;
266 AbstractSlotTrackerStorage &STS;
267 const DXILDebugInfoMap &DI;
268
269public:
270 DXILAssemblyAnnotationWriter(ModuleSlotTracker &MST,
271 AbstractSlotTrackerStorage &STS,
272 const DXILDebugInfoMap &DI)
273 : MST(MST), STS(STS), DI(DI) {}
274
275 void emitInstructionAnnot(const Instruction *OrigI,
276 formatted_raw_ostream &os) override {
277 if (const Instruction *I = &DI.getDXILInstruction(*OrigI); I != OrigI) {
278 os << "; DXIL: to be replaced with: ";
279 I->print(os, MST);
280 os << "\n";
281 }
282 }
283
284 void emitMDNodeAnnot(const MDNode *N, formatted_raw_ostream &os) override {
285 if (const Metadata *NewMD = DI.MDReplace.lookup(N)) {
286 if (const auto *NewN = dyn_cast<MDNode>(NewMD))
287 if (STS.getMetadataSlot(NewN) == -1)
288 STS.createMetadataSlot(NewN);
289
290 os << "; DXIL: ";
291 N->printAsOperand(os, MST);
292 os << ": to be replaced by: ";
293 NewMD->printAsOperand(os, MST);
294 os << "\n";
295 return;
296 }
297
298 if (const Metadata *ExtraMD = DI.MDExtra.lookup(N)) {
299 if (const auto *ExtraN = dyn_cast<MDNode>(ExtraMD))
300 if (STS.getMetadataSlot(ExtraN) == -1)
301 STS.createMetadataSlot(ExtraN);
302
303 os << "; DXIL: ";
304 N->printAsOperand(os, MST);
305 os << ": additional data: ";
306 ExtraMD->printAsOperand(os, MST);
307 os << "\n";
308 return;
309 }
310 }
311};
312} // namespace
313
314static void prettyPrint(raw_ostream &OS, Module &M, const DXILResourceMap &DRM,
315 DXILResourceTypeMap &DRTM) {
316 formatted_raw_ostream FOS(OS);
317
318 prettyPrintResources(FOS, DRM, DRTM);
319
321
322 ModuleSlotTracker MST(&M);
323 AbstractSlotTrackerStorage *STS = nullptr;
324 unsigned NextMetadataSlot = 0;
325 MST.setProcessHook(
326 [&](AbstractSlotTrackerStorage *STS_, const Module *, bool) {
327 STS = STS_;
328 NextMetadataSlot = STS->getNextMetadataSlot();
329 });
330 // Force initialisation. ModuleSlotTracker does not have a dedicated function
331 // for this so trigger it through a dummy print.
332 MDNode::get(M.getContext(), {})->print(llvm::nulls(), MST);
333 assert(STS && "Slot tracker storage should have been initialised");
334
335 DXILAssemblyAnnotationWriter DAAW(MST, *STS, DI);
336 M.print(FOS, &DAAW);
337
339 MST.collectMDNodes(MDNodes, NextMetadataSlot, ~0u);
340 std::sort(MDNodes.begin(), MDNodes.end(),
341 [](const std::pair<unsigned, const MDNode *> &A,
342 const std::pair<unsigned, const MDNode *> &B) {
343 return A.first < B.first;
344 });
345 for (auto [_, MDNode] : MDNodes) {
346 DAAW.emitMDNodeAnnot(MDNode, FOS);
347 MDNode->print(FOS, MST);
348 FOS << "\n";
349 }
350}
351
359
360namespace {
361class DXILPrettyPrinterLegacy : public llvm::ModulePass {
362 raw_ostream &OS; // raw_ostream to print to.
363
364public:
365 static char ID;
366
367 explicit DXILPrettyPrinterLegacy(raw_ostream &O) : ModulePass(ID), OS(O) {}
368
369 StringRef getPassName() const override { return "DXIL Pretty Printer"; }
370
371 bool runOnModule(Module &M) override;
372 void getAnalysisUsage(AnalysisUsage &AU) const override {
373 AU.addRequired<DXILResourceTypeWrapperPass>();
374 AU.addRequired<DXILResourceWrapperPass>();
375 }
376};
377} // namespace
378
379char DXILPrettyPrinterLegacy::ID = 0;
380INITIALIZE_PASS_BEGIN(DXILPrettyPrinterLegacy, "dxil-pretty-printer",
381 "DXIL Pretty Printer", true, true)
384INITIALIZE_PASS_END(DXILPrettyPrinterLegacy, "dxil-pretty-printer",
385 "DXIL Pretty Printer", true, true)
386
387bool DXILPrettyPrinterLegacy::runOnModule(Module &M) {
388 const DXILResourceMap &DRM =
389 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
390 DXILResourceTypeMap &DRTM =
391 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
392 prettyPrint(OS, M, DRM, DRTM);
393 return false;
394}
395
397 return new DXILPrettyPrinterLegacy(OS);
398}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static StringRef getTextureDimName(dxil::ResourceKind RK)
static void prettyPrintResources(raw_ostream &OS, const DXILResourceMap &DRM, DXILResourceTypeMap &DRTM)
static StringRef getRCPrefix(dxil::ResourceClass RC)
static StringRef getFormatName(const dxil::ResourceTypeInfo &RI)
static void prettyPrint(raw_ostream &OS, Module &M, const DXILResourceMap &DRM, DXILResourceTypeMap &DRTM)
static StringRef getRCName(dxil::ResourceClass RC)
DXIL Resource Implicit Binding
dxil translate DXIL Translate Metadata
#define _
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
This file contains the declarations for metadata subclasses.
ModuleAnalysisManager MAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
Abstract interface of slot tracker storage.
virtual unsigned getNextMetadataSlot()=0
AnalysisUsage & addRequired()
PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
Metadata node.
Definition Metadata.h:1075
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1567
LLVM_ABI void print(raw_ostream &OS, const Module *M=nullptr, bool IsForDebug=false) const
Print.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
Manage lifetime of a slot tracker for printing IR.
std::vector< std::pair< unsigned, const MDNode * > > MachineMDNodeListType
void collectMDNodes(MachineMDNodeListType &L, unsigned LB, unsigned UB) const
void setProcessHook(std::function< void(AbstractSlotTrackerStorage *, const Module *, bool)>)
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
LLVM_ABI std::string upper() const
Convert the given ASCII string to uppercase.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
dxil::ResourceClass getResourceClass() const
LLVM_ABI bool isSampler() const
LLVM_ABI bool isTyped() const
LLVM_ABI bool isCBuffer() const
LLVM_ABI TypedInfo getTyped() const
LLVM_ABI bool isStruct() const
formatted_raw_ostream - A raw_ostream that wraps another one and keeps track of line and column posit...
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
DXILDebugInfoMap run(Module &M)
ResourceKind
The kind of resource for an SRV or UAV resource.
Definition DXILABI.h:44
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
FunctionAddr VTableAddr Count
Definition InstrProf.h:139
LLVM_ABI raw_ostream & nulls()
This returns a reference to a raw_ostream which simply discards output.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition Format.h:129
ModulePass * createDXILPrettyPrinterLegacyPass(raw_ostream &OS)
Pass to pretty print DXIL metadata.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
#define N