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