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