[mlir][linalg] Add support for masked vectorization of `tensor.insert_slice` (1/N...
[llvm-project.git] / llvm / lib / Analysis / DXILResource.cpp
blob7f28e63cc117d4c5b8143f76fbf6fed687f45605
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 //===----------------------------------------------------------------------===//
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"
25 using namespace llvm;
26 using namespace dxil;
28 static StringRef getResourceClassName(ResourceClass RC) {
29 switch (RC) {
30 case ResourceClass::SRV:
31 return "SRV";
32 case ResourceClass::UAV:
33 return "UAV";
34 case ResourceClass::CBuffer:
35 return "CBuffer";
36 case ResourceClass::Sampler:
37 return "Sampler";
39 llvm_unreachable("Unhandled ResourceClass");
42 static StringRef getResourceKindName(ResourceKind RK) {
43 switch (RK) {
44 case ResourceKind::Texture1D:
45 return "Texture1D";
46 case ResourceKind::Texture2D:
47 return "Texture2D";
48 case ResourceKind::Texture2DMS:
49 return "Texture2DMS";
50 case ResourceKind::Texture3D:
51 return "Texture3D";
52 case ResourceKind::TextureCube:
53 return "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:
63 return "TypedBuffer";
64 case ResourceKind::RawBuffer:
65 return "RawBuffer";
66 case ResourceKind::StructuredBuffer:
67 return "StructuredBuffer";
68 case ResourceKind::CBuffer:
69 return "CBuffer";
70 case ResourceKind::Sampler:
71 return "Sampler";
72 case ResourceKind::TBuffer:
73 return "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:
82 return "<invalid>";
84 llvm_unreachable("Unhandled ResourceKind");
87 static StringRef getElementTypeName(ElementType ET) {
88 switch (ET) {
89 case ElementType::I1:
90 return "i1";
91 case ElementType::I16:
92 return "i16";
93 case ElementType::U16:
94 return "u16";
95 case ElementType::I32:
96 return "i32";
97 case ElementType::U32:
98 return "u32";
99 case ElementType::I64:
100 return "i64";
101 case ElementType::U64:
102 return "u64";
103 case ElementType::F16:
104 return "f16";
105 case ElementType::F32:
106 return "f32";
107 case ElementType::F64:
108 return "f64";
109 case ElementType::SNormF16:
110 return "snorm_f16";
111 case ElementType::UNormF16:
112 return "unorm_f16";
113 case ElementType::SNormF32:
114 return "snorm_f32";
115 case ElementType::UNormF32:
116 return "unorm_f32";
117 case ElementType::SNormF64:
118 return "snorm_f64";
119 case ElementType::UNormF64:
120 return "unorm_f64";
121 case ElementType::PackedS8x32:
122 return "p32i8";
123 case ElementType::PackedU8x32:
124 return "p32u8";
125 case ElementType::Invalid:
126 return "<invalid>";
128 llvm_unreachable("Unhandled ElementType");
131 static StringRef getSamplerTypeName(SamplerType ST) {
132 switch (ST) {
133 case SamplerType::Default:
134 return "Default";
135 case SamplerType::Comparison:
136 return "Comparison";
137 case SamplerType::Mono:
138 return "Mono";
140 llvm_unreachable("Unhandled SamplerType");
143 static StringRef getSamplerFeedbackTypeName(SamplerFeedbackType SFT) {
144 switch (SFT) {
145 case SamplerFeedbackType::MinMip:
146 return "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()) {
159 case 16:
160 return IsSigned ? ElementType::I16 : ElementType::U16;
161 case 32:
162 return IsSigned ? ElementType::I32 : ElementType::U32;
163 case 64:
164 return IsSigned ? ElementType::I64 : ElementType::U64;
165 case 1:
166 default:
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) {
188 RC = RC_;
189 Kind = Kind_;
190 return;
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;
215 } else
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") : "";
222 Dest += Name;
225 StructType *ResourceTypeInfo::createElementStruct() {
226 SmallString<64> TypeName;
228 switch (Kind) {
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(),
238 RTy->isROV());
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(),
245 /*IsROV=*/false);
246 return StructType::create(RTy->getResourceType(), TypeName);
248 case ResourceKind::TypedBuffer: {
249 auto *RTy = cast<TypedBufferExtType>(HandleTy);
250 formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
251 RTy->isROV());
252 return StructType::create(RTy->getResourceType(), TypeName);
254 case ResourceKind::RawBuffer: {
255 auto *RTy = cast<RawBufferExtType>(HandleTy);
256 formatTypeName(TypeName, "ByteAddressBuffer", RTy->isWriteable(),
257 RTy->isROV());
258 return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
259 TypeName);
261 case ResourceKind::StructuredBuffer: {
262 auto *RTy = cast<RawBufferExtType>(HandleTy);
263 formatTypeName(TypeName, "StructuredBuffer", RTy->isWriteable(),
264 RTy->isROV());
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()),
273 TypeName);
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()),
282 TypeName);
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 {
309 switch (Kind) {
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:
320 return true;
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:
329 return false;
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) {
348 switch (Kind) {
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:
366 return false;
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,
408 TargetExtType *Ty) {
409 switch (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);
449 uint32_t Count = 1;
450 if (auto *VTy = dyn_cast<FixedVectorType>(ElTy))
451 Count = VTy->getNumElements();
452 return {ET, Count};
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.
471 DataLayout DummyDL;
472 if (std::tie(RC, Kind) < std::tie(RHS.RC, RHS.Kind))
473 return true;
474 if (isCBuffer() && RHS.isCBuffer() &&
475 getCBufferSize(DummyDL) < RHS.getCBufferSize(DummyDL))
476 return true;
477 if (isSampler() && RHS.isSampler() && getSamplerType() < RHS.getSamplerType())
478 return true;
479 if (isUAV() && RHS.isUAV() && getUAV() < RHS.getUAV())
480 return true;
481 if (isStruct() && RHS.isStruct() &&
482 getStruct(DummyDL) < RHS.getStruct(DummyDL))
483 return true;
484 if (isFeedback() && RHS.isFeedback() &&
485 getFeedbackType() < RHS.getFeedbackType())
486 return true;
487 if (isTyped() && RHS.isTyped() && getTyped() < RHS.getTyped())
488 return true;
489 if (isMultiSample() && RHS.isMultiSample() &&
490 getMultiSampleCount() < RHS.getMultiSampleCount())
491 return true;
492 return false;
495 void ResourceTypeInfo::print(raw_ostream &OS, const DataLayout &DL) const {
496 OS << " Class: " << getResourceClassName(RC) << "\n"
497 << " Kind: " << getResourceKindName(Kind) << "\n";
499 if (isCBuffer()) {
500 OS << " CBuffer size: " << getCBufferSize(DL) << "\n";
501 } else if (isSampler()) {
502 OS << " Sampler Type: " << getSamplerTypeName(getSamplerType()) << "\n";
503 } else {
504 if (isUAV()) {
505 UAVInfo UAVFlags = getUAV();
506 OS << " Globally Coherent: " << UAVFlags.GloballyCoherent << "\n"
507 << " HasCounter: " << UAVFlags.HasCounter << "\n"
508 << " IsROV: " << UAVFlags.IsROV << "\n";
510 if (isMultiSample())
511 OS << " Sample Count: " << getMultiSampleCount() << "\n";
513 if (isStruct()) {
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())
523 << "\n";
527 GlobalVariable *ResourceBindingInfo::createSymbol(Module &M, StructType *Ty,
528 StringRef Name) {
529 assert(!Symbol && "Symbol has already been created");
530 Symbol = new GlobalVariable(M, Ty, /*isConstant=*/true,
531 GlobalValue::ExternalLinkage,
532 /*Initializer=*/nullptr, Name);
533 return Symbol;
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);
568 } else {
569 MDVals.push_back(getIntMD(llvm::to_underlying(RTI.getResourceKind())));
571 if (RTI.isUAV()) {
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));
576 } else {
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()) {
588 Tags.push_back(
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()) {
595 Tags.push_back(
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;
618 if (IsUAV)
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.
625 uint32_t Word0 = 0;
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;
633 uint32_t Word1 = 0;
634 if (RTI.isStruct())
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 {
656 if (Symbol) {
657 OS << " Symbol: ";
658 Symbol->printAsOperand(OS);
659 OS << "\n";
662 OS << " Binding:\n"
663 << " Record ID: " << Binding.RecordID << "\n"
664 << " Space: " << Binding.Space << "\n"
665 << " Lower Bound: " << Binding.LowerBound << "\n"
666 << " Size: " << Binding.Size << "\n";
668 RTI.print(OS, DL);
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>>
684 CIToInfos;
686 for (Function &F : M.functions()) {
687 if (!F.isDeclaration())
688 continue;
689 LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
690 Intrinsic::ID ID = F.getIntrinsicID();
691 switch (ID) {
692 default:
693 continue;
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");
701 uint32_t Space =
702 cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue();
703 uint32_t LowerBound =
704 cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue();
705 uint32_t Size =
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);
713 break;
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;
737 uint32_t NextID = 0;
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) {
742 FirstUAV = I;
743 NextID = 0;
744 } else if (RTI.isCBuffer() && FirstCBuffer == Size) {
745 FirstCBuffer = I;
746 NextID = 0;
747 } else if (RTI.isSampler() && FirstSampler == Size) {
748 FirstSampler = I;
749 NextID = 0;
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);
763 OS << "\n";
766 for (const auto &[CI, Index] : CallMap) {
767 OS << "Call bound to " << Index << ":";
768 CI->print(OS);
769 OS << "\n";
773 //===----------------------------------------------------------------------===//
775 AnalysisKey DXILResourceTypeAnalysis::Key;
776 AnalysisKey DXILResourceBindingAnalysis::Key;
778 DXILBindingMap DXILResourceBindingAnalysis::run(Module &M,
779 ModuleAnalysisManager &AM) {
780 DXILBindingMap Data;
781 DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);
782 Data.populate(M, DRTM);
783 return Data;
786 PreservedAnalyses
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()
810 : ModulePass(ID) {
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);
828 return false;
831 void DXILResourceBindingWrapperPass::releaseMemory() { Map.reset(); }
833 void DXILResourceBindingWrapperPass::print(raw_ostream &OS,
834 const Module *M) const {
835 if (!Map) {
836 OS << "No resource map has been built!\n";
837 return;
839 Map->print(OS, *DRTM, M->getDataLayout());
842 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
843 LLVM_DUMP_METHOD
844 void DXILResourceBindingWrapperPass::dump() const { print(dbgs(), nullptr); }
845 #endif
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();