xref: /llvm-project/llvm/lib/Analysis/DXILResource.cpp (revision aa07f922103ebe8e78c8da4c754b43af3c129f3e)
1b365dbbdSJustin Bogner //===- DXILResource.cpp - Representations of DXIL resources ---------------===//
2b365dbbdSJustin Bogner //
3b365dbbdSJustin Bogner // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b365dbbdSJustin Bogner // See https://llvm.org/LICENSE.txt for license information.
5b365dbbdSJustin Bogner // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b365dbbdSJustin Bogner //
7b365dbbdSJustin Bogner //===----------------------------------------------------------------------===//
8b365dbbdSJustin Bogner 
9b365dbbdSJustin Bogner #include "llvm/Analysis/DXILResource.h"
10b365dbbdSJustin Bogner #include "llvm/ADT/APInt.h"
11482237e8SJustin Bogner #include "llvm/ADT/SmallString.h"
1251ede55eSJustin Bogner #include "llvm/IR/Constants.h"
13b365dbbdSJustin Bogner #include "llvm/IR/DerivedTypes.h"
1451ede55eSJustin Bogner #include "llvm/IR/DiagnosticInfo.h"
15372ddcd1SJustin Bogner #include "llvm/IR/Instructions.h"
1651ede55eSJustin Bogner #include "llvm/IR/Intrinsics.h"
1751ede55eSJustin Bogner #include "llvm/IR/IntrinsicsDirectX.h"
1882c21f08SJustin Bogner #include "llvm/IR/Metadata.h"
1951ede55eSJustin Bogner #include "llvm/IR/Module.h"
20372ddcd1SJustin Bogner #include "llvm/InitializePasses.h"
21482237e8SJustin Bogner #include "llvm/Support/FormatVariadic.h"
22372ddcd1SJustin Bogner 
23372ddcd1SJustin Bogner #define DEBUG_TYPE "dxil-resource"
24b365dbbdSJustin Bogner 
25b365dbbdSJustin Bogner using namespace llvm;
26b365dbbdSJustin Bogner using namespace dxil;
27b365dbbdSJustin Bogner 
2851ede55eSJustin Bogner static StringRef getResourceClassName(ResourceClass RC) {
2951ede55eSJustin Bogner   switch (RC) {
3051ede55eSJustin Bogner   case ResourceClass::SRV:
3151ede55eSJustin Bogner     return "SRV";
3251ede55eSJustin Bogner   case ResourceClass::UAV:
3351ede55eSJustin Bogner     return "UAV";
3451ede55eSJustin Bogner   case ResourceClass::CBuffer:
3551ede55eSJustin Bogner     return "CBuffer";
3651ede55eSJustin Bogner   case ResourceClass::Sampler:
3751ede55eSJustin Bogner     return "Sampler";
3851ede55eSJustin Bogner   }
3951ede55eSJustin Bogner   llvm_unreachable("Unhandled ResourceClass");
4051ede55eSJustin Bogner }
4151ede55eSJustin Bogner 
4251ede55eSJustin Bogner static StringRef getResourceKindName(ResourceKind RK) {
4351ede55eSJustin Bogner   switch (RK) {
4451ede55eSJustin Bogner   case ResourceKind::Texture1D:
4551ede55eSJustin Bogner     return "Texture1D";
4651ede55eSJustin Bogner   case ResourceKind::Texture2D:
4751ede55eSJustin Bogner     return "Texture2D";
4851ede55eSJustin Bogner   case ResourceKind::Texture2DMS:
4951ede55eSJustin Bogner     return "Texture2DMS";
5051ede55eSJustin Bogner   case ResourceKind::Texture3D:
5151ede55eSJustin Bogner     return "Texture3D";
5251ede55eSJustin Bogner   case ResourceKind::TextureCube:
5351ede55eSJustin Bogner     return "TextureCube";
5451ede55eSJustin Bogner   case ResourceKind::Texture1DArray:
5551ede55eSJustin Bogner     return "Texture1DArray";
5651ede55eSJustin Bogner   case ResourceKind::Texture2DArray:
5751ede55eSJustin Bogner     return "Texture2DArray";
5851ede55eSJustin Bogner   case ResourceKind::Texture2DMSArray:
5951ede55eSJustin Bogner     return "Texture2DMSArray";
6051ede55eSJustin Bogner   case ResourceKind::TextureCubeArray:
6151ede55eSJustin Bogner     return "TextureCubeArray";
6251ede55eSJustin Bogner   case ResourceKind::TypedBuffer:
6351ede55eSJustin Bogner     return "TypedBuffer";
6451ede55eSJustin Bogner   case ResourceKind::RawBuffer:
6551ede55eSJustin Bogner     return "RawBuffer";
6651ede55eSJustin Bogner   case ResourceKind::StructuredBuffer:
6751ede55eSJustin Bogner     return "StructuredBuffer";
6851ede55eSJustin Bogner   case ResourceKind::CBuffer:
6951ede55eSJustin Bogner     return "CBuffer";
7051ede55eSJustin Bogner   case ResourceKind::Sampler:
7151ede55eSJustin Bogner     return "Sampler";
7251ede55eSJustin Bogner   case ResourceKind::TBuffer:
7351ede55eSJustin Bogner     return "TBuffer";
7451ede55eSJustin Bogner   case ResourceKind::RTAccelerationStructure:
7551ede55eSJustin Bogner     return "RTAccelerationStructure";
7651ede55eSJustin Bogner   case ResourceKind::FeedbackTexture2D:
7751ede55eSJustin Bogner     return "FeedbackTexture2D";
7851ede55eSJustin Bogner   case ResourceKind::FeedbackTexture2DArray:
7951ede55eSJustin Bogner     return "FeedbackTexture2DArray";
8051ede55eSJustin Bogner   case ResourceKind::NumEntries:
8151ede55eSJustin Bogner   case ResourceKind::Invalid:
8251ede55eSJustin Bogner     return "<invalid>";
8351ede55eSJustin Bogner   }
8451ede55eSJustin Bogner   llvm_unreachable("Unhandled ResourceKind");
8551ede55eSJustin Bogner }
8651ede55eSJustin Bogner 
8751ede55eSJustin Bogner static StringRef getElementTypeName(ElementType ET) {
8851ede55eSJustin Bogner   switch (ET) {
8951ede55eSJustin Bogner   case ElementType::I1:
9051ede55eSJustin Bogner     return "i1";
9151ede55eSJustin Bogner   case ElementType::I16:
9251ede55eSJustin Bogner     return "i16";
9351ede55eSJustin Bogner   case ElementType::U16:
9451ede55eSJustin Bogner     return "u16";
9551ede55eSJustin Bogner   case ElementType::I32:
9651ede55eSJustin Bogner     return "i32";
9751ede55eSJustin Bogner   case ElementType::U32:
9851ede55eSJustin Bogner     return "u32";
9951ede55eSJustin Bogner   case ElementType::I64:
10051ede55eSJustin Bogner     return "i64";
10151ede55eSJustin Bogner   case ElementType::U64:
10251ede55eSJustin Bogner     return "u64";
10351ede55eSJustin Bogner   case ElementType::F16:
10451ede55eSJustin Bogner     return "f16";
10551ede55eSJustin Bogner   case ElementType::F32:
10651ede55eSJustin Bogner     return "f32";
10751ede55eSJustin Bogner   case ElementType::F64:
10851ede55eSJustin Bogner     return "f64";
10951ede55eSJustin Bogner   case ElementType::SNormF16:
11051ede55eSJustin Bogner     return "snorm_f16";
11151ede55eSJustin Bogner   case ElementType::UNormF16:
11251ede55eSJustin Bogner     return "unorm_f16";
11351ede55eSJustin Bogner   case ElementType::SNormF32:
11451ede55eSJustin Bogner     return "snorm_f32";
11551ede55eSJustin Bogner   case ElementType::UNormF32:
11651ede55eSJustin Bogner     return "unorm_f32";
11751ede55eSJustin Bogner   case ElementType::SNormF64:
11851ede55eSJustin Bogner     return "snorm_f64";
11951ede55eSJustin Bogner   case ElementType::UNormF64:
12051ede55eSJustin Bogner     return "unorm_f64";
12151ede55eSJustin Bogner   case ElementType::PackedS8x32:
12251ede55eSJustin Bogner     return "p32i8";
12351ede55eSJustin Bogner   case ElementType::PackedU8x32:
12451ede55eSJustin Bogner     return "p32u8";
12551ede55eSJustin Bogner   case ElementType::Invalid:
12651ede55eSJustin Bogner     return "<invalid>";
12751ede55eSJustin Bogner   }
12851ede55eSJustin Bogner   llvm_unreachable("Unhandled ElementType");
12951ede55eSJustin Bogner }
13051ede55eSJustin Bogner 
13151ede55eSJustin Bogner static StringRef getSamplerTypeName(SamplerType ST) {
13251ede55eSJustin Bogner   switch (ST) {
13351ede55eSJustin Bogner   case SamplerType::Default:
13451ede55eSJustin Bogner     return "Default";
13551ede55eSJustin Bogner   case SamplerType::Comparison:
13651ede55eSJustin Bogner     return "Comparison";
13751ede55eSJustin Bogner   case SamplerType::Mono:
13851ede55eSJustin Bogner     return "Mono";
13951ede55eSJustin Bogner   }
14051ede55eSJustin Bogner   llvm_unreachable("Unhandled SamplerType");
14151ede55eSJustin Bogner }
14251ede55eSJustin Bogner 
14351ede55eSJustin Bogner static StringRef getSamplerFeedbackTypeName(SamplerFeedbackType SFT) {
14451ede55eSJustin Bogner   switch (SFT) {
14551ede55eSJustin Bogner   case SamplerFeedbackType::MinMip:
14651ede55eSJustin Bogner     return "MinMip";
14751ede55eSJustin Bogner   case SamplerFeedbackType::MipRegionUsed:
14851ede55eSJustin Bogner     return "MipRegionUsed";
14951ede55eSJustin Bogner   }
15051ede55eSJustin Bogner   llvm_unreachable("Unhandled SamplerFeedbackType");
15151ede55eSJustin Bogner }
15251ede55eSJustin Bogner 
153482237e8SJustin Bogner static dxil::ElementType toDXILElementType(Type *Ty, bool IsSigned) {
154482237e8SJustin Bogner   // TODO: Handle unorm, snorm, and packed.
155482237e8SJustin Bogner   Ty = Ty->getScalarType();
156482237e8SJustin Bogner 
157482237e8SJustin Bogner   if (Ty->isIntegerTy()) {
158482237e8SJustin Bogner     switch (Ty->getIntegerBitWidth()) {
159482237e8SJustin Bogner     case 16:
160482237e8SJustin Bogner       return IsSigned ? ElementType::I16 : ElementType::U16;
161482237e8SJustin Bogner     case 32:
162482237e8SJustin Bogner       return IsSigned ? ElementType::I32 : ElementType::U32;
163482237e8SJustin Bogner     case 64:
164482237e8SJustin Bogner       return IsSigned ? ElementType::I64 : ElementType::U64;
165482237e8SJustin Bogner     case 1:
166482237e8SJustin Bogner     default:
167482237e8SJustin Bogner       return ElementType::Invalid;
168482237e8SJustin Bogner     }
169482237e8SJustin Bogner   } else if (Ty->isFloatTy()) {
170482237e8SJustin Bogner     return ElementType::F32;
171482237e8SJustin Bogner   } else if (Ty->isDoubleTy()) {
172482237e8SJustin Bogner     return ElementType::F64;
173482237e8SJustin Bogner   } else if (Ty->isHalfTy()) {
174482237e8SJustin Bogner     return ElementType::F16;
175482237e8SJustin Bogner   }
176482237e8SJustin Bogner 
177482237e8SJustin Bogner   return ElementType::Invalid;
178482237e8SJustin Bogner }
179482237e8SJustin Bogner 
1803eca15cbSJustin Bogner ResourceTypeInfo::ResourceTypeInfo(TargetExtType *HandleTy,
1813eca15cbSJustin Bogner                                    const dxil::ResourceClass RC_,
1823eca15cbSJustin Bogner                                    const dxil::ResourceKind Kind_,
1833eca15cbSJustin Bogner                                    bool GloballyCoherent, bool HasCounter)
1843eca15cbSJustin Bogner     : HandleTy(HandleTy), GloballyCoherent(GloballyCoherent),
1853eca15cbSJustin Bogner       HasCounter(HasCounter) {
1863eca15cbSJustin Bogner   // If we're provided a resource class and kind, trust them.
1873eca15cbSJustin Bogner   if (Kind_ != dxil::ResourceKind::Invalid) {
1883eca15cbSJustin Bogner     RC = RC_;
1893eca15cbSJustin Bogner     Kind = Kind_;
1903eca15cbSJustin Bogner     return;
1913eca15cbSJustin Bogner   }
1923eca15cbSJustin Bogner 
193482237e8SJustin Bogner   if (auto *Ty = dyn_cast<RawBufferExtType>(HandleTy)) {
194482237e8SJustin Bogner     RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
195482237e8SJustin Bogner     Kind = Ty->isStructured() ? ResourceKind::StructuredBuffer
196482237e8SJustin Bogner                               : ResourceKind::RawBuffer;
197482237e8SJustin Bogner   } else if (auto *Ty = dyn_cast<TypedBufferExtType>(HandleTy)) {
198482237e8SJustin Bogner     RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
199482237e8SJustin Bogner     Kind = ResourceKind::TypedBuffer;
200482237e8SJustin Bogner   } else if (auto *Ty = dyn_cast<TextureExtType>(HandleTy)) {
201482237e8SJustin Bogner     RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
202482237e8SJustin Bogner     Kind = Ty->getDimension();
203482237e8SJustin Bogner   } else if (auto *Ty = dyn_cast<MSTextureExtType>(HandleTy)) {
204482237e8SJustin Bogner     RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
205482237e8SJustin Bogner     Kind = Ty->getDimension();
206482237e8SJustin Bogner   } else if (auto *Ty = dyn_cast<FeedbackTextureExtType>(HandleTy)) {
207482237e8SJustin Bogner     RC = ResourceClass::UAV;
208482237e8SJustin Bogner     Kind = Ty->getDimension();
209482237e8SJustin Bogner   } else if (isa<CBufferExtType>(HandleTy)) {
210482237e8SJustin Bogner     RC = ResourceClass::CBuffer;
211482237e8SJustin Bogner     Kind = ResourceKind::CBuffer;
212482237e8SJustin Bogner   } else if (isa<SamplerExtType>(HandleTy)) {
213482237e8SJustin Bogner     RC = ResourceClass::Sampler;
214482237e8SJustin Bogner     Kind = ResourceKind::Sampler;
215482237e8SJustin Bogner   } else
216482237e8SJustin Bogner     llvm_unreachable("Unknown handle type");
217482237e8SJustin Bogner }
218482237e8SJustin Bogner 
2190e2466f6SJustin Bogner static void formatTypeName(SmallString<64> &Dest, StringRef Name,
2200e2466f6SJustin Bogner                            bool isWriteable, bool isROV) {
2210e2466f6SJustin Bogner   Dest = isWriteable ? (isROV ? "RasterizerOrdered" : "RW") : "";
2220e2466f6SJustin Bogner   Dest += Name;
2230e2466f6SJustin Bogner }
2240e2466f6SJustin Bogner 
2250e2466f6SJustin Bogner StructType *ResourceTypeInfo::createElementStruct() {
2260e2466f6SJustin Bogner   SmallString<64> TypeName;
2270e2466f6SJustin Bogner 
2280e2466f6SJustin Bogner   switch (Kind) {
2290e2466f6SJustin Bogner   case ResourceKind::Texture1D:
2300e2466f6SJustin Bogner   case ResourceKind::Texture2D:
2310e2466f6SJustin Bogner   case ResourceKind::Texture3D:
2320e2466f6SJustin Bogner   case ResourceKind::TextureCube:
2330e2466f6SJustin Bogner   case ResourceKind::Texture1DArray:
2340e2466f6SJustin Bogner   case ResourceKind::Texture2DArray:
2350e2466f6SJustin Bogner   case ResourceKind::TextureCubeArray: {
2360e2466f6SJustin Bogner     auto *RTy = cast<TextureExtType>(HandleTy);
2370e2466f6SJustin Bogner     formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
2380e2466f6SJustin Bogner                    RTy->isROV());
2390e2466f6SJustin Bogner     return StructType::create(RTy->getResourceType(), TypeName);
2400e2466f6SJustin Bogner   }
2410e2466f6SJustin Bogner   case ResourceKind::Texture2DMS:
2420e2466f6SJustin Bogner   case ResourceKind::Texture2DMSArray: {
2430e2466f6SJustin Bogner     auto *RTy = cast<MSTextureExtType>(HandleTy);
2440e2466f6SJustin Bogner     formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
2450e2466f6SJustin Bogner                    /*IsROV=*/false);
2460e2466f6SJustin Bogner     return StructType::create(RTy->getResourceType(), TypeName);
2470e2466f6SJustin Bogner   }
2480e2466f6SJustin Bogner   case ResourceKind::TypedBuffer: {
2490e2466f6SJustin Bogner     auto *RTy = cast<TypedBufferExtType>(HandleTy);
2500e2466f6SJustin Bogner     formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
2510e2466f6SJustin Bogner                    RTy->isROV());
2520e2466f6SJustin Bogner     return StructType::create(RTy->getResourceType(), TypeName);
2530e2466f6SJustin Bogner   }
2540e2466f6SJustin Bogner   case ResourceKind::RawBuffer: {
2550e2466f6SJustin Bogner     auto *RTy = cast<RawBufferExtType>(HandleTy);
2560e2466f6SJustin Bogner     formatTypeName(TypeName, "ByteAddressBuffer", RTy->isWriteable(),
2570e2466f6SJustin Bogner                    RTy->isROV());
2580e2466f6SJustin Bogner     return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
2590e2466f6SJustin Bogner                               TypeName);
2600e2466f6SJustin Bogner   }
2610e2466f6SJustin Bogner   case ResourceKind::StructuredBuffer: {
2620e2466f6SJustin Bogner     auto *RTy = cast<RawBufferExtType>(HandleTy);
2630e2466f6SJustin Bogner     formatTypeName(TypeName, "StructuredBuffer", RTy->isWriteable(),
2640e2466f6SJustin Bogner                    RTy->isROV());
2650e2466f6SJustin Bogner     return StructType::create(RTy->getResourceType(), TypeName);
2660e2466f6SJustin Bogner   }
2670e2466f6SJustin Bogner   case ResourceKind::FeedbackTexture2D:
2680e2466f6SJustin Bogner   case ResourceKind::FeedbackTexture2DArray: {
2690e2466f6SJustin Bogner     auto *RTy = cast<FeedbackTextureExtType>(HandleTy);
2700e2466f6SJustin Bogner     TypeName = formatv("{0}<{1}>", getResourceKindName(Kind),
2710e2466f6SJustin Bogner                        llvm::to_underlying(RTy->getFeedbackType()));
2720e2466f6SJustin Bogner     return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
2730e2466f6SJustin Bogner                               TypeName);
2740e2466f6SJustin Bogner   }
2750e2466f6SJustin Bogner   case ResourceKind::CBuffer:
2760e2466f6SJustin Bogner     return StructType::create(HandleTy->getContext(), "cbuffer");
2770e2466f6SJustin Bogner   case ResourceKind::Sampler: {
2780e2466f6SJustin Bogner     auto *RTy = cast<SamplerExtType>(HandleTy);
2790e2466f6SJustin Bogner     TypeName = formatv("SamplerState<{0}>",
2800e2466f6SJustin Bogner                        llvm::to_underlying(RTy->getSamplerType()));
2810e2466f6SJustin Bogner     return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
2820e2466f6SJustin Bogner                               TypeName);
2830e2466f6SJustin Bogner   }
2840e2466f6SJustin Bogner   case ResourceKind::TBuffer:
2850e2466f6SJustin Bogner   case ResourceKind::RTAccelerationStructure:
2860e2466f6SJustin Bogner     llvm_unreachable("Unhandled resource kind");
2870e2466f6SJustin Bogner   case ResourceKind::Invalid:
2880e2466f6SJustin Bogner   case ResourceKind::NumEntries:
2890e2466f6SJustin Bogner     llvm_unreachable("Invalid resource kind");
2900e2466f6SJustin Bogner   }
2910e2466f6SJustin Bogner   llvm_unreachable("Unhandled ResourceKind enum");
2920e2466f6SJustin Bogner }
2930e2466f6SJustin Bogner 
2943eca15cbSJustin Bogner bool ResourceTypeInfo::isUAV() const { return RC == ResourceClass::UAV; }
295b365dbbdSJustin Bogner 
2963eca15cbSJustin Bogner bool ResourceTypeInfo::isCBuffer() const {
2973eca15cbSJustin Bogner   return RC == ResourceClass::CBuffer;
2983eca15cbSJustin Bogner }
299b365dbbdSJustin Bogner 
3003eca15cbSJustin Bogner bool ResourceTypeInfo::isSampler() const {
3013eca15cbSJustin Bogner   return RC == ResourceClass::Sampler;
3023eca15cbSJustin Bogner }
303b365dbbdSJustin Bogner 
3043eca15cbSJustin Bogner bool ResourceTypeInfo::isStruct() const {
305b365dbbdSJustin Bogner   return Kind == ResourceKind::StructuredBuffer;
306b365dbbdSJustin Bogner }
307b365dbbdSJustin Bogner 
3083eca15cbSJustin Bogner bool ResourceTypeInfo::isTyped() const {
309b365dbbdSJustin Bogner   switch (Kind) {
310b365dbbdSJustin Bogner   case ResourceKind::Texture1D:
311b365dbbdSJustin Bogner   case ResourceKind::Texture2D:
312b365dbbdSJustin Bogner   case ResourceKind::Texture2DMS:
313b365dbbdSJustin Bogner   case ResourceKind::Texture3D:
314b365dbbdSJustin Bogner   case ResourceKind::TextureCube:
315b365dbbdSJustin Bogner   case ResourceKind::Texture1DArray:
316b365dbbdSJustin Bogner   case ResourceKind::Texture2DArray:
317b365dbbdSJustin Bogner   case ResourceKind::Texture2DMSArray:
318b365dbbdSJustin Bogner   case ResourceKind::TextureCubeArray:
319b365dbbdSJustin Bogner   case ResourceKind::TypedBuffer:
320b365dbbdSJustin Bogner     return true;
321b365dbbdSJustin Bogner   case ResourceKind::RawBuffer:
322b365dbbdSJustin Bogner   case ResourceKind::StructuredBuffer:
323b365dbbdSJustin Bogner   case ResourceKind::FeedbackTexture2D:
324b365dbbdSJustin Bogner   case ResourceKind::FeedbackTexture2DArray:
325b365dbbdSJustin Bogner   case ResourceKind::CBuffer:
326b365dbbdSJustin Bogner   case ResourceKind::Sampler:
327b365dbbdSJustin Bogner   case ResourceKind::TBuffer:
328b365dbbdSJustin Bogner   case ResourceKind::RTAccelerationStructure:
329b365dbbdSJustin Bogner     return false;
330b365dbbdSJustin Bogner   case ResourceKind::Invalid:
331b365dbbdSJustin Bogner   case ResourceKind::NumEntries:
332b365dbbdSJustin Bogner     llvm_unreachable("Invalid resource kind");
333b365dbbdSJustin Bogner   }
334b365dbbdSJustin Bogner   llvm_unreachable("Unhandled ResourceKind enum");
335b365dbbdSJustin Bogner }
336b365dbbdSJustin Bogner 
3373eca15cbSJustin Bogner bool ResourceTypeInfo::isFeedback() const {
338b365dbbdSJustin Bogner   return Kind == ResourceKind::FeedbackTexture2D ||
339b365dbbdSJustin Bogner          Kind == ResourceKind::FeedbackTexture2DArray;
340b365dbbdSJustin Bogner }
341b365dbbdSJustin Bogner 
3423eca15cbSJustin Bogner bool ResourceTypeInfo::isMultiSample() const {
343b365dbbdSJustin Bogner   return Kind == ResourceKind::Texture2DMS ||
344b365dbbdSJustin Bogner          Kind == ResourceKind::Texture2DMSArray;
345b365dbbdSJustin Bogner }
346b365dbbdSJustin Bogner 
347482237e8SJustin Bogner static bool isROV(dxil::ResourceKind Kind, TargetExtType *Ty) {
348482237e8SJustin Bogner   switch (Kind) {
349482237e8SJustin Bogner   case ResourceKind::Texture1D:
350482237e8SJustin Bogner   case ResourceKind::Texture2D:
351482237e8SJustin Bogner   case ResourceKind::Texture3D:
352482237e8SJustin Bogner   case ResourceKind::TextureCube:
353482237e8SJustin Bogner   case ResourceKind::Texture1DArray:
354482237e8SJustin Bogner   case ResourceKind::Texture2DArray:
355482237e8SJustin Bogner   case ResourceKind::TextureCubeArray:
356482237e8SJustin Bogner     return cast<TextureExtType>(Ty)->isROV();
357482237e8SJustin Bogner   case ResourceKind::TypedBuffer:
358482237e8SJustin Bogner     return cast<TypedBufferExtType>(Ty)->isROV();
359482237e8SJustin Bogner   case ResourceKind::RawBuffer:
360482237e8SJustin Bogner   case ResourceKind::StructuredBuffer:
361482237e8SJustin Bogner     return cast<RawBufferExtType>(Ty)->isROV();
362482237e8SJustin Bogner   case ResourceKind::Texture2DMS:
363482237e8SJustin Bogner   case ResourceKind::Texture2DMSArray:
364482237e8SJustin Bogner   case ResourceKind::FeedbackTexture2D:
365482237e8SJustin Bogner   case ResourceKind::FeedbackTexture2DArray:
366b365dbbdSJustin Bogner     return false;
367482237e8SJustin Bogner   case ResourceKind::CBuffer:
368482237e8SJustin Bogner   case ResourceKind::Sampler:
369482237e8SJustin Bogner   case ResourceKind::TBuffer:
370482237e8SJustin Bogner   case ResourceKind::RTAccelerationStructure:
371482237e8SJustin Bogner   case ResourceKind::Invalid:
372482237e8SJustin Bogner   case ResourceKind::NumEntries:
373482237e8SJustin Bogner     llvm_unreachable("Resource cannot be ROV");
374482237e8SJustin Bogner   }
375482237e8SJustin Bogner   llvm_unreachable("Unhandled ResourceKind enum");
376b365dbbdSJustin Bogner }
377b365dbbdSJustin Bogner 
3783eca15cbSJustin Bogner ResourceTypeInfo::UAVInfo ResourceTypeInfo::getUAV() const {
379482237e8SJustin Bogner   assert(isUAV() && "Not a UAV");
380482237e8SJustin Bogner   return {GloballyCoherent, HasCounter, isROV(Kind, HandleTy)};
381782bc4f6SJustin Bogner }
382782bc4f6SJustin Bogner 
3833eca15cbSJustin Bogner uint32_t ResourceTypeInfo::getCBufferSize(const DataLayout &DL) const {
384482237e8SJustin Bogner   assert(isCBuffer() && "Not a CBuffer");
385482237e8SJustin Bogner   return cast<CBufferExtType>(HandleTy)->getCBufferSize();
386482237e8SJustin Bogner }
387482237e8SJustin Bogner 
3883eca15cbSJustin Bogner dxil::SamplerType ResourceTypeInfo::getSamplerType() const {
389482237e8SJustin Bogner   assert(isSampler() && "Not a Sampler");
390482237e8SJustin Bogner   return cast<SamplerExtType>(HandleTy)->getSamplerType();
391482237e8SJustin Bogner }
392482237e8SJustin Bogner 
3933eca15cbSJustin Bogner ResourceTypeInfo::StructInfo
3943eca15cbSJustin Bogner ResourceTypeInfo::getStruct(const DataLayout &DL) const {
395482237e8SJustin Bogner   assert(isStruct() && "Not a Struct");
396482237e8SJustin Bogner 
397482237e8SJustin Bogner   Type *ElTy = cast<RawBufferExtType>(HandleTy)->getResourceType();
398482237e8SJustin Bogner 
399482237e8SJustin Bogner   uint32_t Stride = DL.getTypeAllocSize(ElTy);
400482237e8SJustin Bogner   MaybeAlign Alignment;
401482237e8SJustin Bogner   if (auto *STy = dyn_cast<StructType>(ElTy))
402482237e8SJustin Bogner     Alignment = DL.getStructLayout(STy)->getAlignment();
403482237e8SJustin Bogner   uint32_t AlignLog2 = Alignment ? Log2(*Alignment) : 0;
404482237e8SJustin Bogner   return {Stride, AlignLog2};
405482237e8SJustin Bogner }
406482237e8SJustin Bogner 
407482237e8SJustin Bogner static std::pair<Type *, bool> getTypedElementType(dxil::ResourceKind Kind,
408482237e8SJustin Bogner                                                    TargetExtType *Ty) {
409482237e8SJustin Bogner   switch (Kind) {
410482237e8SJustin Bogner   case ResourceKind::Texture1D:
411482237e8SJustin Bogner   case ResourceKind::Texture2D:
412482237e8SJustin Bogner   case ResourceKind::Texture3D:
413482237e8SJustin Bogner   case ResourceKind::TextureCube:
414482237e8SJustin Bogner   case ResourceKind::Texture1DArray:
415482237e8SJustin Bogner   case ResourceKind::Texture2DArray:
416482237e8SJustin Bogner   case ResourceKind::TextureCubeArray: {
417482237e8SJustin Bogner     auto *RTy = cast<TextureExtType>(Ty);
418482237e8SJustin Bogner     return {RTy->getResourceType(), RTy->isSigned()};
419482237e8SJustin Bogner   }
420482237e8SJustin Bogner   case ResourceKind::Texture2DMS:
421482237e8SJustin Bogner   case ResourceKind::Texture2DMSArray: {
422482237e8SJustin Bogner     auto *RTy = cast<MSTextureExtType>(Ty);
423482237e8SJustin Bogner     return {RTy->getResourceType(), RTy->isSigned()};
424482237e8SJustin Bogner   }
425482237e8SJustin Bogner   case ResourceKind::TypedBuffer: {
426482237e8SJustin Bogner     auto *RTy = cast<TypedBufferExtType>(Ty);
427482237e8SJustin Bogner     return {RTy->getResourceType(), RTy->isSigned()};
428482237e8SJustin Bogner   }
429482237e8SJustin Bogner   case ResourceKind::RawBuffer:
430482237e8SJustin Bogner   case ResourceKind::StructuredBuffer:
431482237e8SJustin Bogner   case ResourceKind::FeedbackTexture2D:
432482237e8SJustin Bogner   case ResourceKind::FeedbackTexture2DArray:
433482237e8SJustin Bogner   case ResourceKind::CBuffer:
434482237e8SJustin Bogner   case ResourceKind::Sampler:
435482237e8SJustin Bogner   case ResourceKind::TBuffer:
436482237e8SJustin Bogner   case ResourceKind::RTAccelerationStructure:
437482237e8SJustin Bogner   case ResourceKind::Invalid:
438482237e8SJustin Bogner   case ResourceKind::NumEntries:
439482237e8SJustin Bogner     llvm_unreachable("Resource is not typed");
440482237e8SJustin Bogner   }
441482237e8SJustin Bogner   llvm_unreachable("Unhandled ResourceKind enum");
442482237e8SJustin Bogner }
443482237e8SJustin Bogner 
4443eca15cbSJustin Bogner ResourceTypeInfo::TypedInfo ResourceTypeInfo::getTyped() const {
445482237e8SJustin Bogner   assert(isTyped() && "Not typed");
446482237e8SJustin Bogner 
447482237e8SJustin Bogner   auto [ElTy, IsSigned] = getTypedElementType(Kind, HandleTy);
448482237e8SJustin Bogner   dxil::ElementType ET = toDXILElementType(ElTy, IsSigned);
449482237e8SJustin Bogner   uint32_t Count = 1;
450482237e8SJustin Bogner   if (auto *VTy = dyn_cast<FixedVectorType>(ElTy))
451482237e8SJustin Bogner     Count = VTy->getNumElements();
452482237e8SJustin Bogner   return {ET, Count};
453482237e8SJustin Bogner }
454482237e8SJustin Bogner 
4553eca15cbSJustin Bogner dxil::SamplerFeedbackType ResourceTypeInfo::getFeedbackType() const {
456482237e8SJustin Bogner   assert(isFeedback() && "Not Feedback");
457482237e8SJustin Bogner   return cast<FeedbackTextureExtType>(HandleTy)->getFeedbackType();
458482237e8SJustin Bogner }
4593eca15cbSJustin Bogner uint32_t ResourceTypeInfo::getMultiSampleCount() const {
460482237e8SJustin Bogner   assert(isMultiSample() && "Not MultiSampled");
461482237e8SJustin Bogner   return cast<MSTextureExtType>(HandleTy)->getSampleCount();
462482237e8SJustin Bogner }
463482237e8SJustin Bogner 
4643eca15cbSJustin Bogner bool ResourceTypeInfo::operator==(const ResourceTypeInfo &RHS) const {
4653eca15cbSJustin Bogner   return std::tie(HandleTy, GloballyCoherent, HasCounter) ==
4663eca15cbSJustin Bogner          std::tie(RHS.HandleTy, RHS.GloballyCoherent, RHS.HasCounter);
467b365dbbdSJustin Bogner }
468b365dbbdSJustin Bogner 
4693eca15cbSJustin Bogner bool ResourceTypeInfo::operator<(const ResourceTypeInfo &RHS) const {
470482237e8SJustin Bogner   // An empty datalayout is sufficient for sorting purposes.
471482237e8SJustin Bogner   DataLayout DummyDL;
4723eca15cbSJustin Bogner   if (std::tie(RC, Kind) < std::tie(RHS.RC, RHS.Kind))
473482237e8SJustin Bogner     return true;
474482237e8SJustin Bogner   if (isCBuffer() && RHS.isCBuffer() &&
475482237e8SJustin Bogner       getCBufferSize(DummyDL) < RHS.getCBufferSize(DummyDL))
476482237e8SJustin Bogner     return true;
477482237e8SJustin Bogner   if (isSampler() && RHS.isSampler() && getSamplerType() < RHS.getSamplerType())
478482237e8SJustin Bogner     return true;
479482237e8SJustin Bogner   if (isUAV() && RHS.isUAV() && getUAV() < RHS.getUAV())
480482237e8SJustin Bogner     return true;
481482237e8SJustin Bogner   if (isStruct() && RHS.isStruct() &&
482482237e8SJustin Bogner       getStruct(DummyDL) < RHS.getStruct(DummyDL))
483482237e8SJustin Bogner     return true;
484482237e8SJustin Bogner   if (isFeedback() && RHS.isFeedback() &&
485482237e8SJustin Bogner       getFeedbackType() < RHS.getFeedbackType())
486482237e8SJustin Bogner     return true;
487482237e8SJustin Bogner   if (isTyped() && RHS.isTyped() && getTyped() < RHS.getTyped())
488482237e8SJustin Bogner     return true;
489482237e8SJustin Bogner   if (isMultiSample() && RHS.isMultiSample() &&
490482237e8SJustin Bogner       getMultiSampleCount() < RHS.getMultiSampleCount())
491482237e8SJustin Bogner     return true;
492482237e8SJustin Bogner   return false;
493482237e8SJustin Bogner }
494482237e8SJustin Bogner 
4953eca15cbSJustin Bogner void ResourceTypeInfo::print(raw_ostream &OS, const DataLayout &DL) const {
496482237e8SJustin Bogner   OS << "  Class: " << getResourceClassName(RC) << "\n"
49751ede55eSJustin Bogner      << "  Kind: " << getResourceKindName(Kind) << "\n";
49851ede55eSJustin Bogner 
49951ede55eSJustin Bogner   if (isCBuffer()) {
500482237e8SJustin Bogner     OS << "  CBuffer size: " << getCBufferSize(DL) << "\n";
50151ede55eSJustin Bogner   } else if (isSampler()) {
502482237e8SJustin Bogner     OS << "  Sampler Type: " << getSamplerTypeName(getSamplerType()) << "\n";
50351ede55eSJustin Bogner   } else {
50451ede55eSJustin Bogner     if (isUAV()) {
505482237e8SJustin Bogner       UAVInfo UAVFlags = getUAV();
50651ede55eSJustin Bogner       OS << "  Globally Coherent: " << UAVFlags.GloballyCoherent << "\n"
50751ede55eSJustin Bogner          << "  HasCounter: " << UAVFlags.HasCounter << "\n"
50851ede55eSJustin Bogner          << "  IsROV: " << UAVFlags.IsROV << "\n";
50951ede55eSJustin Bogner     }
51051ede55eSJustin Bogner     if (isMultiSample())
511482237e8SJustin Bogner       OS << "  Sample Count: " << getMultiSampleCount() << "\n";
51251ede55eSJustin Bogner 
51351ede55eSJustin Bogner     if (isStruct()) {
514482237e8SJustin Bogner       StructInfo Struct = getStruct(DL);
51551ede55eSJustin Bogner       OS << "  Buffer Stride: " << Struct.Stride << "\n";
51651ede55eSJustin Bogner       OS << "  Alignment: " << Struct.AlignLog2 << "\n";
51751ede55eSJustin Bogner     } else if (isTyped()) {
518482237e8SJustin Bogner       TypedInfo Typed = getTyped();
51951ede55eSJustin Bogner       OS << "  Element Type: " << getElementTypeName(Typed.ElementTy) << "\n"
52051ede55eSJustin Bogner          << "  Element Count: " << Typed.ElementCount << "\n";
52151ede55eSJustin Bogner     } else if (isFeedback())
522482237e8SJustin Bogner       OS << "  Feedback Type: " << getSamplerFeedbackTypeName(getFeedbackType())
52351ede55eSJustin Bogner          << "\n";
52451ede55eSJustin Bogner   }
52551ede55eSJustin Bogner }
52651ede55eSJustin Bogner 
5270e2466f6SJustin Bogner GlobalVariable *ResourceBindingInfo::createSymbol(Module &M, StructType *Ty,
5280e2466f6SJustin Bogner                                                   StringRef Name) {
5290e2466f6SJustin Bogner   assert(!Symbol && "Symbol has already been created");
5300e2466f6SJustin Bogner   Symbol = new GlobalVariable(M, Ty, /*isConstant=*/true,
5310e2466f6SJustin Bogner                               GlobalValue::ExternalLinkage,
5320e2466f6SJustin Bogner                               /*Initializer=*/nullptr, Name);
5330e2466f6SJustin Bogner   return Symbol;
5340e2466f6SJustin Bogner }
5350e2466f6SJustin Bogner 
5363eca15cbSJustin Bogner MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
5373eca15cbSJustin Bogner                                             dxil::ResourceTypeInfo &RTI) const {
5383eca15cbSJustin Bogner   LLVMContext &Ctx = M.getContext();
5393eca15cbSJustin Bogner   const DataLayout &DL = M.getDataLayout();
5403eca15cbSJustin Bogner 
5413eca15cbSJustin Bogner   SmallVector<Metadata *, 11> MDVals;
5423eca15cbSJustin Bogner 
5433eca15cbSJustin Bogner   Type *I32Ty = Type::getInt32Ty(Ctx);
5443eca15cbSJustin Bogner   Type *I1Ty = Type::getInt1Ty(Ctx);
5453eca15cbSJustin Bogner   auto getIntMD = [&I32Ty](uint32_t V) {
5463eca15cbSJustin Bogner     return ConstantAsMetadata::get(
5473eca15cbSJustin Bogner         Constant::getIntegerValue(I32Ty, APInt(32, V)));
5483eca15cbSJustin Bogner   };
5493eca15cbSJustin Bogner   auto getBoolMD = [&I1Ty](uint32_t V) {
5503eca15cbSJustin Bogner     return ConstantAsMetadata::get(
5513eca15cbSJustin Bogner         Constant::getIntegerValue(I1Ty, APInt(1, V)));
5523eca15cbSJustin Bogner   };
5533eca15cbSJustin Bogner 
5543eca15cbSJustin Bogner   MDVals.push_back(getIntMD(Binding.RecordID));
5550e2466f6SJustin Bogner   assert(Symbol && "Cannot yet create useful resource metadata without symbol");
5560e2466f6SJustin Bogner   MDVals.push_back(ValueAsMetadata::get(Symbol));
5570e2466f6SJustin Bogner   MDVals.push_back(MDString::get(Ctx, Symbol->getName()));
5583eca15cbSJustin Bogner   MDVals.push_back(getIntMD(Binding.Space));
5593eca15cbSJustin Bogner   MDVals.push_back(getIntMD(Binding.LowerBound));
5603eca15cbSJustin Bogner   MDVals.push_back(getIntMD(Binding.Size));
5613eca15cbSJustin Bogner 
5623eca15cbSJustin Bogner   if (RTI.isCBuffer()) {
5633eca15cbSJustin Bogner     MDVals.push_back(getIntMD(RTI.getCBufferSize(DL)));
5643eca15cbSJustin Bogner     MDVals.push_back(nullptr);
5653eca15cbSJustin Bogner   } else if (RTI.isSampler()) {
5663eca15cbSJustin Bogner     MDVals.push_back(getIntMD(llvm::to_underlying(RTI.getSamplerType())));
5673eca15cbSJustin Bogner     MDVals.push_back(nullptr);
5683eca15cbSJustin Bogner   } else {
5693eca15cbSJustin Bogner     MDVals.push_back(getIntMD(llvm::to_underlying(RTI.getResourceKind())));
5703eca15cbSJustin Bogner 
5713eca15cbSJustin Bogner     if (RTI.isUAV()) {
5723eca15cbSJustin Bogner       ResourceTypeInfo::UAVInfo UAVFlags = RTI.getUAV();
5733eca15cbSJustin Bogner       MDVals.push_back(getBoolMD(UAVFlags.GloballyCoherent));
5743eca15cbSJustin Bogner       MDVals.push_back(getBoolMD(UAVFlags.HasCounter));
5753eca15cbSJustin Bogner       MDVals.push_back(getBoolMD(UAVFlags.IsROV));
5763eca15cbSJustin Bogner     } else {
5773eca15cbSJustin Bogner       // All SRVs include sample count in the metadata, but it's only meaningful
5783eca15cbSJustin Bogner       // for multi-sampled textured. Also, UAVs can be multisampled in SM6.7+,
5793eca15cbSJustin Bogner       // but this just isn't reflected in the metadata at all.
5803eca15cbSJustin Bogner       uint32_t SampleCount =
5813eca15cbSJustin Bogner           RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0;
5823eca15cbSJustin Bogner       MDVals.push_back(getIntMD(SampleCount));
5833eca15cbSJustin Bogner     }
5843eca15cbSJustin Bogner 
5853eca15cbSJustin Bogner     // Further properties are attached to a metadata list of tag-value pairs.
5863eca15cbSJustin Bogner     SmallVector<Metadata *> Tags;
5873eca15cbSJustin Bogner     if (RTI.isStruct()) {
5883eca15cbSJustin Bogner       Tags.push_back(
5893eca15cbSJustin Bogner           getIntMD(llvm::to_underlying(ExtPropTags::StructuredBufferStride)));
5903eca15cbSJustin Bogner       Tags.push_back(getIntMD(RTI.getStruct(DL).Stride));
5913eca15cbSJustin Bogner     } else if (RTI.isTyped()) {
5923eca15cbSJustin Bogner       Tags.push_back(getIntMD(llvm::to_underlying(ExtPropTags::ElementType)));
5933eca15cbSJustin Bogner       Tags.push_back(getIntMD(llvm::to_underlying(RTI.getTyped().ElementTy)));
5943eca15cbSJustin Bogner     } else if (RTI.isFeedback()) {
5953eca15cbSJustin Bogner       Tags.push_back(
5963eca15cbSJustin Bogner           getIntMD(llvm::to_underlying(ExtPropTags::SamplerFeedbackKind)));
5973eca15cbSJustin Bogner       Tags.push_back(getIntMD(llvm::to_underlying(RTI.getFeedbackType())));
5983eca15cbSJustin Bogner     }
5993eca15cbSJustin Bogner     MDVals.push_back(Tags.empty() ? nullptr : MDNode::get(Ctx, Tags));
6003eca15cbSJustin Bogner   }
6013eca15cbSJustin Bogner 
6023eca15cbSJustin Bogner   return MDNode::get(Ctx, MDVals);
6033eca15cbSJustin Bogner }
6043eca15cbSJustin Bogner 
6053eca15cbSJustin Bogner std::pair<uint32_t, uint32_t>
6063eca15cbSJustin Bogner ResourceBindingInfo::getAnnotateProps(Module &M,
6073eca15cbSJustin Bogner                                       dxil::ResourceTypeInfo &RTI) const {
6083eca15cbSJustin Bogner   const DataLayout &DL = M.getDataLayout();
6093eca15cbSJustin Bogner 
6103eca15cbSJustin Bogner   uint32_t ResourceKind = llvm::to_underlying(RTI.getResourceKind());
6113eca15cbSJustin Bogner   uint32_t AlignLog2 = RTI.isStruct() ? RTI.getStruct(DL).AlignLog2 : 0;
6123eca15cbSJustin Bogner   bool IsUAV = RTI.isUAV();
6133eca15cbSJustin Bogner   ResourceTypeInfo::UAVInfo UAVFlags =
6143eca15cbSJustin Bogner       IsUAV ? RTI.getUAV() : ResourceTypeInfo::UAVInfo{};
6153eca15cbSJustin Bogner   bool IsROV = IsUAV && UAVFlags.IsROV;
6163eca15cbSJustin Bogner   bool IsGloballyCoherent = IsUAV && UAVFlags.GloballyCoherent;
6173eca15cbSJustin Bogner   uint8_t SamplerCmpOrHasCounter = 0;
6183eca15cbSJustin Bogner   if (IsUAV)
6193eca15cbSJustin Bogner     SamplerCmpOrHasCounter = UAVFlags.HasCounter;
6203eca15cbSJustin Bogner   else if (RTI.isSampler())
6213eca15cbSJustin Bogner     SamplerCmpOrHasCounter = RTI.getSamplerType() == SamplerType::Comparison;
6223eca15cbSJustin Bogner 
6233eca15cbSJustin Bogner   // TODO: Document this format. Currently the only reference is the
6243eca15cbSJustin Bogner   // implementation of dxc's DxilResourceProperties struct.
6253eca15cbSJustin Bogner   uint32_t Word0 = 0;
6263eca15cbSJustin Bogner   Word0 |= ResourceKind & 0xFF;
6273eca15cbSJustin Bogner   Word0 |= (AlignLog2 & 0xF) << 8;
6283eca15cbSJustin Bogner   Word0 |= (IsUAV & 1) << 12;
6293eca15cbSJustin Bogner   Word0 |= (IsROV & 1) << 13;
6303eca15cbSJustin Bogner   Word0 |= (IsGloballyCoherent & 1) << 14;
6313eca15cbSJustin Bogner   Word0 |= (SamplerCmpOrHasCounter & 1) << 15;
6323eca15cbSJustin Bogner 
6333eca15cbSJustin Bogner   uint32_t Word1 = 0;
6343eca15cbSJustin Bogner   if (RTI.isStruct())
6353eca15cbSJustin Bogner     Word1 = RTI.getStruct(DL).Stride;
6363eca15cbSJustin Bogner   else if (RTI.isCBuffer())
6373eca15cbSJustin Bogner     Word1 = RTI.getCBufferSize(DL);
6383eca15cbSJustin Bogner   else if (RTI.isFeedback())
6393eca15cbSJustin Bogner     Word1 = llvm::to_underlying(RTI.getFeedbackType());
6403eca15cbSJustin Bogner   else if (RTI.isTyped()) {
6413eca15cbSJustin Bogner     ResourceTypeInfo::TypedInfo Typed = RTI.getTyped();
6423eca15cbSJustin Bogner     uint32_t CompType = llvm::to_underlying(Typed.ElementTy);
6433eca15cbSJustin Bogner     uint32_t CompCount = Typed.ElementCount;
6443eca15cbSJustin Bogner     uint32_t SampleCount = RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0;
6453eca15cbSJustin Bogner 
6463eca15cbSJustin Bogner     Word1 |= (CompType & 0xFF) << 0;
6473eca15cbSJustin Bogner     Word1 |= (CompCount & 0xFF) << 8;
6483eca15cbSJustin Bogner     Word1 |= (SampleCount & 0xFF) << 16;
6493eca15cbSJustin Bogner   }
6503eca15cbSJustin Bogner 
6513eca15cbSJustin Bogner   return {Word0, Word1};
6523eca15cbSJustin Bogner }
6533eca15cbSJustin Bogner 
6543eca15cbSJustin Bogner void ResourceBindingInfo::print(raw_ostream &OS, dxil::ResourceTypeInfo &RTI,
6553eca15cbSJustin Bogner                                 const DataLayout &DL) const {
6560e2466f6SJustin Bogner   if (Symbol) {
6570e2466f6SJustin Bogner     OS << "  Symbol: ";
6580e2466f6SJustin Bogner     Symbol->printAsOperand(OS);
6590e2466f6SJustin Bogner     OS << "\n";
6600e2466f6SJustin Bogner   }
6610e2466f6SJustin Bogner 
6623eca15cbSJustin Bogner   OS << "  Binding:\n"
6633eca15cbSJustin Bogner      << "    Record ID: " << Binding.RecordID << "\n"
6643eca15cbSJustin Bogner      << "    Space: " << Binding.Space << "\n"
6653eca15cbSJustin Bogner      << "    Lower Bound: " << Binding.LowerBound << "\n"
6663eca15cbSJustin Bogner      << "    Size: " << Binding.Size << "\n";
6673eca15cbSJustin Bogner 
6683eca15cbSJustin Bogner   RTI.print(OS, DL);
6693eca15cbSJustin Bogner }
6703eca15cbSJustin Bogner 
67151ede55eSJustin Bogner //===----------------------------------------------------------------------===//
67251ede55eSJustin Bogner 
6733eca15cbSJustin Bogner bool DXILResourceTypeMap::invalidate(Module &M, const PreservedAnalyses &PA,
6743eca15cbSJustin Bogner                                      ModuleAnalysisManager::Invalidator &Inv) {
6753eca15cbSJustin Bogner   // Passes that introduce resource types must explicitly invalidate this pass.
6763eca15cbSJustin Bogner   auto PAC = PA.getChecker<DXILResourceTypeAnalysis>();
6773eca15cbSJustin Bogner   return !PAC.preservedWhenStateless();
6783eca15cbSJustin Bogner }
6793eca15cbSJustin Bogner 
6803eca15cbSJustin Bogner //===----------------------------------------------------------------------===//
6813eca15cbSJustin Bogner 
6823eca15cbSJustin Bogner void DXILBindingMap::populate(Module &M, DXILResourceTypeMap &DRTM) {
6833eca15cbSJustin Bogner   SmallVector<std::tuple<CallInst *, ResourceBindingInfo, ResourceTypeInfo>>
6843eca15cbSJustin Bogner       CIToInfos;
68551ede55eSJustin Bogner 
68651ede55eSJustin Bogner   for (Function &F : M.functions()) {
68751ede55eSJustin Bogner     if (!F.isDeclaration())
68851ede55eSJustin Bogner       continue;
68951ede55eSJustin Bogner     LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
69051ede55eSJustin Bogner     Intrinsic::ID ID = F.getIntrinsicID();
69151ede55eSJustin Bogner     switch (ID) {
69251ede55eSJustin Bogner     default:
69351ede55eSJustin Bogner       continue;
694*aa07f922SJustin Bogner     case Intrinsic::dx_resource_handlefrombinding: {
695482237e8SJustin Bogner       auto *HandleTy = cast<TargetExtType>(F.getReturnType());
6963eca15cbSJustin Bogner       ResourceTypeInfo &RTI = DRTM[HandleTy];
697482237e8SJustin Bogner 
698482237e8SJustin Bogner       for (User *U : F.users())
699482237e8SJustin Bogner         if (CallInst *CI = dyn_cast<CallInst>(U)) {
70051ede55eSJustin Bogner           LLVM_DEBUG(dbgs() << "  Visiting: " << *U << "\n");
701482237e8SJustin Bogner           uint32_t Space =
702482237e8SJustin Bogner               cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue();
703482237e8SJustin Bogner           uint32_t LowerBound =
704482237e8SJustin Bogner               cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue();
705482237e8SJustin Bogner           uint32_t Size =
706482237e8SJustin Bogner               cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue();
7073eca15cbSJustin Bogner           ResourceBindingInfo RBI = ResourceBindingInfo{
7083eca15cbSJustin Bogner               /*RecordID=*/0, Space, LowerBound, Size, HandleTy};
709482237e8SJustin Bogner 
7103eca15cbSJustin Bogner           CIToInfos.emplace_back(CI, RBI, RTI);
71151ede55eSJustin Bogner         }
712482237e8SJustin Bogner 
71351ede55eSJustin Bogner       break;
71451ede55eSJustin Bogner     }
71551ede55eSJustin Bogner     }
71651ede55eSJustin Bogner   }
71751ede55eSJustin Bogner 
7183eca15cbSJustin Bogner   llvm::stable_sort(CIToInfos, [](auto &LHS, auto &RHS) {
7193eca15cbSJustin Bogner     const auto &[LCI, LRBI, LRTI] = LHS;
7203eca15cbSJustin Bogner     const auto &[RCI, RRBI, RRTI] = RHS;
7213eca15cbSJustin Bogner     // Sort by resource class first for grouping purposes, and then by the
7223eca15cbSJustin Bogner     // binding and type so we can remove duplicates.
7233eca15cbSJustin Bogner     ResourceClass LRC = LRTI.getResourceClass();
7243eca15cbSJustin Bogner     ResourceClass RRC = RRTI.getResourceClass();
7253eca15cbSJustin Bogner 
7263eca15cbSJustin Bogner     return std::tie(LRC, LRBI, LRTI) < std::tie(RRC, RRBI, RRTI);
727782bc4f6SJustin Bogner   });
7283eca15cbSJustin Bogner   for (auto [CI, RBI, RTI] : CIToInfos) {
7293eca15cbSJustin Bogner     if (Infos.empty() || RBI != Infos.back())
7303eca15cbSJustin Bogner       Infos.push_back(RBI);
731482237e8SJustin Bogner     CallMap[CI] = Infos.size() - 1;
732782bc4f6SJustin Bogner   }
733782bc4f6SJustin Bogner 
734482237e8SJustin Bogner   unsigned Size = Infos.size();
735782bc4f6SJustin Bogner   // In DXC, Record ID is unique per resource type. Match that.
736782bc4f6SJustin Bogner   FirstUAV = FirstCBuffer = FirstSampler = Size;
737782bc4f6SJustin Bogner   uint32_t NextID = 0;
738782bc4f6SJustin Bogner   for (unsigned I = 0, E = Size; I != E; ++I) {
7393eca15cbSJustin Bogner     ResourceBindingInfo &RBI = Infos[I];
7403eca15cbSJustin Bogner     ResourceTypeInfo &RTI = DRTM[RBI.getHandleTy()];
7413eca15cbSJustin Bogner     if (RTI.isUAV() && FirstUAV == Size) {
742782bc4f6SJustin Bogner       FirstUAV = I;
743782bc4f6SJustin Bogner       NextID = 0;
7443eca15cbSJustin Bogner     } else if (RTI.isCBuffer() && FirstCBuffer == Size) {
745782bc4f6SJustin Bogner       FirstCBuffer = I;
746782bc4f6SJustin Bogner       NextID = 0;
7473eca15cbSJustin Bogner     } else if (RTI.isSampler() && FirstSampler == Size) {
748782bc4f6SJustin Bogner       FirstSampler = I;
749782bc4f6SJustin Bogner       NextID = 0;
750782bc4f6SJustin Bogner     }
751782bc4f6SJustin Bogner 
752782bc4f6SJustin Bogner     // Adjust the resource binding to use the next ID.
7533eca15cbSJustin Bogner     RBI.setBindingID(NextID++);
754782bc4f6SJustin Bogner   }
755782bc4f6SJustin Bogner }
756782bc4f6SJustin Bogner 
7573eca15cbSJustin Bogner void DXILBindingMap::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
7583eca15cbSJustin Bogner                            const DataLayout &DL) const {
759482237e8SJustin Bogner   for (unsigned I = 0, E = Infos.size(); I != E; ++I) {
760782bc4f6SJustin Bogner     OS << "Binding " << I << ":\n";
7613eca15cbSJustin Bogner     const dxil::ResourceBindingInfo &RBI = Infos[I];
7623eca15cbSJustin Bogner     RBI.print(OS, DRTM[RBI.getHandleTy()], DL);
763782bc4f6SJustin Bogner     OS << "\n";
764782bc4f6SJustin Bogner   }
765782bc4f6SJustin Bogner 
766782bc4f6SJustin Bogner   for (const auto &[CI, Index] : CallMap) {
767782bc4f6SJustin Bogner     OS << "Call bound to " << Index << ":";
768782bc4f6SJustin Bogner     CI->print(OS);
769782bc4f6SJustin Bogner     OS << "\n";
770782bc4f6SJustin Bogner   }
771782bc4f6SJustin Bogner }
772782bc4f6SJustin Bogner 
773372ddcd1SJustin Bogner //===----------------------------------------------------------------------===//
774372ddcd1SJustin Bogner 
7753eca15cbSJustin Bogner AnalysisKey DXILResourceTypeAnalysis::Key;
7763eca15cbSJustin Bogner AnalysisKey DXILResourceBindingAnalysis::Key;
777372ddcd1SJustin Bogner 
7783eca15cbSJustin Bogner DXILBindingMap DXILResourceBindingAnalysis::run(Module &M,
779372ddcd1SJustin Bogner                                                 ModuleAnalysisManager &AM) {
7803eca15cbSJustin Bogner   DXILBindingMap Data;
7813eca15cbSJustin Bogner   DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);
7823eca15cbSJustin Bogner   Data.populate(M, DRTM);
783372ddcd1SJustin Bogner   return Data;
784372ddcd1SJustin Bogner }
785372ddcd1SJustin Bogner 
7863eca15cbSJustin Bogner PreservedAnalyses
7873eca15cbSJustin Bogner DXILResourceBindingPrinterPass::run(Module &M, ModuleAnalysisManager &AM) {
7883eca15cbSJustin Bogner   DXILBindingMap &DBM = AM.getResult<DXILResourceBindingAnalysis>(M);
7893eca15cbSJustin Bogner   DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);
790482237e8SJustin Bogner 
7913eca15cbSJustin Bogner   DBM.print(OS, DRTM, M.getDataLayout());
792372ddcd1SJustin Bogner   return PreservedAnalyses::all();
793372ddcd1SJustin Bogner }
794372ddcd1SJustin Bogner 
7953eca15cbSJustin Bogner void DXILResourceTypeWrapperPass::anchor() {}
7963eca15cbSJustin Bogner 
7973eca15cbSJustin Bogner DXILResourceTypeWrapperPass::DXILResourceTypeWrapperPass() : ImmutablePass(ID) {
7983eca15cbSJustin Bogner   initializeDXILResourceTypeWrapperPassPass(*PassRegistry::getPassRegistry());
799372ddcd1SJustin Bogner }
800372ddcd1SJustin Bogner 
8013eca15cbSJustin Bogner INITIALIZE_PASS(DXILResourceTypeWrapperPass, "dxil-resource-type",
8023eca15cbSJustin Bogner                 "DXIL Resource Type Analysis", false, true)
8033eca15cbSJustin Bogner char DXILResourceTypeWrapperPass::ID = 0;
804372ddcd1SJustin Bogner 
8053eca15cbSJustin Bogner ModulePass *llvm::createDXILResourceTypeWrapperPassPass() {
8063eca15cbSJustin Bogner   return new DXILResourceTypeWrapperPass();
8073eca15cbSJustin Bogner }
8083eca15cbSJustin Bogner 
8093eca15cbSJustin Bogner DXILResourceBindingWrapperPass::DXILResourceBindingWrapperPass()
8103eca15cbSJustin Bogner     : ModulePass(ID) {
8113eca15cbSJustin Bogner   initializeDXILResourceBindingWrapperPassPass(
8123eca15cbSJustin Bogner       *PassRegistry::getPassRegistry());
8133eca15cbSJustin Bogner }
8143eca15cbSJustin Bogner 
8153eca15cbSJustin Bogner DXILResourceBindingWrapperPass::~DXILResourceBindingWrapperPass() = default;
8163eca15cbSJustin Bogner 
8173eca15cbSJustin Bogner void DXILResourceBindingWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
8183eca15cbSJustin Bogner   AU.addRequiredTransitive<DXILResourceTypeWrapperPass>();
819372ddcd1SJustin Bogner   AU.setPreservesAll();
820372ddcd1SJustin Bogner }
821372ddcd1SJustin Bogner 
8223eca15cbSJustin Bogner bool DXILResourceBindingWrapperPass::runOnModule(Module &M) {
8233eca15cbSJustin Bogner   Map.reset(new DXILBindingMap());
824482237e8SJustin Bogner 
8253eca15cbSJustin Bogner   DRTM = &getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
8263eca15cbSJustin Bogner   Map->populate(M, *DRTM);
827482237e8SJustin Bogner 
828372ddcd1SJustin Bogner   return false;
829372ddcd1SJustin Bogner }
830372ddcd1SJustin Bogner 
8313eca15cbSJustin Bogner void DXILResourceBindingWrapperPass::releaseMemory() { Map.reset(); }
832372ddcd1SJustin Bogner 
8333eca15cbSJustin Bogner void DXILResourceBindingWrapperPass::print(raw_ostream &OS,
8343eca15cbSJustin Bogner                                            const Module *M) const {
835482237e8SJustin Bogner   if (!Map) {
836372ddcd1SJustin Bogner     OS << "No resource map has been built!\n";
837372ddcd1SJustin Bogner     return;
838372ddcd1SJustin Bogner   }
8393eca15cbSJustin Bogner   Map->print(OS, *DRTM, M->getDataLayout());
840372ddcd1SJustin Bogner }
841372ddcd1SJustin Bogner 
842372ddcd1SJustin Bogner #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
843372ddcd1SJustin Bogner LLVM_DUMP_METHOD
8443eca15cbSJustin Bogner void DXILResourceBindingWrapperPass::dump() const { print(dbgs(), nullptr); }
845372ddcd1SJustin Bogner #endif
846372ddcd1SJustin Bogner 
8473eca15cbSJustin Bogner INITIALIZE_PASS(DXILResourceBindingWrapperPass, "dxil-resource-binding",
8483eca15cbSJustin Bogner                 "DXIL Resource Binding Analysis", false, true)
8493eca15cbSJustin Bogner char DXILResourceBindingWrapperPass::ID = 0;
850372ddcd1SJustin Bogner 
8513eca15cbSJustin Bogner ModulePass *llvm::createDXILResourceBindingWrapperPassPass() {
8523eca15cbSJustin Bogner   return new DXILResourceBindingWrapperPass();
853372ddcd1SJustin Bogner }
854