1 //===- DXILResource.cpp - Representations of DXIL resources ---------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Analysis/DXILResource.h"
10 #include "llvm/ADT/APInt.h"
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/IR/Constants.h"
13 #include "llvm/IR/DerivedTypes.h"
14 #include "llvm/IR/DiagnosticInfo.h"
15 #include "llvm/IR/Instructions.h"
16 #include "llvm/IR/Intrinsics.h"
17 #include "llvm/IR/IntrinsicsDirectX.h"
18 #include "llvm/IR/Metadata.h"
19 #include "llvm/IR/Module.h"
20 #include "llvm/InitializePasses.h"
21 #include "llvm/Support/FormatVariadic.h"
23 #define DEBUG_TYPE "dxil-resource"
28 static StringRef
getResourceClassName(ResourceClass RC
) {
30 case ResourceClass::SRV
:
32 case ResourceClass::UAV
:
34 case ResourceClass::CBuffer
:
36 case ResourceClass::Sampler
:
39 llvm_unreachable("Unhandled ResourceClass");
42 static StringRef
getResourceKindName(ResourceKind RK
) {
44 case ResourceKind::Texture1D
:
46 case ResourceKind::Texture2D
:
48 case ResourceKind::Texture2DMS
:
50 case ResourceKind::Texture3D
:
52 case ResourceKind::TextureCube
:
54 case ResourceKind::Texture1DArray
:
55 return "Texture1DArray";
56 case ResourceKind::Texture2DArray
:
57 return "Texture2DArray";
58 case ResourceKind::Texture2DMSArray
:
59 return "Texture2DMSArray";
60 case ResourceKind::TextureCubeArray
:
61 return "TextureCubeArray";
62 case ResourceKind::TypedBuffer
:
64 case ResourceKind::RawBuffer
:
66 case ResourceKind::StructuredBuffer
:
67 return "StructuredBuffer";
68 case ResourceKind::CBuffer
:
70 case ResourceKind::Sampler
:
72 case ResourceKind::TBuffer
:
74 case ResourceKind::RTAccelerationStructure
:
75 return "RTAccelerationStructure";
76 case ResourceKind::FeedbackTexture2D
:
77 return "FeedbackTexture2D";
78 case ResourceKind::FeedbackTexture2DArray
:
79 return "FeedbackTexture2DArray";
80 case ResourceKind::NumEntries
:
81 case ResourceKind::Invalid
:
84 llvm_unreachable("Unhandled ResourceKind");
87 static StringRef
getElementTypeName(ElementType ET
) {
91 case ElementType::I16
:
93 case ElementType::U16
:
95 case ElementType::I32
:
97 case ElementType::U32
:
99 case ElementType::I64
:
101 case ElementType::U64
:
103 case ElementType::F16
:
105 case ElementType::F32
:
107 case ElementType::F64
:
109 case ElementType::SNormF16
:
111 case ElementType::UNormF16
:
113 case ElementType::SNormF32
:
115 case ElementType::UNormF32
:
117 case ElementType::SNormF64
:
119 case ElementType::UNormF64
:
121 case ElementType::PackedS8x32
:
123 case ElementType::PackedU8x32
:
125 case ElementType::Invalid
:
128 llvm_unreachable("Unhandled ElementType");
131 static StringRef
getSamplerTypeName(SamplerType ST
) {
133 case SamplerType::Default
:
135 case SamplerType::Comparison
:
137 case SamplerType::Mono
:
140 llvm_unreachable("Unhandled SamplerType");
143 static StringRef
getSamplerFeedbackTypeName(SamplerFeedbackType SFT
) {
145 case SamplerFeedbackType::MinMip
:
147 case SamplerFeedbackType::MipRegionUsed
:
148 return "MipRegionUsed";
150 llvm_unreachable("Unhandled SamplerFeedbackType");
153 static dxil::ElementType
toDXILElementType(Type
*Ty
, bool IsSigned
) {
154 // TODO: Handle unorm, snorm, and packed.
155 Ty
= Ty
->getScalarType();
157 if (Ty
->isIntegerTy()) {
158 switch (Ty
->getIntegerBitWidth()) {
160 return IsSigned
? ElementType::I16
: ElementType::U16
;
162 return IsSigned
? ElementType::I32
: ElementType::U32
;
164 return IsSigned
? ElementType::I64
: ElementType::U64
;
167 return ElementType::Invalid
;
169 } else if (Ty
->isFloatTy()) {
170 return ElementType::F32
;
171 } else if (Ty
->isDoubleTy()) {
172 return ElementType::F64
;
173 } else if (Ty
->isHalfTy()) {
174 return ElementType::F16
;
177 return ElementType::Invalid
;
180 ResourceTypeInfo::ResourceTypeInfo(TargetExtType
*HandleTy
,
181 const dxil::ResourceClass RC_
,
182 const dxil::ResourceKind Kind_
,
183 bool GloballyCoherent
, bool HasCounter
)
184 : HandleTy(HandleTy
), GloballyCoherent(GloballyCoherent
),
185 HasCounter(HasCounter
) {
186 // If we're provided a resource class and kind, trust them.
187 if (Kind_
!= dxil::ResourceKind::Invalid
) {
193 if (auto *Ty
= dyn_cast
<RawBufferExtType
>(HandleTy
)) {
194 RC
= Ty
->isWriteable() ? ResourceClass::UAV
: ResourceClass::SRV
;
195 Kind
= Ty
->isStructured() ? ResourceKind::StructuredBuffer
196 : ResourceKind::RawBuffer
;
197 } else if (auto *Ty
= dyn_cast
<TypedBufferExtType
>(HandleTy
)) {
198 RC
= Ty
->isWriteable() ? ResourceClass::UAV
: ResourceClass::SRV
;
199 Kind
= ResourceKind::TypedBuffer
;
200 } else if (auto *Ty
= dyn_cast
<TextureExtType
>(HandleTy
)) {
201 RC
= Ty
->isWriteable() ? ResourceClass::UAV
: ResourceClass::SRV
;
202 Kind
= Ty
->getDimension();
203 } else if (auto *Ty
= dyn_cast
<MSTextureExtType
>(HandleTy
)) {
204 RC
= Ty
->isWriteable() ? ResourceClass::UAV
: ResourceClass::SRV
;
205 Kind
= Ty
->getDimension();
206 } else if (auto *Ty
= dyn_cast
<FeedbackTextureExtType
>(HandleTy
)) {
207 RC
= ResourceClass::UAV
;
208 Kind
= Ty
->getDimension();
209 } else if (isa
<CBufferExtType
>(HandleTy
)) {
210 RC
= ResourceClass::CBuffer
;
211 Kind
= ResourceKind::CBuffer
;
212 } else if (isa
<SamplerExtType
>(HandleTy
)) {
213 RC
= ResourceClass::Sampler
;
214 Kind
= ResourceKind::Sampler
;
216 llvm_unreachable("Unknown handle type");
219 static void formatTypeName(SmallString
<64> &Dest
, StringRef Name
,
220 bool isWriteable
, bool isROV
) {
221 Dest
= isWriteable
? (isROV
? "RasterizerOrdered" : "RW") : "";
225 StructType
*ResourceTypeInfo::createElementStruct() {
226 SmallString
<64> TypeName
;
229 case ResourceKind::Texture1D
:
230 case ResourceKind::Texture2D
:
231 case ResourceKind::Texture3D
:
232 case ResourceKind::TextureCube
:
233 case ResourceKind::Texture1DArray
:
234 case ResourceKind::Texture2DArray
:
235 case ResourceKind::TextureCubeArray
: {
236 auto *RTy
= cast
<TextureExtType
>(HandleTy
);
237 formatTypeName(TypeName
, getResourceKindName(Kind
), RTy
->isWriteable(),
239 return StructType::create(RTy
->getResourceType(), TypeName
);
241 case ResourceKind::Texture2DMS
:
242 case ResourceKind::Texture2DMSArray
: {
243 auto *RTy
= cast
<MSTextureExtType
>(HandleTy
);
244 formatTypeName(TypeName
, getResourceKindName(Kind
), RTy
->isWriteable(),
246 return StructType::create(RTy
->getResourceType(), TypeName
);
248 case ResourceKind::TypedBuffer
: {
249 auto *RTy
= cast
<TypedBufferExtType
>(HandleTy
);
250 formatTypeName(TypeName
, getResourceKindName(Kind
), RTy
->isWriteable(),
252 return StructType::create(RTy
->getResourceType(), TypeName
);
254 case ResourceKind::RawBuffer
: {
255 auto *RTy
= cast
<RawBufferExtType
>(HandleTy
);
256 formatTypeName(TypeName
, "ByteAddressBuffer", RTy
->isWriteable(),
258 return StructType::create(Type::getInt32Ty(HandleTy
->getContext()),
261 case ResourceKind::StructuredBuffer
: {
262 auto *RTy
= cast
<RawBufferExtType
>(HandleTy
);
263 formatTypeName(TypeName
, "StructuredBuffer", RTy
->isWriteable(),
265 return StructType::create(RTy
->getResourceType(), TypeName
);
267 case ResourceKind::FeedbackTexture2D
:
268 case ResourceKind::FeedbackTexture2DArray
: {
269 auto *RTy
= cast
<FeedbackTextureExtType
>(HandleTy
);
270 TypeName
= formatv("{0}<{1}>", getResourceKindName(Kind
),
271 llvm::to_underlying(RTy
->getFeedbackType()));
272 return StructType::create(Type::getInt32Ty(HandleTy
->getContext()),
275 case ResourceKind::CBuffer
:
276 return StructType::create(HandleTy
->getContext(), "cbuffer");
277 case ResourceKind::Sampler
: {
278 auto *RTy
= cast
<SamplerExtType
>(HandleTy
);
279 TypeName
= formatv("SamplerState<{0}>",
280 llvm::to_underlying(RTy
->getSamplerType()));
281 return StructType::create(Type::getInt32Ty(HandleTy
->getContext()),
284 case ResourceKind::TBuffer
:
285 case ResourceKind::RTAccelerationStructure
:
286 llvm_unreachable("Unhandled resource kind");
287 case ResourceKind::Invalid
:
288 case ResourceKind::NumEntries
:
289 llvm_unreachable("Invalid resource kind");
291 llvm_unreachable("Unhandled ResourceKind enum");
294 bool ResourceTypeInfo::isUAV() const { return RC
== ResourceClass::UAV
; }
296 bool ResourceTypeInfo::isCBuffer() const {
297 return RC
== ResourceClass::CBuffer
;
300 bool ResourceTypeInfo::isSampler() const {
301 return RC
== ResourceClass::Sampler
;
304 bool ResourceTypeInfo::isStruct() const {
305 return Kind
== ResourceKind::StructuredBuffer
;
308 bool ResourceTypeInfo::isTyped() const {
310 case ResourceKind::Texture1D
:
311 case ResourceKind::Texture2D
:
312 case ResourceKind::Texture2DMS
:
313 case ResourceKind::Texture3D
:
314 case ResourceKind::TextureCube
:
315 case ResourceKind::Texture1DArray
:
316 case ResourceKind::Texture2DArray
:
317 case ResourceKind::Texture2DMSArray
:
318 case ResourceKind::TextureCubeArray
:
319 case ResourceKind::TypedBuffer
:
321 case ResourceKind::RawBuffer
:
322 case ResourceKind::StructuredBuffer
:
323 case ResourceKind::FeedbackTexture2D
:
324 case ResourceKind::FeedbackTexture2DArray
:
325 case ResourceKind::CBuffer
:
326 case ResourceKind::Sampler
:
327 case ResourceKind::TBuffer
:
328 case ResourceKind::RTAccelerationStructure
:
330 case ResourceKind::Invalid
:
331 case ResourceKind::NumEntries
:
332 llvm_unreachable("Invalid resource kind");
334 llvm_unreachable("Unhandled ResourceKind enum");
337 bool ResourceTypeInfo::isFeedback() const {
338 return Kind
== ResourceKind::FeedbackTexture2D
||
339 Kind
== ResourceKind::FeedbackTexture2DArray
;
342 bool ResourceTypeInfo::isMultiSample() const {
343 return Kind
== ResourceKind::Texture2DMS
||
344 Kind
== ResourceKind::Texture2DMSArray
;
347 static bool isROV(dxil::ResourceKind Kind
, TargetExtType
*Ty
) {
349 case ResourceKind::Texture1D
:
350 case ResourceKind::Texture2D
:
351 case ResourceKind::Texture3D
:
352 case ResourceKind::TextureCube
:
353 case ResourceKind::Texture1DArray
:
354 case ResourceKind::Texture2DArray
:
355 case ResourceKind::TextureCubeArray
:
356 return cast
<TextureExtType
>(Ty
)->isROV();
357 case ResourceKind::TypedBuffer
:
358 return cast
<TypedBufferExtType
>(Ty
)->isROV();
359 case ResourceKind::RawBuffer
:
360 case ResourceKind::StructuredBuffer
:
361 return cast
<RawBufferExtType
>(Ty
)->isROV();
362 case ResourceKind::Texture2DMS
:
363 case ResourceKind::Texture2DMSArray
:
364 case ResourceKind::FeedbackTexture2D
:
365 case ResourceKind::FeedbackTexture2DArray
:
367 case ResourceKind::CBuffer
:
368 case ResourceKind::Sampler
:
369 case ResourceKind::TBuffer
:
370 case ResourceKind::RTAccelerationStructure
:
371 case ResourceKind::Invalid
:
372 case ResourceKind::NumEntries
:
373 llvm_unreachable("Resource cannot be ROV");
375 llvm_unreachable("Unhandled ResourceKind enum");
378 ResourceTypeInfo::UAVInfo
ResourceTypeInfo::getUAV() const {
379 assert(isUAV() && "Not a UAV");
380 return {GloballyCoherent
, HasCounter
, isROV(Kind
, HandleTy
)};
383 uint32_t ResourceTypeInfo::getCBufferSize(const DataLayout
&DL
) const {
384 assert(isCBuffer() && "Not a CBuffer");
385 return cast
<CBufferExtType
>(HandleTy
)->getCBufferSize();
388 dxil::SamplerType
ResourceTypeInfo::getSamplerType() const {
389 assert(isSampler() && "Not a Sampler");
390 return cast
<SamplerExtType
>(HandleTy
)->getSamplerType();
393 ResourceTypeInfo::StructInfo
394 ResourceTypeInfo::getStruct(const DataLayout
&DL
) const {
395 assert(isStruct() && "Not a Struct");
397 Type
*ElTy
= cast
<RawBufferExtType
>(HandleTy
)->getResourceType();
399 uint32_t Stride
= DL
.getTypeAllocSize(ElTy
);
400 MaybeAlign Alignment
;
401 if (auto *STy
= dyn_cast
<StructType
>(ElTy
))
402 Alignment
= DL
.getStructLayout(STy
)->getAlignment();
403 uint32_t AlignLog2
= Alignment
? Log2(*Alignment
) : 0;
404 return {Stride
, AlignLog2
};
407 static std::pair
<Type
*, bool> getTypedElementType(dxil::ResourceKind Kind
,
410 case ResourceKind::Texture1D
:
411 case ResourceKind::Texture2D
:
412 case ResourceKind::Texture3D
:
413 case ResourceKind::TextureCube
:
414 case ResourceKind::Texture1DArray
:
415 case ResourceKind::Texture2DArray
:
416 case ResourceKind::TextureCubeArray
: {
417 auto *RTy
= cast
<TextureExtType
>(Ty
);
418 return {RTy
->getResourceType(), RTy
->isSigned()};
420 case ResourceKind::Texture2DMS
:
421 case ResourceKind::Texture2DMSArray
: {
422 auto *RTy
= cast
<MSTextureExtType
>(Ty
);
423 return {RTy
->getResourceType(), RTy
->isSigned()};
425 case ResourceKind::TypedBuffer
: {
426 auto *RTy
= cast
<TypedBufferExtType
>(Ty
);
427 return {RTy
->getResourceType(), RTy
->isSigned()};
429 case ResourceKind::RawBuffer
:
430 case ResourceKind::StructuredBuffer
:
431 case ResourceKind::FeedbackTexture2D
:
432 case ResourceKind::FeedbackTexture2DArray
:
433 case ResourceKind::CBuffer
:
434 case ResourceKind::Sampler
:
435 case ResourceKind::TBuffer
:
436 case ResourceKind::RTAccelerationStructure
:
437 case ResourceKind::Invalid
:
438 case ResourceKind::NumEntries
:
439 llvm_unreachable("Resource is not typed");
441 llvm_unreachable("Unhandled ResourceKind enum");
444 ResourceTypeInfo::TypedInfo
ResourceTypeInfo::getTyped() const {
445 assert(isTyped() && "Not typed");
447 auto [ElTy
, IsSigned
] = getTypedElementType(Kind
, HandleTy
);
448 dxil::ElementType ET
= toDXILElementType(ElTy
, IsSigned
);
450 if (auto *VTy
= dyn_cast
<FixedVectorType
>(ElTy
))
451 Count
= VTy
->getNumElements();
455 dxil::SamplerFeedbackType
ResourceTypeInfo::getFeedbackType() const {
456 assert(isFeedback() && "Not Feedback");
457 return cast
<FeedbackTextureExtType
>(HandleTy
)->getFeedbackType();
459 uint32_t ResourceTypeInfo::getMultiSampleCount() const {
460 assert(isMultiSample() && "Not MultiSampled");
461 return cast
<MSTextureExtType
>(HandleTy
)->getSampleCount();
464 bool ResourceTypeInfo::operator==(const ResourceTypeInfo
&RHS
) const {
465 return std::tie(HandleTy
, GloballyCoherent
, HasCounter
) ==
466 std::tie(RHS
.HandleTy
, RHS
.GloballyCoherent
, RHS
.HasCounter
);
469 bool ResourceTypeInfo::operator<(const ResourceTypeInfo
&RHS
) const {
470 // An empty datalayout is sufficient for sorting purposes.
472 if (std::tie(RC
, Kind
) < std::tie(RHS
.RC
, RHS
.Kind
))
474 if (isCBuffer() && RHS
.isCBuffer() &&
475 getCBufferSize(DummyDL
) < RHS
.getCBufferSize(DummyDL
))
477 if (isSampler() && RHS
.isSampler() && getSamplerType() < RHS
.getSamplerType())
479 if (isUAV() && RHS
.isUAV() && getUAV() < RHS
.getUAV())
481 if (isStruct() && RHS
.isStruct() &&
482 getStruct(DummyDL
) < RHS
.getStruct(DummyDL
))
484 if (isFeedback() && RHS
.isFeedback() &&
485 getFeedbackType() < RHS
.getFeedbackType())
487 if (isTyped() && RHS
.isTyped() && getTyped() < RHS
.getTyped())
489 if (isMultiSample() && RHS
.isMultiSample() &&
490 getMultiSampleCount() < RHS
.getMultiSampleCount())
495 void ResourceTypeInfo::print(raw_ostream
&OS
, const DataLayout
&DL
) const {
496 OS
<< " Class: " << getResourceClassName(RC
) << "\n"
497 << " Kind: " << getResourceKindName(Kind
) << "\n";
500 OS
<< " CBuffer size: " << getCBufferSize(DL
) << "\n";
501 } else if (isSampler()) {
502 OS
<< " Sampler Type: " << getSamplerTypeName(getSamplerType()) << "\n";
505 UAVInfo UAVFlags
= getUAV();
506 OS
<< " Globally Coherent: " << UAVFlags
.GloballyCoherent
<< "\n"
507 << " HasCounter: " << UAVFlags
.HasCounter
<< "\n"
508 << " IsROV: " << UAVFlags
.IsROV
<< "\n";
511 OS
<< " Sample Count: " << getMultiSampleCount() << "\n";
514 StructInfo Struct
= getStruct(DL
);
515 OS
<< " Buffer Stride: " << Struct
.Stride
<< "\n";
516 OS
<< " Alignment: " << Struct
.AlignLog2
<< "\n";
517 } else if (isTyped()) {
518 TypedInfo Typed
= getTyped();
519 OS
<< " Element Type: " << getElementTypeName(Typed
.ElementTy
) << "\n"
520 << " Element Count: " << Typed
.ElementCount
<< "\n";
521 } else if (isFeedback())
522 OS
<< " Feedback Type: " << getSamplerFeedbackTypeName(getFeedbackType())
527 GlobalVariable
*ResourceBindingInfo::createSymbol(Module
&M
, StructType
*Ty
,
529 assert(!Symbol
&& "Symbol has already been created");
530 Symbol
= new GlobalVariable(M
, Ty
, /*isConstant=*/true,
531 GlobalValue::ExternalLinkage
,
532 /*Initializer=*/nullptr, Name
);
536 MDTuple
*ResourceBindingInfo::getAsMetadata(Module
&M
,
537 dxil::ResourceTypeInfo
&RTI
) const {
538 LLVMContext
&Ctx
= M
.getContext();
539 const DataLayout
&DL
= M
.getDataLayout();
541 SmallVector
<Metadata
*, 11> MDVals
;
543 Type
*I32Ty
= Type::getInt32Ty(Ctx
);
544 Type
*I1Ty
= Type::getInt1Ty(Ctx
);
545 auto getIntMD
= [&I32Ty
](uint32_t V
) {
546 return ConstantAsMetadata::get(
547 Constant::getIntegerValue(I32Ty
, APInt(32, V
)));
549 auto getBoolMD
= [&I1Ty
](uint32_t V
) {
550 return ConstantAsMetadata::get(
551 Constant::getIntegerValue(I1Ty
, APInt(1, V
)));
554 MDVals
.push_back(getIntMD(Binding
.RecordID
));
555 assert(Symbol
&& "Cannot yet create useful resource metadata without symbol");
556 MDVals
.push_back(ValueAsMetadata::get(Symbol
));
557 MDVals
.push_back(MDString::get(Ctx
, Symbol
->getName()));
558 MDVals
.push_back(getIntMD(Binding
.Space
));
559 MDVals
.push_back(getIntMD(Binding
.LowerBound
));
560 MDVals
.push_back(getIntMD(Binding
.Size
));
562 if (RTI
.isCBuffer()) {
563 MDVals
.push_back(getIntMD(RTI
.getCBufferSize(DL
)));
564 MDVals
.push_back(nullptr);
565 } else if (RTI
.isSampler()) {
566 MDVals
.push_back(getIntMD(llvm::to_underlying(RTI
.getSamplerType())));
567 MDVals
.push_back(nullptr);
569 MDVals
.push_back(getIntMD(llvm::to_underlying(RTI
.getResourceKind())));
572 ResourceTypeInfo::UAVInfo UAVFlags
= RTI
.getUAV();
573 MDVals
.push_back(getBoolMD(UAVFlags
.GloballyCoherent
));
574 MDVals
.push_back(getBoolMD(UAVFlags
.HasCounter
));
575 MDVals
.push_back(getBoolMD(UAVFlags
.IsROV
));
577 // All SRVs include sample count in the metadata, but it's only meaningful
578 // for multi-sampled textured. Also, UAVs can be multisampled in SM6.7+,
579 // but this just isn't reflected in the metadata at all.
580 uint32_t SampleCount
=
581 RTI
.isMultiSample() ? RTI
.getMultiSampleCount() : 0;
582 MDVals
.push_back(getIntMD(SampleCount
));
585 // Further properties are attached to a metadata list of tag-value pairs.
586 SmallVector
<Metadata
*> Tags
;
587 if (RTI
.isStruct()) {
589 getIntMD(llvm::to_underlying(ExtPropTags::StructuredBufferStride
)));
590 Tags
.push_back(getIntMD(RTI
.getStruct(DL
).Stride
));
591 } else if (RTI
.isTyped()) {
592 Tags
.push_back(getIntMD(llvm::to_underlying(ExtPropTags::ElementType
)));
593 Tags
.push_back(getIntMD(llvm::to_underlying(RTI
.getTyped().ElementTy
)));
594 } else if (RTI
.isFeedback()) {
596 getIntMD(llvm::to_underlying(ExtPropTags::SamplerFeedbackKind
)));
597 Tags
.push_back(getIntMD(llvm::to_underlying(RTI
.getFeedbackType())));
599 MDVals
.push_back(Tags
.empty() ? nullptr : MDNode::get(Ctx
, Tags
));
602 return MDNode::get(Ctx
, MDVals
);
605 std::pair
<uint32_t, uint32_t>
606 ResourceBindingInfo::getAnnotateProps(Module
&M
,
607 dxil::ResourceTypeInfo
&RTI
) const {
608 const DataLayout
&DL
= M
.getDataLayout();
610 uint32_t ResourceKind
= llvm::to_underlying(RTI
.getResourceKind());
611 uint32_t AlignLog2
= RTI
.isStruct() ? RTI
.getStruct(DL
).AlignLog2
: 0;
612 bool IsUAV
= RTI
.isUAV();
613 ResourceTypeInfo::UAVInfo UAVFlags
=
614 IsUAV
? RTI
.getUAV() : ResourceTypeInfo::UAVInfo
{};
615 bool IsROV
= IsUAV
&& UAVFlags
.IsROV
;
616 bool IsGloballyCoherent
= IsUAV
&& UAVFlags
.GloballyCoherent
;
617 uint8_t SamplerCmpOrHasCounter
= 0;
619 SamplerCmpOrHasCounter
= UAVFlags
.HasCounter
;
620 else if (RTI
.isSampler())
621 SamplerCmpOrHasCounter
= RTI
.getSamplerType() == SamplerType::Comparison
;
623 // TODO: Document this format. Currently the only reference is the
624 // implementation of dxc's DxilResourceProperties struct.
626 Word0
|= ResourceKind
& 0xFF;
627 Word0
|= (AlignLog2
& 0xF) << 8;
628 Word0
|= (IsUAV
& 1) << 12;
629 Word0
|= (IsROV
& 1) << 13;
630 Word0
|= (IsGloballyCoherent
& 1) << 14;
631 Word0
|= (SamplerCmpOrHasCounter
& 1) << 15;
635 Word1
= RTI
.getStruct(DL
).Stride
;
636 else if (RTI
.isCBuffer())
637 Word1
= RTI
.getCBufferSize(DL
);
638 else if (RTI
.isFeedback())
639 Word1
= llvm::to_underlying(RTI
.getFeedbackType());
640 else if (RTI
.isTyped()) {
641 ResourceTypeInfo::TypedInfo Typed
= RTI
.getTyped();
642 uint32_t CompType
= llvm::to_underlying(Typed
.ElementTy
);
643 uint32_t CompCount
= Typed
.ElementCount
;
644 uint32_t SampleCount
= RTI
.isMultiSample() ? RTI
.getMultiSampleCount() : 0;
646 Word1
|= (CompType
& 0xFF) << 0;
647 Word1
|= (CompCount
& 0xFF) << 8;
648 Word1
|= (SampleCount
& 0xFF) << 16;
651 return {Word0
, Word1
};
654 void ResourceBindingInfo::print(raw_ostream
&OS
, dxil::ResourceTypeInfo
&RTI
,
655 const DataLayout
&DL
) const {
658 Symbol
->printAsOperand(OS
);
663 << " Record ID: " << Binding
.RecordID
<< "\n"
664 << " Space: " << Binding
.Space
<< "\n"
665 << " Lower Bound: " << Binding
.LowerBound
<< "\n"
666 << " Size: " << Binding
.Size
<< "\n";
671 //===----------------------------------------------------------------------===//
673 bool DXILResourceTypeMap::invalidate(Module
&M
, const PreservedAnalyses
&PA
,
674 ModuleAnalysisManager::Invalidator
&Inv
) {
675 // Passes that introduce resource types must explicitly invalidate this pass.
676 auto PAC
= PA
.getChecker
<DXILResourceTypeAnalysis
>();
677 return !PAC
.preservedWhenStateless();
680 //===----------------------------------------------------------------------===//
682 void DXILBindingMap::populate(Module
&M
, DXILResourceTypeMap
&DRTM
) {
683 SmallVector
<std::tuple
<CallInst
*, ResourceBindingInfo
, ResourceTypeInfo
>>
686 for (Function
&F
: M
.functions()) {
687 if (!F
.isDeclaration())
689 LLVM_DEBUG(dbgs() << "Function: " << F
.getName() << "\n");
690 Intrinsic::ID ID
= F
.getIntrinsicID();
694 case Intrinsic::dx_resource_handlefrombinding
: {
695 auto *HandleTy
= cast
<TargetExtType
>(F
.getReturnType());
696 ResourceTypeInfo
&RTI
= DRTM
[HandleTy
];
698 for (User
*U
: F
.users())
699 if (CallInst
*CI
= dyn_cast
<CallInst
>(U
)) {
700 LLVM_DEBUG(dbgs() << " Visiting: " << *U
<< "\n");
702 cast
<ConstantInt
>(CI
->getArgOperand(0))->getZExtValue();
703 uint32_t LowerBound
=
704 cast
<ConstantInt
>(CI
->getArgOperand(1))->getZExtValue();
706 cast
<ConstantInt
>(CI
->getArgOperand(2))->getZExtValue();
707 ResourceBindingInfo RBI
= ResourceBindingInfo
{
708 /*RecordID=*/0, Space
, LowerBound
, Size
, HandleTy
};
710 CIToInfos
.emplace_back(CI
, RBI
, RTI
);
718 llvm::stable_sort(CIToInfos
, [](auto &LHS
, auto &RHS
) {
719 const auto &[LCI
, LRBI
, LRTI
] = LHS
;
720 const auto &[RCI
, RRBI
, RRTI
] = RHS
;
721 // Sort by resource class first for grouping purposes, and then by the
722 // binding and type so we can remove duplicates.
723 ResourceClass LRC
= LRTI
.getResourceClass();
724 ResourceClass RRC
= RRTI
.getResourceClass();
726 return std::tie(LRC
, LRBI
, LRTI
) < std::tie(RRC
, RRBI
, RRTI
);
728 for (auto [CI
, RBI
, RTI
] : CIToInfos
) {
729 if (Infos
.empty() || RBI
!= Infos
.back())
730 Infos
.push_back(RBI
);
731 CallMap
[CI
] = Infos
.size() - 1;
734 unsigned Size
= Infos
.size();
735 // In DXC, Record ID is unique per resource type. Match that.
736 FirstUAV
= FirstCBuffer
= FirstSampler
= Size
;
738 for (unsigned I
= 0, E
= Size
; I
!= E
; ++I
) {
739 ResourceBindingInfo
&RBI
= Infos
[I
];
740 ResourceTypeInfo
&RTI
= DRTM
[RBI
.getHandleTy()];
741 if (RTI
.isUAV() && FirstUAV
== Size
) {
744 } else if (RTI
.isCBuffer() && FirstCBuffer
== Size
) {
747 } else if (RTI
.isSampler() && FirstSampler
== Size
) {
752 // Adjust the resource binding to use the next ID.
753 RBI
.setBindingID(NextID
++);
757 void DXILBindingMap::print(raw_ostream
&OS
, DXILResourceTypeMap
&DRTM
,
758 const DataLayout
&DL
) const {
759 for (unsigned I
= 0, E
= Infos
.size(); I
!= E
; ++I
) {
760 OS
<< "Binding " << I
<< ":\n";
761 const dxil::ResourceBindingInfo
&RBI
= Infos
[I
];
762 RBI
.print(OS
, DRTM
[RBI
.getHandleTy()], DL
);
766 for (const auto &[CI
, Index
] : CallMap
) {
767 OS
<< "Call bound to " << Index
<< ":";
773 //===----------------------------------------------------------------------===//
775 AnalysisKey
DXILResourceTypeAnalysis::Key
;
776 AnalysisKey
DXILResourceBindingAnalysis::Key
;
778 DXILBindingMap
DXILResourceBindingAnalysis::run(Module
&M
,
779 ModuleAnalysisManager
&AM
) {
781 DXILResourceTypeMap
&DRTM
= AM
.getResult
<DXILResourceTypeAnalysis
>(M
);
782 Data
.populate(M
, DRTM
);
787 DXILResourceBindingPrinterPass::run(Module
&M
, ModuleAnalysisManager
&AM
) {
788 DXILBindingMap
&DBM
= AM
.getResult
<DXILResourceBindingAnalysis
>(M
);
789 DXILResourceTypeMap
&DRTM
= AM
.getResult
<DXILResourceTypeAnalysis
>(M
);
791 DBM
.print(OS
, DRTM
, M
.getDataLayout());
792 return PreservedAnalyses::all();
795 void DXILResourceTypeWrapperPass::anchor() {}
797 DXILResourceTypeWrapperPass::DXILResourceTypeWrapperPass() : ImmutablePass(ID
) {
798 initializeDXILResourceTypeWrapperPassPass(*PassRegistry::getPassRegistry());
801 INITIALIZE_PASS(DXILResourceTypeWrapperPass
, "dxil-resource-type",
802 "DXIL Resource Type Analysis", false, true)
803 char DXILResourceTypeWrapperPass::ID
= 0;
805 ModulePass
*llvm::createDXILResourceTypeWrapperPassPass() {
806 return new DXILResourceTypeWrapperPass();
809 DXILResourceBindingWrapperPass::DXILResourceBindingWrapperPass()
811 initializeDXILResourceBindingWrapperPassPass(
812 *PassRegistry::getPassRegistry());
815 DXILResourceBindingWrapperPass::~DXILResourceBindingWrapperPass() = default;
817 void DXILResourceBindingWrapperPass::getAnalysisUsage(AnalysisUsage
&AU
) const {
818 AU
.addRequiredTransitive
<DXILResourceTypeWrapperPass
>();
819 AU
.setPreservesAll();
822 bool DXILResourceBindingWrapperPass::runOnModule(Module
&M
) {
823 Map
.reset(new DXILBindingMap());
825 DRTM
= &getAnalysis
<DXILResourceTypeWrapperPass
>().getResourceTypeMap();
826 Map
->populate(M
, *DRTM
);
831 void DXILResourceBindingWrapperPass::releaseMemory() { Map
.reset(); }
833 void DXILResourceBindingWrapperPass::print(raw_ostream
&OS
,
834 const Module
*M
) const {
836 OS
<< "No resource map has been built!\n";
839 Map
->print(OS
, *DRTM
, M
->getDataLayout());
842 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
844 void DXILResourceBindingWrapperPass::dump() const { print(dbgs(), nullptr); }
847 INITIALIZE_PASS(DXILResourceBindingWrapperPass
, "dxil-resource-binding",
848 "DXIL Resource Binding Analysis", false, true)
849 char DXILResourceBindingWrapperPass::ID
= 0;
851 ModulePass
*llvm::createDXILResourceBindingWrapperPassPass() {
852 return new DXILResourceBindingWrapperPass();