1//===- DXILResource.cpp - Representations of DXIL resources ---------------===//
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 "llvm/Analysis/DXILResource.h"
10#include "llvm/ADT/APInt.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/ADT/SmallString.h"
13#include "llvm/ADT/SmallVector.h"
14#include "llvm/IR/Constants.h"
15#include "llvm/IR/DerivedTypes.h"
16#include "llvm/IR/DiagnosticInfo.h"
17#include "llvm/IR/Instructions.h"
18#include "llvm/IR/Intrinsics.h"
19#include "llvm/IR/IntrinsicsDirectX.h"
20#include "llvm/IR/Metadata.h"
21#include "llvm/IR/Module.h"
22#include "llvm/InitializePasses.h"
23#include "llvm/Support/DXILABI.h"
24#include "llvm/Support/FormatVariadic.h"
25#include <cstdint>
26
27#define DEBUG_TYPE "dxil-resource"
28
29using namespace llvm;
30using namespace dxil;
31
32static StringRef getResourceKindName(ResourceKind RK) {
33 switch (RK) {
34 case ResourceKind::Texture1D:
35 return "Texture1D";
36 case ResourceKind::Texture2D:
37 return "Texture2D";
38 case ResourceKind::Texture2DMS:
39 return "Texture2DMS";
40 case ResourceKind::Texture3D:
41 return "Texture3D";
42 case ResourceKind::TextureCube:
43 return "TextureCube";
44 case ResourceKind::Texture1DArray:
45 return "Texture1DArray";
46 case ResourceKind::Texture2DArray:
47 return "Texture2DArray";
48 case ResourceKind::Texture2DMSArray:
49 return "Texture2DMSArray";
50 case ResourceKind::TextureCubeArray:
51 return "TextureCubeArray";
52 case ResourceKind::TypedBuffer:
53 return "Buffer";
54 case ResourceKind::RawBuffer:
55 return "RawBuffer";
56 case ResourceKind::StructuredBuffer:
57 return "StructuredBuffer";
58 case ResourceKind::CBuffer:
59 return "CBuffer";
60 case ResourceKind::Sampler:
61 return "Sampler";
62 case ResourceKind::TBuffer:
63 return "TBuffer";
64 case ResourceKind::RTAccelerationStructure:
65 return "RTAccelerationStructure";
66 case ResourceKind::FeedbackTexture2D:
67 return "FeedbackTexture2D";
68 case ResourceKind::FeedbackTexture2DArray:
69 return "FeedbackTexture2DArray";
70 case ResourceKind::NumEntries:
71 case ResourceKind::Invalid:
72 return "<invalid>";
73 }
74 llvm_unreachable("Unhandled ResourceKind");
75}
76
77static StringRef getElementTypeName(ElementType ET) {
78 switch (ET) {
79 case ElementType::I1:
80 return "i1";
81 case ElementType::I16:
82 return "i16";
83 case ElementType::U16:
84 return "u16";
85 case ElementType::I32:
86 return "i32";
87 case ElementType::U32:
88 return "u32";
89 case ElementType::I64:
90 return "i64";
91 case ElementType::U64:
92 return "u64";
93 case ElementType::F16:
94 return "f16";
95 case ElementType::F32:
96 return "f32";
97 case ElementType::F64:
98 return "f64";
99 case ElementType::SNormF16:
100 return "snorm_f16";
101 case ElementType::UNormF16:
102 return "unorm_f16";
103 case ElementType::SNormF32:
104 return "snorm_f32";
105 case ElementType::UNormF32:
106 return "unorm_f32";
107 case ElementType::SNormF64:
108 return "snorm_f64";
109 case ElementType::UNormF64:
110 return "unorm_f64";
111 case ElementType::PackedS8x32:
112 return "p32i8";
113 case ElementType::PackedU8x32:
114 return "p32u8";
115 case ElementType::Invalid:
116 return "<invalid>";
117 }
118 llvm_unreachable("Unhandled ElementType");
119}
120
121static StringRef getElementTypeNameForTemplate(ElementType ET) {
122 switch (ET) {
123 case ElementType::I1:
124 return "bool";
125 case ElementType::I16:
126 return "int16_t";
127 case ElementType::U16:
128 return "uint16_t";
129 case ElementType::I32:
130 return "int32_t";
131 case ElementType::U32:
132 return "uint32_t";
133 case ElementType::I64:
134 return "int64_t";
135 case ElementType::U64:
136 return "uint32_t";
137 case ElementType::F16:
138 case ElementType::SNormF16:
139 case ElementType::UNormF16:
140 return "half";
141 case ElementType::F32:
142 case ElementType::SNormF32:
143 case ElementType::UNormF32:
144 return "float";
145 case ElementType::F64:
146 case ElementType::SNormF64:
147 case ElementType::UNormF64:
148 return "double";
149 case ElementType::PackedS8x32:
150 return "int8_t4_packed";
151 case ElementType::PackedU8x32:
152 return "uint8_t4_packed";
153 case ElementType::Invalid:
154 return "<invalid>";
155 }
156 llvm_unreachable("Unhandled ElementType");
157}
158
159static StringRef getSamplerTypeName(SamplerType ST) {
160 switch (ST) {
161 case SamplerType::Default:
162 return "Default";
163 case SamplerType::Comparison:
164 return "Comparison";
165 case SamplerType::Mono:
166 return "Mono";
167 }
168 llvm_unreachable("Unhandled SamplerType");
169}
170
171static StringRef getSamplerFeedbackTypeName(SamplerFeedbackType SFT) {
172 switch (SFT) {
173 case SamplerFeedbackType::MinMip:
174 return "MinMip";
175 case SamplerFeedbackType::MipRegionUsed:
176 return "MipRegionUsed";
177 }
178 llvm_unreachable("Unhandled SamplerFeedbackType");
179}
180
181static dxil::ElementType toDXILElementType(Type *Ty, bool IsSigned) {
182 // TODO: Handle unorm, snorm, and packed.
183 Ty = Ty->getScalarType();
184
185 if (Ty->isIntegerTy()) {
186 switch (Ty->getIntegerBitWidth()) {
187 case 16:
188 return IsSigned ? ElementType::I16 : ElementType::U16;
189 case 32:
190 return IsSigned ? ElementType::I32 : ElementType::U32;
191 case 64:
192 return IsSigned ? ElementType::I64 : ElementType::U64;
193 case 1:
194 default:
195 return ElementType::Invalid;
196 }
197 } else if (Ty->isFloatTy()) {
198 return ElementType::F32;
199 } else if (Ty->isDoubleTy()) {
200 return ElementType::F64;
201 } else if (Ty->isHalfTy()) {
202 return ElementType::F16;
203 }
204
205 return ElementType::Invalid;
206}
207
208static dxil::ElementType toDXILStorageType(dxil::ElementType ET) {
209 if (ET == dxil::ElementType::U64 || ET == dxil::ElementType::F64 ||
210 ET == dxil::ElementType::I64 || ET == dxil::ElementType::SNormF64 ||
211 ET == dxil::ElementType::UNormF64)
212 return dxil::ElementType::U32;
213 return ET;
214}
215
216ResourceTypeInfo::ResourceTypeInfo(TargetExtType *HandleTy,
217 const dxil::ResourceClass RC_,
218 const dxil::ResourceKind Kind_)
219 : HandleTy(HandleTy) {
220 // If we're provided a resource class and kind, trust them.
221 if (Kind_ != dxil::ResourceKind::Invalid) {
222 RC = RC_;
223 Kind = Kind_;
224 return;
225 }
226
227 if (auto *Ty = dyn_cast<RawBufferExtType>(Val: HandleTy)) {
228 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
229 Kind = Ty->isStructured() ? ResourceKind::StructuredBuffer
230 : ResourceKind::RawBuffer;
231 } else if (auto *Ty = dyn_cast<TypedBufferExtType>(Val: HandleTy)) {
232 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
233 Kind = ResourceKind::TypedBuffer;
234 } else if (auto *Ty = dyn_cast<TextureExtType>(Val: HandleTy)) {
235 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
236 Kind = Ty->getDimension();
237 } else if (auto *Ty = dyn_cast<MSTextureExtType>(Val: HandleTy)) {
238 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
239 Kind = Ty->getDimension();
240 } else if (auto *Ty = dyn_cast<FeedbackTextureExtType>(Val: HandleTy)) {
241 RC = ResourceClass::UAV;
242 Kind = Ty->getDimension();
243 } else if (isa<CBufferExtType>(Val: HandleTy)) {
244 RC = ResourceClass::CBuffer;
245 Kind = ResourceKind::CBuffer;
246 } else if (isa<SamplerExtType>(Val: HandleTy)) {
247 RC = ResourceClass::Sampler;
248 Kind = ResourceKind::Sampler;
249 } else
250 llvm_unreachable("Unknown handle type");
251}
252
253static void formatTypeName(SmallString<64> &Dest, StringRef Name,
254 bool IsWriteable, bool IsROV,
255 Type *ContainedType = nullptr,
256 bool IsSigned = true) {
257 raw_svector_ostream DestStream(Dest);
258 if (IsWriteable)
259 DestStream << (IsROV ? "RasterizerOrdered" : "RW");
260 DestStream << Name;
261
262 if (!ContainedType)
263 return;
264
265 SmallVector<uint64_t> ArrayDimensions;
266 while (ArrayType *AT = dyn_cast<ArrayType>(Val: ContainedType)) {
267 ArrayDimensions.push_back(Elt: AT->getNumElements());
268 ContainedType = AT->getElementType();
269 }
270
271 StringRef ElementName;
272 ElementType ET = toDXILElementType(Ty: ContainedType, IsSigned);
273 if (ET != ElementType::Invalid) {
274 ElementName = getElementTypeNameForTemplate(ET);
275 } else {
276 assert(isa<StructType>(ContainedType) &&
277 "invalid element type for raw buffer");
278 StructType *ST = cast<StructType>(Val: ContainedType);
279 if (!ST->hasName())
280 return;
281 ElementName = ST->getStructName();
282 }
283
284 DestStream << "<" << ElementName;
285 if (const FixedVectorType *VTy = dyn_cast<FixedVectorType>(Val: ContainedType))
286 DestStream << VTy->getNumElements();
287 for (uint64_t Dim : ArrayDimensions)
288 DestStream << "[" << Dim << "]";
289 DestStream << ">";
290}
291
292static StructType *getOrCreateElementStruct(Type *ElemType, StringRef Name) {
293 StructType *Ty = StructType::getTypeByName(C&: ElemType->getContext(), Name);
294 if (Ty && Ty->getNumElements() == 1 && Ty->getElementType(N: 0) == ElemType)
295 return Ty;
296 return StructType::create(Elements: ElemType, Name);
297}
298
299static Type *getTypeWithoutPadding(Type *Ty) {
300 // Recursively remove padding from structures.
301 if (auto *ST = dyn_cast<StructType>(Val: Ty)) {
302 LLVMContext &Ctx = Ty->getContext();
303 SmallVector<Type *> ElementTypes;
304 ElementTypes.reserve(N: ST->getNumElements());
305 for (Type *ElTy : ST->elements()) {
306 if (isa<PaddingExtType>(Val: ElTy))
307 continue;
308 ElementTypes.push_back(Elt: getTypeWithoutPadding(Ty: ElTy));
309 }
310
311 // Handle explicitly padded cbuffer arrays like { [ n x paddedty ], ty }
312 if (ElementTypes.size() == 2)
313 if (auto *AT = dyn_cast<ArrayType>(Val: ElementTypes[0]))
314 if (ElementTypes[1] == AT->getElementType())
315 return ArrayType::get(ElementType: ElementTypes[1], NumElements: AT->getNumElements() + 1);
316
317 // If we only have a single element, don't wrap it in a struct.
318 if (ElementTypes.size() == 1)
319 return ElementTypes[0];
320
321 return StructType::get(Context&: Ctx, Elements: ElementTypes, /*IsPacked=*/isPacked: false);
322 }
323 // Arrays just need to have their element type adjusted.
324 if (auto *AT = dyn_cast<ArrayType>(Val: Ty))
325 return ArrayType::get(ElementType: getTypeWithoutPadding(Ty: AT->getElementType()),
326 NumElements: AT->getNumElements());
327 // Anything else should be good as is.
328 return Ty;
329}
330
331StructType *ResourceTypeInfo::createElementStruct(StringRef CBufferName) {
332 SmallString<64> TypeName;
333
334 switch (Kind) {
335 case ResourceKind::Texture1D:
336 case ResourceKind::Texture2D:
337 case ResourceKind::Texture3D:
338 case ResourceKind::TextureCube:
339 case ResourceKind::Texture1DArray:
340 case ResourceKind::Texture2DArray:
341 case ResourceKind::TextureCubeArray: {
342 auto *RTy = cast<TextureExtType>(Val: HandleTy);
343 formatTypeName(Dest&: TypeName, Name: getResourceKindName(RK: Kind), IsWriteable: RTy->isWriteable(),
344 IsROV: RTy->isROV(), ContainedType: RTy->getResourceType(), IsSigned: RTy->isSigned());
345 return getOrCreateElementStruct(ElemType: RTy->getResourceType(), Name: TypeName);
346 }
347 case ResourceKind::Texture2DMS:
348 case ResourceKind::Texture2DMSArray: {
349 auto *RTy = cast<MSTextureExtType>(Val: HandleTy);
350 formatTypeName(Dest&: TypeName, Name: getResourceKindName(RK: Kind), IsWriteable: RTy->isWriteable(),
351 /*IsROV=*/false, ContainedType: RTy->getResourceType(), IsSigned: RTy->isSigned());
352 return getOrCreateElementStruct(ElemType: RTy->getResourceType(), Name: TypeName);
353 }
354 case ResourceKind::TypedBuffer: {
355 auto *RTy = cast<TypedBufferExtType>(Val: HandleTy);
356 formatTypeName(Dest&: TypeName, Name: getResourceKindName(RK: Kind), IsWriteable: RTy->isWriteable(),
357 IsROV: RTy->isROV(), ContainedType: RTy->getResourceType(), IsSigned: RTy->isSigned());
358 return getOrCreateElementStruct(ElemType: RTy->getResourceType(), Name: TypeName);
359 }
360 case ResourceKind::RawBuffer: {
361 auto *RTy = cast<RawBufferExtType>(Val: HandleTy);
362 formatTypeName(Dest&: TypeName, Name: "ByteAddressBuffer", IsWriteable: RTy->isWriteable(),
363 IsROV: RTy->isROV());
364 return getOrCreateElementStruct(ElemType: Type::getInt32Ty(C&: HandleTy->getContext()),
365 Name: TypeName);
366 }
367 case ResourceKind::StructuredBuffer: {
368 auto *RTy = cast<RawBufferExtType>(Val: HandleTy);
369 Type *Ty = RTy->getResourceType();
370 formatTypeName(Dest&: TypeName, Name: "StructuredBuffer", IsWriteable: RTy->isWriteable(),
371 IsROV: RTy->isROV(), ContainedType: RTy->getResourceType(), IsSigned: true);
372 return getOrCreateElementStruct(ElemType: Ty, Name: TypeName);
373 }
374 case ResourceKind::FeedbackTexture2D:
375 case ResourceKind::FeedbackTexture2DArray: {
376 auto *RTy = cast<FeedbackTextureExtType>(Val: HandleTy);
377 TypeName = formatv(Fmt: "{0}<{1}>", Vals: getResourceKindName(RK: Kind),
378 Vals: llvm::to_underlying(E: RTy->getFeedbackType()));
379 return getOrCreateElementStruct(ElemType: Type::getInt32Ty(C&: HandleTy->getContext()),
380 Name: TypeName);
381 }
382 case ResourceKind::CBuffer: {
383 auto *RTy = cast<CBufferExtType>(Val: HandleTy);
384 SmallString<64> Name = getResourceKindName(RK: Kind);
385 if (!CBufferName.empty()) {
386 Name.append(RHS: ".");
387 Name.append(RHS: CBufferName);
388 }
389
390 // TODO: Remove this when we update the frontend to use explicit padding.
391 if (LayoutExtType *LayoutType =
392 dyn_cast<LayoutExtType>(Val: RTy->getResourceType())) {
393 StructType *Ty = cast<StructType>(Val: LayoutType->getWrappedType());
394 return StructType::create(Elements: Ty->elements(), Name);
395 }
396
397 return getOrCreateElementStruct(
398 ElemType: getTypeWithoutPadding(Ty: RTy->getResourceType()), Name);
399 }
400 case ResourceKind::Sampler: {
401 auto *RTy = cast<SamplerExtType>(Val: HandleTy);
402 TypeName = formatv(Fmt: "SamplerState<{0}>",
403 Vals: llvm::to_underlying(E: RTy->getSamplerType()));
404 return getOrCreateElementStruct(ElemType: Type::getInt32Ty(C&: HandleTy->getContext()),
405 Name: TypeName);
406 }
407 case ResourceKind::TBuffer:
408 case ResourceKind::RTAccelerationStructure:
409 llvm_unreachable("Unhandled resource kind");
410 case ResourceKind::Invalid:
411 case ResourceKind::NumEntries:
412 llvm_unreachable("Invalid resource kind");
413 }
414 llvm_unreachable("Unhandled ResourceKind enum");
415}
416
417bool ResourceTypeInfo::isUAV() const { return RC == ResourceClass::UAV; }
418
419bool ResourceTypeInfo::isCBuffer() const {
420 return RC == ResourceClass::CBuffer;
421}
422
423bool ResourceTypeInfo::isSampler() const {
424 return RC == ResourceClass::Sampler;
425}
426
427bool ResourceTypeInfo::isStruct() const {
428 return Kind == ResourceKind::StructuredBuffer;
429}
430
431bool ResourceTypeInfo::isTyped() const {
432 switch (Kind) {
433 case ResourceKind::Texture1D:
434 case ResourceKind::Texture2D:
435 case ResourceKind::Texture2DMS:
436 case ResourceKind::Texture3D:
437 case ResourceKind::TextureCube:
438 case ResourceKind::Texture1DArray:
439 case ResourceKind::Texture2DArray:
440 case ResourceKind::Texture2DMSArray:
441 case ResourceKind::TextureCubeArray:
442 case ResourceKind::TypedBuffer:
443 return true;
444 case ResourceKind::RawBuffer:
445 case ResourceKind::StructuredBuffer:
446 case ResourceKind::FeedbackTexture2D:
447 case ResourceKind::FeedbackTexture2DArray:
448 case ResourceKind::CBuffer:
449 case ResourceKind::Sampler:
450 case ResourceKind::TBuffer:
451 case ResourceKind::RTAccelerationStructure:
452 return false;
453 case ResourceKind::Invalid:
454 case ResourceKind::NumEntries:
455 llvm_unreachable("Invalid resource kind");
456 }
457 llvm_unreachable("Unhandled ResourceKind enum");
458}
459
460bool ResourceTypeInfo::isFeedback() const {
461 return Kind == ResourceKind::FeedbackTexture2D ||
462 Kind == ResourceKind::FeedbackTexture2DArray;
463}
464
465bool ResourceTypeInfo::isMultiSample() const {
466 return Kind == ResourceKind::Texture2DMS ||
467 Kind == ResourceKind::Texture2DMSArray;
468}
469
470static bool isROV(dxil::ResourceKind Kind, TargetExtType *Ty) {
471 switch (Kind) {
472 case ResourceKind::Texture1D:
473 case ResourceKind::Texture2D:
474 case ResourceKind::Texture3D:
475 case ResourceKind::TextureCube:
476 case ResourceKind::Texture1DArray:
477 case ResourceKind::Texture2DArray:
478 case ResourceKind::TextureCubeArray:
479 return cast<TextureExtType>(Val: Ty)->isROV();
480 case ResourceKind::TypedBuffer:
481 return cast<TypedBufferExtType>(Val: Ty)->isROV();
482 case ResourceKind::RawBuffer:
483 case ResourceKind::StructuredBuffer:
484 return cast<RawBufferExtType>(Val: Ty)->isROV();
485 case ResourceKind::Texture2DMS:
486 case ResourceKind::Texture2DMSArray:
487 case ResourceKind::FeedbackTexture2D:
488 case ResourceKind::FeedbackTexture2DArray:
489 return false;
490 case ResourceKind::CBuffer:
491 case ResourceKind::Sampler:
492 case ResourceKind::TBuffer:
493 case ResourceKind::RTAccelerationStructure:
494 case ResourceKind::Invalid:
495 case ResourceKind::NumEntries:
496 llvm_unreachable("Resource cannot be ROV");
497 }
498 llvm_unreachable("Unhandled ResourceKind enum");
499}
500
501ResourceTypeInfo::UAVInfo ResourceTypeInfo::getUAV() const {
502 assert(isUAV() && "Not a UAV");
503 return {.IsROV: isROV(Kind, Ty: HandleTy)};
504}
505
506uint32_t ResourceTypeInfo::getCBufferSize(const DataLayout &DL) const {
507 assert(isCBuffer() && "Not a CBuffer");
508
509 Type *ElTy = cast<CBufferExtType>(Val: HandleTy)->getResourceType();
510
511 // TODO: Remove this when we update the frontend to use explicit padding.
512 if (auto *LayoutTy = dyn_cast<LayoutExtType>(Val: ElTy))
513 return LayoutTy->getSize();
514
515 return DL.getTypeAllocSize(Ty: ElTy);
516}
517
518dxil::SamplerType ResourceTypeInfo::getSamplerType() const {
519 assert(isSampler() && "Not a Sampler");
520 return cast<SamplerExtType>(Val: HandleTy)->getSamplerType();
521}
522
523ResourceTypeInfo::StructInfo
524ResourceTypeInfo::getStruct(const DataLayout &DL) const {
525 assert(isStruct() && "Not a Struct");
526
527 Type *ElTy = cast<RawBufferExtType>(Val: HandleTy)->getResourceType();
528
529 uint32_t Stride = DL.getTypeAllocSize(Ty: ElTy);
530 MaybeAlign Alignment;
531 if (auto *STy = dyn_cast<StructType>(Val: ElTy))
532 Alignment = DL.getStructLayout(Ty: STy)->getAlignment();
533 uint32_t AlignLog2 = Alignment ? Log2(A: *Alignment) : 0;
534 return {.Stride: Stride, .AlignLog2: AlignLog2};
535}
536
537static std::pair<Type *, bool> getTypedElementType(dxil::ResourceKind Kind,
538 TargetExtType *Ty) {
539 switch (Kind) {
540 case ResourceKind::Texture1D:
541 case ResourceKind::Texture2D:
542 case ResourceKind::Texture3D:
543 case ResourceKind::TextureCube:
544 case ResourceKind::Texture1DArray:
545 case ResourceKind::Texture2DArray:
546 case ResourceKind::TextureCubeArray: {
547 auto *RTy = cast<TextureExtType>(Val: Ty);
548 return {RTy->getResourceType(), RTy->isSigned()};
549 }
550 case ResourceKind::Texture2DMS:
551 case ResourceKind::Texture2DMSArray: {
552 auto *RTy = cast<MSTextureExtType>(Val: Ty);
553 return {RTy->getResourceType(), RTy->isSigned()};
554 }
555 case ResourceKind::TypedBuffer: {
556 auto *RTy = cast<TypedBufferExtType>(Val: Ty);
557 return {RTy->getResourceType(), RTy->isSigned()};
558 }
559 case ResourceKind::RawBuffer:
560 case ResourceKind::StructuredBuffer:
561 case ResourceKind::FeedbackTexture2D:
562 case ResourceKind::FeedbackTexture2DArray:
563 case ResourceKind::CBuffer:
564 case ResourceKind::Sampler:
565 case ResourceKind::TBuffer:
566 case ResourceKind::RTAccelerationStructure:
567 case ResourceKind::Invalid:
568 case ResourceKind::NumEntries:
569 llvm_unreachable("Resource is not typed");
570 }
571 llvm_unreachable("Unhandled ResourceKind enum");
572}
573
574ResourceTypeInfo::TypedInfo ResourceTypeInfo::getTyped() const {
575 assert(isTyped() && "Not typed");
576
577 auto [ElTy, IsSigned] = getTypedElementType(Kind, Ty: HandleTy);
578 dxil::ElementType ET = toDXILElementType(Ty: ElTy, IsSigned);
579 dxil::ElementType DXILStorageTy = toDXILStorageType(ET);
580 uint32_t Count = 1;
581 if (auto *VTy = dyn_cast<FixedVectorType>(Val: ElTy))
582 Count = VTy->getNumElements();
583 return {.ElementTy: ET, .DXILStorageTy: DXILStorageTy, .ElementCount: Count};
584}
585
586dxil::SamplerFeedbackType ResourceTypeInfo::getFeedbackType() const {
587 assert(isFeedback() && "Not Feedback");
588 return cast<FeedbackTextureExtType>(Val: HandleTy)->getFeedbackType();
589}
590uint32_t ResourceTypeInfo::getMultiSampleCount() const {
591 assert(isMultiSample() && "Not MultiSampled");
592 return cast<MSTextureExtType>(Val: HandleTy)->getSampleCount();
593}
594
595bool ResourceTypeInfo::operator==(const ResourceTypeInfo &RHS) const {
596 return HandleTy == RHS.HandleTy;
597}
598
599bool ResourceTypeInfo::operator<(const ResourceTypeInfo &RHS) const {
600 // An empty datalayout is sufficient for sorting purposes.
601 DataLayout DummyDL;
602 if (std::tie(args: RC, args: Kind) < std::tie(args: RHS.RC, args: RHS.Kind))
603 return true;
604 if (isCBuffer() && RHS.isCBuffer() &&
605 getCBufferSize(DL: DummyDL) < RHS.getCBufferSize(DL: DummyDL))
606 return true;
607 if (isSampler() && RHS.isSampler() && getSamplerType() < RHS.getSamplerType())
608 return true;
609 if (isUAV() && RHS.isUAV() && getUAV() < RHS.getUAV())
610 return true;
611 if (isStruct() && RHS.isStruct() &&
612 getStruct(DL: DummyDL) < RHS.getStruct(DL: DummyDL))
613 return true;
614 if (isFeedback() && RHS.isFeedback() &&
615 getFeedbackType() < RHS.getFeedbackType())
616 return true;
617 if (isTyped() && RHS.isTyped() && getTyped() < RHS.getTyped())
618 return true;
619 if (isMultiSample() && RHS.isMultiSample() &&
620 getMultiSampleCount() < RHS.getMultiSampleCount())
621 return true;
622 return false;
623}
624
625void ResourceTypeInfo::print(raw_ostream &OS, const DataLayout &DL) const {
626 OS << " Class: " << getResourceClassName(RC) << "\n"
627 << " Kind: " << getResourceKindName(RK: Kind) << "\n";
628
629 if (isCBuffer()) {
630 OS << " CBuffer size: " << getCBufferSize(DL) << "\n";
631 } else if (isSampler()) {
632 OS << " Sampler Type: " << getSamplerTypeName(ST: getSamplerType()) << "\n";
633 } else {
634 if (isUAV()) {
635 UAVInfo UAVFlags = getUAV();
636 OS << " IsROV: " << UAVFlags.IsROV << "\n";
637 }
638 if (isMultiSample())
639 OS << " Sample Count: " << getMultiSampleCount() << "\n";
640
641 if (isStruct()) {
642 StructInfo Struct = getStruct(DL);
643 OS << " Buffer Stride: " << Struct.Stride << "\n";
644 OS << " Alignment: " << Struct.AlignLog2 << "\n";
645 } else if (isTyped()) {
646 TypedInfo Typed = getTyped();
647 OS << " Element Type: " << getElementTypeName(ET: Typed.ElementTy);
648 if (Typed.ElementTy != Typed.DXILStorageTy)
649 OS << " (stored as " << getElementTypeName(ET: Typed.DXILStorageTy) << ")";
650 OS << "\n"
651 << " Element Count: " << Typed.ElementCount << "\n";
652 } else if (isFeedback())
653 OS << " Feedback Type: " << getSamplerFeedbackTypeName(SFT: getFeedbackType())
654 << "\n";
655 }
656}
657
658GlobalVariable *ResourceInfo::createSymbol(Module &M, StructType *Ty) {
659 assert(!Symbol && "Symbol has already been created");
660 Type *ResTy = Ty;
661 int64_t Size = Binding.Size;
662 if (Size != 1)
663 // unbounded arrays are represented as zero-sized arrays in LLVM IR
664 ResTy = ArrayType::get(ElementType: Ty, NumElements: Size == ~0u ? 0 : Size);
665 Symbol = new GlobalVariable(M, ResTy, /*isConstant=*/true,
666 GlobalValue::ExternalLinkage,
667 /*Initializer=*/nullptr, Name);
668 return Symbol;
669}
670
671MDTuple *ResourceInfo::getAsMetadata(Module &M,
672 dxil::ResourceTypeInfo &RTI) const {
673 LLVMContext &Ctx = M.getContext();
674 const DataLayout &DL = M.getDataLayout();
675
676 SmallVector<Metadata *, 11> MDVals;
677
678 Type *I32Ty = Type::getInt32Ty(C&: Ctx);
679 Type *I1Ty = Type::getInt1Ty(C&: Ctx);
680 auto getIntMD = [&I32Ty](uint32_t V) {
681 return ConstantAsMetadata::get(
682 C: Constant::getIntegerValue(Ty: I32Ty, V: APInt(32, V)));
683 };
684 auto getBoolMD = [&I1Ty](uint32_t V) {
685 return ConstantAsMetadata::get(
686 C: Constant::getIntegerValue(Ty: I1Ty, V: APInt(1, V)));
687 };
688
689 MDVals.push_back(Elt: getIntMD(Binding.RecordID));
690 assert(Symbol && "Cannot yet create useful resource metadata without symbol");
691 MDVals.push_back(Elt: ValueAsMetadata::get(V: Symbol));
692 MDVals.push_back(Elt: MDString::get(Context&: Ctx, Str: Name));
693 MDVals.push_back(Elt: getIntMD(Binding.Space));
694 MDVals.push_back(Elt: getIntMD(Binding.LowerBound));
695 MDVals.push_back(Elt: getIntMD(Binding.Size));
696
697 if (RTI.isCBuffer()) {
698 MDVals.push_back(Elt: getIntMD(RTI.getCBufferSize(DL)));
699 MDVals.push_back(Elt: nullptr);
700 } else if (RTI.isSampler()) {
701 MDVals.push_back(Elt: getIntMD(llvm::to_underlying(E: RTI.getSamplerType())));
702 MDVals.push_back(Elt: nullptr);
703 } else {
704 MDVals.push_back(Elt: getIntMD(llvm::to_underlying(E: RTI.getResourceKind())));
705
706 if (RTI.isUAV()) {
707 ResourceTypeInfo::UAVInfo UAVFlags = RTI.getUAV();
708 MDVals.push_back(Elt: getBoolMD(GloballyCoherent));
709 MDVals.push_back(Elt: getBoolMD(hasCounter()));
710 MDVals.push_back(Elt: getBoolMD(UAVFlags.IsROV));
711 } else {
712 // All SRVs include sample count in the metadata, but it's only meaningful
713 // for multi-sampled textured. Also, UAVs can be multisampled in SM6.7+,
714 // but this just isn't reflected in the metadata at all.
715 uint32_t SampleCount =
716 RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0;
717 MDVals.push_back(Elt: getIntMD(SampleCount));
718 }
719
720 // Further properties are attached to a metadata list of tag-value pairs.
721 SmallVector<Metadata *> Tags;
722 if (RTI.isStruct()) {
723 Tags.push_back(
724 Elt: getIntMD(llvm::to_underlying(E: ExtPropTags::StructuredBufferStride)));
725 Tags.push_back(Elt: getIntMD(RTI.getStruct(DL).Stride));
726 } else if (RTI.isTyped()) {
727 Tags.push_back(Elt: getIntMD(llvm::to_underlying(E: ExtPropTags::ElementType)));
728 Tags.push_back(
729 Elt: getIntMD(llvm::to_underlying(E: RTI.getTyped().DXILStorageTy)));
730 } else if (RTI.isFeedback()) {
731 Tags.push_back(
732 Elt: getIntMD(llvm::to_underlying(E: ExtPropTags::SamplerFeedbackKind)));
733 Tags.push_back(Elt: getIntMD(llvm::to_underlying(E: RTI.getFeedbackType())));
734 }
735 MDVals.push_back(Elt: Tags.empty() ? nullptr : MDNode::get(Context&: Ctx, MDs: Tags));
736 }
737
738 return MDNode::get(Context&: Ctx, MDs: MDVals);
739}
740
741std::pair<uint32_t, uint32_t>
742ResourceInfo::getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const {
743 const DataLayout &DL = M.getDataLayout();
744
745 uint32_t ResourceKind = llvm::to_underlying(E: RTI.getResourceKind());
746 uint32_t AlignLog2 = RTI.isStruct() ? RTI.getStruct(DL).AlignLog2 : 0;
747 bool IsUAV = RTI.isUAV();
748 ResourceTypeInfo::UAVInfo UAVFlags =
749 IsUAV ? RTI.getUAV() : ResourceTypeInfo::UAVInfo{};
750 bool IsROV = IsUAV && UAVFlags.IsROV;
751 bool IsGloballyCoherent = IsUAV && GloballyCoherent;
752 uint8_t SamplerCmpOrHasCounter = 0;
753 if (IsUAV)
754 SamplerCmpOrHasCounter = hasCounter();
755 else if (RTI.isSampler())
756 SamplerCmpOrHasCounter = RTI.getSamplerType() == SamplerType::Comparison;
757
758 // TODO: Document this format. Currently the only reference is the
759 // implementation of dxc's DxilResourceProperties struct.
760 uint32_t Word0 = 0;
761 Word0 |= ResourceKind & 0xFF;
762 Word0 |= (AlignLog2 & 0xF) << 8;
763 Word0 |= (IsUAV & 1) << 12;
764 Word0 |= (IsROV & 1) << 13;
765 Word0 |= (IsGloballyCoherent & 1) << 14;
766 Word0 |= (SamplerCmpOrHasCounter & 1) << 15;
767
768 uint32_t Word1 = 0;
769 if (RTI.isStruct())
770 Word1 = RTI.getStruct(DL).Stride;
771 else if (RTI.isCBuffer())
772 Word1 = RTI.getCBufferSize(DL);
773 else if (RTI.isFeedback())
774 Word1 = llvm::to_underlying(E: RTI.getFeedbackType());
775 else if (RTI.isTyped()) {
776 ResourceTypeInfo::TypedInfo Typed = RTI.getTyped();
777 uint32_t CompType = llvm::to_underlying(E: Typed.ElementTy);
778 uint32_t CompCount = Typed.ElementCount;
779 uint32_t SampleCount = RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0;
780
781 Word1 |= (CompType & 0xFF) << 0;
782 Word1 |= (CompCount & 0xFF) << 8;
783 Word1 |= (SampleCount & 0xFF) << 16;
784 }
785
786 return {Word0, Word1};
787}
788
789void ResourceInfo::print(raw_ostream &OS, dxil::ResourceTypeInfo &RTI,
790 const DataLayout &DL) const {
791 if (!Name.empty())
792 OS << " Name: " << Name << "\n";
793
794 if (Symbol) {
795 OS << " Symbol: ";
796 Symbol->printAsOperand(O&: OS);
797 OS << "\n";
798 }
799
800 OS << " Binding:\n"
801 << " Record ID: " << Binding.RecordID << "\n"
802 << " Space: " << Binding.Space << "\n"
803 << " Lower Bound: " << Binding.LowerBound << "\n"
804 << " Size: " << Binding.Size << "\n";
805
806 OS << " Globally Coherent: " << GloballyCoherent << "\n";
807 OS << " Counter Direction: ";
808
809 switch (CounterDirection) {
810 case ResourceCounterDirection::Increment:
811 OS << "Increment\n";
812 break;
813 case ResourceCounterDirection::Decrement:
814 OS << "Decrement\n";
815 break;
816 case ResourceCounterDirection::Unknown:
817 OS << "Unknown\n";
818 break;
819 case ResourceCounterDirection::Invalid:
820 OS << "Invalid\n";
821 break;
822 }
823
824 RTI.print(OS, DL);
825}
826
827//===----------------------------------------------------------------------===//
828
829bool DXILResourceTypeMap::invalidate(Module &M, const PreservedAnalyses &PA,
830 ModuleAnalysisManager::Invalidator &Inv) {
831 // Passes that introduce resource types must explicitly invalidate this pass.
832 auto PAC = PA.getChecker<DXILResourceTypeAnalysis>();
833 return !PAC.preservedWhenStateless();
834}
835
836//===----------------------------------------------------------------------===//
837static bool isUpdateCounterIntrinsic(Function &F) {
838 return F.getIntrinsicID() == Intrinsic::dx_resource_updatecounter;
839}
840
841StringRef dxil::getResourceNameFromBindingCall(CallInst *CI) {
842 Value *Op = nullptr;
843 switch (CI->getCalledFunction()->getIntrinsicID()) {
844 default:
845 llvm_unreachable("unexpected handle creation intrinsic");
846 case Intrinsic::dx_resource_handlefrombinding:
847 case Intrinsic::dx_resource_handlefromimplicitbinding:
848 Op = CI->getArgOperand(i: 4);
849 break;
850 }
851
852 auto *GV = dyn_cast<llvm::GlobalVariable>(Val: Op);
853 if (!GV)
854 return "";
855
856 auto *CA = dyn_cast<ConstantDataArray>(Val: GV->getInitializer());
857 assert(CA && CA->isString() && "expected constant string");
858 StringRef Name = CA->getAsString();
859 // strip trailing 0
860 if (Name.ends_with(Suffix: '\0'))
861 Name = Name.drop_back(N: 1);
862 return Name;
863}
864
865void DXILResourceMap::populateResourceInfos(Module &M,
866 DXILResourceTypeMap &DRTM) {
867 SmallVector<std::tuple<CallInst *, ResourceInfo, ResourceTypeInfo>> CIToInfos;
868
869 for (Function &F : M.functions()) {
870 if (!F.isDeclaration())
871 continue;
872 LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
873 Intrinsic::ID ID = F.getIntrinsicID();
874 switch (ID) {
875 default:
876 continue;
877 case Intrinsic::dx_resource_handlefrombinding: {
878 auto *HandleTy = cast<TargetExtType>(Val: F.getReturnType());
879 ResourceTypeInfo &RTI = DRTM[HandleTy];
880
881 for (User *U : F.users())
882 if (CallInst *CI = dyn_cast<CallInst>(Val: U)) {
883 LLVM_DEBUG(dbgs() << " Visiting: " << *U << "\n");
884 uint32_t Space =
885 cast<ConstantInt>(Val: CI->getArgOperand(i: 0))->getZExtValue();
886 uint32_t LowerBound =
887 cast<ConstantInt>(Val: CI->getArgOperand(i: 1))->getZExtValue();
888 uint32_t Size =
889 cast<ConstantInt>(Val: CI->getArgOperand(i: 2))->getZExtValue();
890 StringRef Name = getResourceNameFromBindingCall(CI);
891
892 ResourceInfo RI =
893 ResourceInfo{/*RecordID=*/0, Space, LowerBound,
894 Size, HandleTy, Name};
895
896 CIToInfos.emplace_back(Args&: CI, Args&: RI, Args&: RTI);
897 }
898
899 break;
900 }
901 }
902 }
903
904 llvm::stable_sort(Range&: CIToInfos, C: [](auto &LHS, auto &RHS) {
905 const auto &[LCI, LRI, LRTI] = LHS;
906 const auto &[RCI, RRI, RRTI] = RHS;
907 // Sort by resource class first for grouping purposes, and then by the
908 // binding and type so we can remove duplicates.
909 ResourceClass LRC = LRTI.getResourceClass();
910 ResourceClass RRC = RRTI.getResourceClass();
911
912 return std::tie(LRC, LRI, LRTI) < std::tie(RRC, RRI, RRTI);
913 });
914 for (auto [CI, RI, RTI] : CIToInfos) {
915 if (Infos.empty() || RI != Infos.back())
916 Infos.push_back(Elt: RI);
917 CallMap[CI] = Infos.size() - 1;
918 }
919
920 unsigned Size = Infos.size();
921 // In DXC, Record ID is unique per resource type. Match that.
922 FirstUAV = FirstCBuffer = FirstSampler = Size;
923 uint32_t NextID = 0;
924 for (unsigned I = 0, E = Size; I != E; ++I) {
925 ResourceInfo &RI = Infos[I];
926 ResourceTypeInfo &RTI = DRTM[RI.getHandleTy()];
927 if (RTI.isUAV() && FirstUAV == Size) {
928 FirstUAV = I;
929 NextID = 0;
930 } else if (RTI.isCBuffer() && FirstCBuffer == Size) {
931 FirstCBuffer = I;
932 NextID = 0;
933 } else if (RTI.isSampler() && FirstSampler == Size) {
934 FirstSampler = I;
935 NextID = 0;
936 }
937
938 // We need to make sure the types of resource are ordered even if some are
939 // missing.
940 FirstCBuffer = std::min(l: {FirstCBuffer, FirstSampler});
941 FirstUAV = std::min(l: {FirstUAV, FirstCBuffer});
942
943 // Adjust the resource binding to use the next ID.
944 RI.setBindingID(NextID++);
945 }
946}
947
948void DXILResourceMap::populateCounterDirections(Module &M) {
949 for (Function &F : M.functions()) {
950 if (!isUpdateCounterIntrinsic(F))
951 continue;
952
953 LLVM_DEBUG(dbgs() << "Update Counter Function: " << F.getName() << "\n");
954
955 for (const User *U : F.users()) {
956 const CallInst *CI = dyn_cast<CallInst>(Val: U);
957 assert(CI && "Users of dx_resource_updateCounter must be call instrs");
958
959 // Determine if the use is an increment or decrement
960 Value *CountArg = CI->getArgOperand(i: 1);
961 ConstantInt *CountValue = cast<ConstantInt>(Val: CountArg);
962 int64_t CountLiteral = CountValue->getSExtValue();
963
964 // 0 is an unknown direction and shouldn't result in an insert
965 if (CountLiteral == 0)
966 continue;
967
968 ResourceCounterDirection Direction = ResourceCounterDirection::Decrement;
969 if (CountLiteral > 0)
970 Direction = ResourceCounterDirection::Increment;
971
972 // Collect all potential creation points for the handle arg
973 Value *HandleArg = CI->getArgOperand(i: 0);
974 SmallVector<ResourceInfo *> RBInfos = findByUse(Key: HandleArg);
975 for (ResourceInfo *RBInfo : RBInfos) {
976 if (RBInfo->CounterDirection == ResourceCounterDirection::Unknown)
977 RBInfo->CounterDirection = Direction;
978 else if (RBInfo->CounterDirection != Direction) {
979 RBInfo->CounterDirection = ResourceCounterDirection::Invalid;
980 HasInvalidDirection = true;
981 }
982 }
983 }
984 }
985}
986
987void DXILResourceMap::populate(Module &M, DXILResourceTypeMap &DRTM) {
988 populateResourceInfos(M, DRTM);
989 populateCounterDirections(M);
990}
991
992void DXILResourceMap::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
993 const DataLayout &DL) const {
994 for (unsigned I = 0, E = Infos.size(); I != E; ++I) {
995 OS << "Resource " << I << ":\n";
996 const dxil::ResourceInfo &RI = Infos[I];
997 RI.print(OS, RTI&: DRTM[RI.getHandleTy()], DL);
998 OS << "\n";
999 }
1000
1001 for (const auto &[CI, Index] : CallMap) {
1002 OS << "Call bound to " << Index << ":";
1003 CI->print(O&: OS);
1004 OS << "\n";
1005 }
1006}
1007
1008SmallVector<dxil::ResourceInfo *> DXILResourceMap::findByUse(const Value *Key) {
1009 if (const PHINode *Phi = dyn_cast<PHINode>(Val: Key)) {
1010 SmallVector<dxil::ResourceInfo *> Children;
1011 for (const Value *V : Phi->operands()) {
1012 Children.append(RHS: findByUse(Key: V));
1013 }
1014 return Children;
1015 }
1016
1017 const CallInst *CI = dyn_cast<CallInst>(Val: Key);
1018 if (!CI)
1019 return {};
1020
1021 switch (CI->getIntrinsicID()) {
1022 // Found the create, return the binding
1023 case Intrinsic::dx_resource_handlefrombinding: {
1024 auto Pos = CallMap.find(Val: CI);
1025 assert(Pos != CallMap.end() && "HandleFromBinding must be in resource map");
1026 return {&Infos[Pos->second]};
1027 }
1028 default:
1029 break;
1030 }
1031
1032 // Check if any of the parameters are the resource we are following. If so
1033 // keep searching. If none of them are return an empty list
1034 const Type *UseType = CI->getType();
1035 SmallVector<dxil::ResourceInfo *> Children;
1036 for (const Value *V : CI->args()) {
1037 if (V->getType() != UseType)
1038 continue;
1039
1040 Children.append(RHS: findByUse(Key: V));
1041 }
1042
1043 return Children;
1044}
1045
1046//===----------------------------------------------------------------------===//
1047
1048void DXILResourceBindingInfo::populate(Module &M, DXILResourceTypeMap &DRTM) {
1049 hlsl::BindingInfoBuilder Builder;
1050
1051 // collect all of the llvm.dx.resource.handlefrombinding calls;
1052 // make a note if there is llvm.dx.resource.handlefromimplicitbinding
1053 for (Function &F : M.functions()) {
1054 if (!F.isDeclaration())
1055 continue;
1056
1057 switch (F.getIntrinsicID()) {
1058 default:
1059 continue;
1060 case Intrinsic::dx_resource_handlefrombinding: {
1061 auto *HandleTy = cast<TargetExtType>(Val: F.getReturnType());
1062 ResourceTypeInfo &RTI = DRTM[HandleTy];
1063
1064 for (User *U : F.users())
1065 if (CallInst *CI = dyn_cast<CallInst>(Val: U)) {
1066 uint32_t Space =
1067 cast<ConstantInt>(Val: CI->getArgOperand(i: 0))->getZExtValue();
1068 uint32_t LowerBound =
1069 cast<ConstantInt>(Val: CI->getArgOperand(i: 1))->getZExtValue();
1070 int32_t Size =
1071 cast<ConstantInt>(Val: CI->getArgOperand(i: 2))->getZExtValue();
1072 Value *Name = CI->getArgOperand(i: 4);
1073
1074 // negative size means unbounded resource array;
1075 // upper bound register overflow should be detected in Sema
1076 assert((Size < 0 || (unsigned)LowerBound + Size - 1 <= UINT32_MAX) &&
1077 "upper bound register overflow");
1078 uint32_t UpperBound = Size < 0 ? UINT32_MAX : LowerBound + Size - 1;
1079 Builder.trackBinding(RC: RTI.getResourceClass(), Space, LowerBound,
1080 UpperBound, Cookie: Name);
1081 }
1082 break;
1083 }
1084 case Intrinsic::dx_resource_handlefromimplicitbinding: {
1085 HasImplicitBinding = true;
1086 break;
1087 }
1088 }
1089 }
1090
1091 Bindings = Builder.calculateBindingInfo(
1092 ReportOverlap: [this](auto, auto) { this->HasOverlappingBinding = true; });
1093}
1094
1095//===----------------------------------------------------------------------===//
1096
1097AnalysisKey DXILResourceTypeAnalysis::Key;
1098AnalysisKey DXILResourceAnalysis::Key;
1099AnalysisKey DXILResourceBindingAnalysis::Key;
1100
1101DXILResourceMap DXILResourceAnalysis::run(Module &M,
1102 ModuleAnalysisManager &AM) {
1103 DXILResourceMap Data;
1104 DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(IR&: M);
1105 Data.populate(M, DRTM);
1106 return Data;
1107}
1108
1109DXILResourceBindingInfo
1110DXILResourceBindingAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
1111 DXILResourceBindingInfo Data;
1112 DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(IR&: M);
1113 Data.populate(M, DRTM);
1114 return Data;
1115}
1116
1117PreservedAnalyses DXILResourcePrinterPass::run(Module &M,
1118 ModuleAnalysisManager &AM) {
1119 DXILResourceMap &DRM = AM.getResult<DXILResourceAnalysis>(IR&: M);
1120 DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(IR&: M);
1121
1122 DRM.print(OS, DRTM, DL: M.getDataLayout());
1123 return PreservedAnalyses::all();
1124}
1125
1126void DXILResourceTypeWrapperPass::anchor() {}
1127
1128DXILResourceTypeWrapperPass::DXILResourceTypeWrapperPass()
1129 : ImmutablePass(ID) {}
1130
1131INITIALIZE_PASS(DXILResourceTypeWrapperPass, "dxil-resource-type",
1132 "DXIL Resource Type Analysis", false, true)
1133char DXILResourceTypeWrapperPass::ID = 0;
1134
1135ModulePass *llvm::createDXILResourceTypeWrapperPassPass() {
1136 return new DXILResourceTypeWrapperPass();
1137}
1138
1139DXILResourceWrapperPass::DXILResourceWrapperPass() : ModulePass(ID) {}
1140
1141DXILResourceWrapperPass::~DXILResourceWrapperPass() = default;
1142
1143void DXILResourceWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
1144 AU.addRequiredTransitive<DXILResourceTypeWrapperPass>();
1145 AU.setPreservesAll();
1146}
1147
1148bool DXILResourceWrapperPass::runOnModule(Module &M) {
1149 Map.reset(p: new DXILResourceMap());
1150
1151 DRTM = &getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1152 Map->populate(M, DRTM&: *DRTM);
1153
1154 return false;
1155}
1156
1157void DXILResourceWrapperPass::releaseMemory() { Map.reset(); }
1158
1159void DXILResourceWrapperPass::print(raw_ostream &OS, const Module *M) const {
1160 if (!Map) {
1161 OS << "No resource map has been built!\n";
1162 return;
1163 }
1164 Map->print(OS, DRTM&: *DRTM, DL: M->getDataLayout());
1165}
1166
1167#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1168LLVM_DUMP_METHOD
1169void DXILResourceWrapperPass::dump() const { print(dbgs(), nullptr); }
1170#endif
1171
1172INITIALIZE_PASS(DXILResourceWrapperPass, "dxil-resources",
1173 "DXIL Resources Analysis", false, true)
1174char DXILResourceWrapperPass::ID = 0;
1175
1176ModulePass *llvm::createDXILResourceWrapperPassPass() {
1177 return new DXILResourceWrapperPass();
1178}
1179
1180DXILResourceBindingWrapperPass::DXILResourceBindingWrapperPass()
1181 : ModulePass(ID) {}
1182
1183DXILResourceBindingWrapperPass::~DXILResourceBindingWrapperPass() = default;
1184
1185void DXILResourceBindingWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
1186 AU.addRequiredTransitive<DXILResourceTypeWrapperPass>();
1187 AU.setPreservesAll();
1188}
1189
1190bool DXILResourceBindingWrapperPass::runOnModule(Module &M) {
1191 BindingInfo.reset(p: new DXILResourceBindingInfo());
1192
1193 DXILResourceTypeMap &DRTM =
1194 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1195 BindingInfo->populate(M, DRTM);
1196
1197 return false;
1198}
1199
1200void DXILResourceBindingWrapperPass::releaseMemory() { BindingInfo.reset(); }
1201
1202INITIALIZE_PASS(DXILResourceBindingWrapperPass, "dxil-resource-binding",
1203 "DXIL Resource Binding Analysis", false, true)
1204char DXILResourceBindingWrapperPass::ID = 0;
1205
1206ModulePass *llvm::createDXILResourceBindingWrapperPassPass() {
1207 return new DXILResourceWrapperPass();
1208}
1209