xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/Utils/DXILResource.cpp (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 //===- DXILResource.cpp - Tools to translate DXIL resources ---------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/Transforms/Utils/DXILResource.h"
10 #include "llvm/ADT/APInt.h"
11 #include "llvm/IR/DerivedTypes.h"
12 
13 using namespace llvm;
14 using namespace dxil;
15 
16 bool ResourceInfo::isUAV() const { return RC == ResourceClass::UAV; }
17 
18 bool ResourceInfo::isCBuffer() const { return RC == ResourceClass::CBuffer; }
19 
20 bool ResourceInfo::isSampler() const { return RC == ResourceClass::Sampler; }
21 
22 bool ResourceInfo::isStruct() const {
23   return Kind == ResourceKind::StructuredBuffer;
24 }
25 
26 bool ResourceInfo::isTyped() const {
27   switch (Kind) {
28   case ResourceKind::Texture1D:
29   case ResourceKind::Texture2D:
30   case ResourceKind::Texture2DMS:
31   case ResourceKind::Texture3D:
32   case ResourceKind::TextureCube:
33   case ResourceKind::Texture1DArray:
34   case ResourceKind::Texture2DArray:
35   case ResourceKind::Texture2DMSArray:
36   case ResourceKind::TextureCubeArray:
37   case ResourceKind::TypedBuffer:
38     return true;
39   case ResourceKind::RawBuffer:
40   case ResourceKind::StructuredBuffer:
41   case ResourceKind::FeedbackTexture2D:
42   case ResourceKind::FeedbackTexture2DArray:
43   case ResourceKind::CBuffer:
44   case ResourceKind::Sampler:
45   case ResourceKind::TBuffer:
46   case ResourceKind::RTAccelerationStructure:
47     return false;
48   case ResourceKind::Invalid:
49   case ResourceKind::NumEntries:
50     llvm_unreachable("Invalid resource kind");
51   }
52   llvm_unreachable("Unhandled ResourceKind enum");
53 }
54 
55 bool ResourceInfo::isFeedback() const {
56   return Kind == ResourceKind::FeedbackTexture2D ||
57          Kind == ResourceKind::FeedbackTexture2DArray;
58 }
59 
60 bool ResourceInfo::isMultiSample() const {
61   return Kind == ResourceKind::Texture2DMS ||
62          Kind == ResourceKind::Texture2DMSArray;
63 }
64 
65 ResourceInfo ResourceInfo::SRV(Value *Symbol, StringRef Name,
66                                ResourceBinding Binding, uint32_t UniqueID,
67                                ElementType ElementTy, uint32_t ElementCount,
68                                ResourceKind Kind) {
69   ResourceInfo RI(ResourceClass::SRV, Kind, Symbol, Name, Binding, UniqueID);
70   assert(RI.isTyped() && !(RI.isStruct() || RI.isMultiSample()) &&
71          "Invalid ResourceKind for SRV constructor.");
72   RI.Typed.ElementTy = ElementTy;
73   RI.Typed.ElementCount = ElementCount;
74   return RI;
75 }
76 
77 ResourceInfo ResourceInfo::RawBuffer(Value *Symbol, StringRef Name,
78                                      ResourceBinding Binding,
79                                      uint32_t UniqueID) {
80   ResourceInfo RI(ResourceClass::SRV, ResourceKind::RawBuffer, Symbol, Name,
81                   Binding, UniqueID);
82   return RI;
83 }
84 
85 ResourceInfo ResourceInfo::StructuredBuffer(Value *Symbol, StringRef Name,
86                                             ResourceBinding Binding,
87                                             uint32_t UniqueID, uint32_t Stride,
88                                             Align Alignment) {
89   ResourceInfo RI(ResourceClass::SRV, ResourceKind::StructuredBuffer, Symbol,
90                   Name, Binding, UniqueID);
91   RI.Struct.Stride = Stride;
92   RI.Struct.Alignment = Alignment;
93   return RI;
94 }
95 
96 ResourceInfo ResourceInfo::Texture2DMS(Value *Symbol, StringRef Name,
97                                        ResourceBinding Binding,
98                                        uint32_t UniqueID, ElementType ElementTy,
99                                        uint32_t ElementCount,
100                                        uint32_t SampleCount) {
101   ResourceInfo RI(ResourceClass::SRV, ResourceKind::Texture2DMS, Symbol, Name,
102                   Binding, UniqueID);
103   RI.Typed.ElementTy = ElementTy;
104   RI.Typed.ElementCount = ElementCount;
105   RI.MultiSample.Count = SampleCount;
106   return RI;
107 }
108 
109 ResourceInfo ResourceInfo::Texture2DMSArray(
110     Value *Symbol, StringRef Name, ResourceBinding Binding, uint32_t UniqueID,
111     ElementType ElementTy, uint32_t ElementCount, uint32_t SampleCount) {
112   ResourceInfo RI(ResourceClass::SRV, ResourceKind::Texture2DMSArray, Symbol,
113                   Name, Binding, UniqueID);
114   RI.Typed.ElementTy = ElementTy;
115   RI.Typed.ElementCount = ElementCount;
116   RI.MultiSample.Count = SampleCount;
117   return RI;
118 }
119 
120 ResourceInfo ResourceInfo::UAV(Value *Symbol, StringRef Name,
121                                ResourceBinding Binding, uint32_t UniqueID,
122                                ElementType ElementTy, uint32_t ElementCount,
123                                bool GloballyCoherent, bool IsROV,
124                                ResourceKind Kind) {
125   ResourceInfo RI(ResourceClass::UAV, Kind, Symbol, Name, Binding, UniqueID);
126   assert(RI.isTyped() && !(RI.isStruct() || RI.isMultiSample()) &&
127          "Invalid ResourceKind for UAV constructor.");
128   RI.Typed.ElementTy = ElementTy;
129   RI.Typed.ElementCount = ElementCount;
130   RI.UAVFlags.GloballyCoherent = GloballyCoherent;
131   RI.UAVFlags.IsROV = IsROV;
132   RI.UAVFlags.HasCounter = false;
133   return RI;
134 }
135 
136 ResourceInfo ResourceInfo::RWRawBuffer(Value *Symbol, StringRef Name,
137                                        ResourceBinding Binding,
138                                        uint32_t UniqueID, bool GloballyCoherent,
139                                        bool IsROV) {
140   ResourceInfo RI(ResourceClass::UAV, ResourceKind::RawBuffer, Symbol, Name,
141                   Binding, UniqueID);
142   RI.UAVFlags.GloballyCoherent = GloballyCoherent;
143   RI.UAVFlags.IsROV = IsROV;
144   RI.UAVFlags.HasCounter = false;
145   return RI;
146 }
147 
148 ResourceInfo ResourceInfo::RWStructuredBuffer(Value *Symbol, StringRef Name,
149                                               ResourceBinding Binding,
150                                               uint32_t UniqueID,
151                                               uint32_t Stride, Align Alignment,
152                                               bool GloballyCoherent, bool IsROV,
153                                               bool HasCounter) {
154   ResourceInfo RI(ResourceClass::UAV, ResourceKind::StructuredBuffer, Symbol,
155                   Name, Binding, UniqueID);
156   RI.Struct.Stride = Stride;
157   RI.Struct.Alignment = Alignment;
158   RI.UAVFlags.GloballyCoherent = GloballyCoherent;
159   RI.UAVFlags.IsROV = IsROV;
160   RI.UAVFlags.HasCounter = HasCounter;
161   return RI;
162 }
163 
164 ResourceInfo
165 ResourceInfo::RWTexture2DMS(Value *Symbol, StringRef Name,
166                             ResourceBinding Binding, uint32_t UniqueID,
167                             ElementType ElementTy, uint32_t ElementCount,
168                             uint32_t SampleCount, bool GloballyCoherent) {
169   ResourceInfo RI(ResourceClass::UAV, ResourceKind::Texture2DMS, Symbol, Name,
170                   Binding, UniqueID);
171   RI.Typed.ElementTy = ElementTy;
172   RI.Typed.ElementCount = ElementCount;
173   RI.UAVFlags.GloballyCoherent = GloballyCoherent;
174   RI.UAVFlags.IsROV = false;
175   RI.UAVFlags.HasCounter = false;
176   RI.MultiSample.Count = SampleCount;
177   return RI;
178 }
179 
180 ResourceInfo
181 ResourceInfo::RWTexture2DMSArray(Value *Symbol, StringRef Name,
182                                  ResourceBinding Binding, uint32_t UniqueID,
183                                  ElementType ElementTy, uint32_t ElementCount,
184                                  uint32_t SampleCount, bool GloballyCoherent) {
185   ResourceInfo RI(ResourceClass::UAV, ResourceKind::Texture2DMSArray, Symbol,
186                   Name, Binding, UniqueID);
187   RI.Typed.ElementTy = ElementTy;
188   RI.Typed.ElementCount = ElementCount;
189   RI.UAVFlags.GloballyCoherent = GloballyCoherent;
190   RI.UAVFlags.IsROV = false;
191   RI.UAVFlags.HasCounter = false;
192   RI.MultiSample.Count = SampleCount;
193   return RI;
194 }
195 
196 ResourceInfo ResourceInfo::FeedbackTexture2D(Value *Symbol, StringRef Name,
197                                              ResourceBinding Binding,
198                                              uint32_t UniqueID,
199                                              SamplerFeedbackType FeedbackTy) {
200   ResourceInfo RI(ResourceClass::UAV, ResourceKind::FeedbackTexture2D, Symbol,
201                   Name, Binding, UniqueID);
202   RI.UAVFlags.GloballyCoherent = false;
203   RI.UAVFlags.IsROV = false;
204   RI.UAVFlags.HasCounter = false;
205   RI.Feedback.Type = FeedbackTy;
206   return RI;
207 }
208 
209 ResourceInfo
210 ResourceInfo::FeedbackTexture2DArray(Value *Symbol, StringRef Name,
211                                      ResourceBinding Binding, uint32_t UniqueID,
212                                      SamplerFeedbackType FeedbackTy) {
213   ResourceInfo RI(ResourceClass::UAV, ResourceKind::FeedbackTexture2DArray,
214                   Symbol, Name, Binding, UniqueID);
215   RI.UAVFlags.GloballyCoherent = false;
216   RI.UAVFlags.IsROV = false;
217   RI.UAVFlags.HasCounter = false;
218   RI.Feedback.Type = FeedbackTy;
219   return RI;
220 }
221 
222 ResourceInfo ResourceInfo::CBuffer(Value *Symbol, StringRef Name,
223                                    ResourceBinding Binding, uint32_t UniqueID,
224                                    uint32_t Size) {
225   ResourceInfo RI(ResourceClass::CBuffer, ResourceKind::CBuffer, Symbol, Name,
226                   Binding, UniqueID);
227   RI.CBufferSize = Size;
228   return RI;
229 }
230 
231 ResourceInfo ResourceInfo::Sampler(Value *Symbol, StringRef Name,
232                                    ResourceBinding Binding, uint32_t UniqueID,
233                                    SamplerType SamplerTy) {
234   ResourceInfo RI(ResourceClass::Sampler, ResourceKind::Sampler, Symbol, Name,
235                   Binding, UniqueID);
236   RI.SamplerTy = SamplerTy;
237   return RI;
238 }
239 
240 bool ResourceInfo::operator==(const ResourceInfo &RHS) const {
241   if (std::tie(Symbol, Name, Binding, UniqueID, RC, Kind) !=
242       std::tie(RHS.Symbol, RHS.Name, RHS.Binding, RHS.UniqueID, RHS.RC,
243                RHS.Kind))
244     return false;
245   if (isCBuffer())
246     return CBufferSize == RHS.CBufferSize;
247   if (isSampler())
248     return SamplerTy == RHS.SamplerTy;
249   if (isUAV() && UAVFlags != RHS.UAVFlags)
250     return false;
251 
252   if (isStruct())
253     return Struct == RHS.Struct;
254   if (isFeedback())
255     return Feedback == RHS.Feedback;
256   if (isTyped() && Typed != RHS.Typed)
257     return false;
258 
259   if (isMultiSample())
260     return MultiSample == RHS.MultiSample;
261 
262   assert((Kind == ResourceKind::RawBuffer) && "Unhandled resource kind");
263   return true;
264 }
265 
266 MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const {
267   SmallVector<Metadata *, 11> MDVals;
268 
269   Type *I32Ty = Type::getInt32Ty(Ctx);
270   Type *I1Ty = Type::getInt1Ty(Ctx);
271   auto getIntMD = [&I32Ty](uint32_t V) {
272     return ConstantAsMetadata::get(
273         Constant::getIntegerValue(I32Ty, APInt(32, V)));
274   };
275   auto getBoolMD = [&I1Ty](uint32_t V) {
276     return ConstantAsMetadata::get(
277         Constant::getIntegerValue(I1Ty, APInt(1, V)));
278   };
279 
280   MDVals.push_back(getIntMD(UniqueID));
281   MDVals.push_back(ValueAsMetadata::get(Symbol));
282   MDVals.push_back(MDString::get(Ctx, Name));
283   MDVals.push_back(getIntMD(Binding.Space));
284   MDVals.push_back(getIntMD(Binding.LowerBound));
285   MDVals.push_back(getIntMD(Binding.Size));
286 
287   if (isCBuffer()) {
288     MDVals.push_back(getIntMD(CBufferSize));
289     MDVals.push_back(nullptr);
290   } else if (isSampler()) {
291     MDVals.push_back(getIntMD(llvm::to_underlying(SamplerTy)));
292     MDVals.push_back(nullptr);
293   } else {
294     MDVals.push_back(getIntMD(llvm::to_underlying(Kind)));
295 
296     if (isUAV()) {
297       MDVals.push_back(getBoolMD(UAVFlags.GloballyCoherent));
298       MDVals.push_back(getBoolMD(UAVFlags.HasCounter));
299       MDVals.push_back(getBoolMD(UAVFlags.IsROV));
300     } else {
301       // All SRVs include sample count in the metadata, but it's only meaningful
302       // for multi-sampled textured. Also, UAVs can be multisampled in SM6.7+,
303       // but this just isn't reflected in the metadata at all.
304       uint32_t SampleCount = isMultiSample() ? MultiSample.Count : 0;
305       MDVals.push_back(getIntMD(SampleCount));
306     }
307 
308     // Further properties are attached to a metadata list of tag-value pairs.
309     SmallVector<Metadata *> Tags;
310     if (isStruct()) {
311       Tags.push_back(
312           getIntMD(llvm::to_underlying(ExtPropTags::StructuredBufferStride)));
313       Tags.push_back(getIntMD(Struct.Stride));
314     } else if (isTyped()) {
315       Tags.push_back(getIntMD(llvm::to_underlying(ExtPropTags::ElementType)));
316       Tags.push_back(getIntMD(llvm::to_underlying(Typed.ElementTy)));
317     } else if (isFeedback()) {
318       Tags.push_back(
319           getIntMD(llvm::to_underlying(ExtPropTags::SamplerFeedbackKind)));
320       Tags.push_back(getIntMD(llvm::to_underlying(Feedback.Type)));
321     }
322     MDVals.push_back(Tags.empty() ? nullptr : MDNode::get(Ctx, Tags));
323   }
324 
325   return MDNode::get(Ctx, MDVals);
326 }
327 
328 std::pair<uint32_t, uint32_t> ResourceInfo::getAnnotateProps() const {
329   uint32_t ResourceKind = llvm::to_underlying(Kind);
330   uint32_t AlignLog2 = isStruct() ? Log2(Struct.Alignment) : 0;
331   bool IsUAV = isUAV();
332   bool IsROV = IsUAV && UAVFlags.IsROV;
333   bool IsGloballyCoherent = IsUAV && UAVFlags.GloballyCoherent;
334   uint8_t SamplerCmpOrHasCounter = 0;
335   if (IsUAV)
336     SamplerCmpOrHasCounter = UAVFlags.HasCounter;
337   else if (isSampler())
338     SamplerCmpOrHasCounter = SamplerTy == SamplerType::Comparison;
339 
340   // TODO: Document this format. Currently the only reference is the
341   // implementation of dxc's DxilResourceProperties struct.
342   uint32_t Word0 = 0;
343   Word0 |= ResourceKind & 0xFF;
344   Word0 |= (AlignLog2 & 0xF) << 8;
345   Word0 |= (IsUAV & 1) << 12;
346   Word0 |= (IsROV & 1) << 13;
347   Word0 |= (IsGloballyCoherent & 1) << 14;
348   Word0 |= (SamplerCmpOrHasCounter & 1) << 15;
349 
350   uint32_t Word1 = 0;
351   if (isStruct())
352     Word1 = Struct.Stride;
353   else if (isCBuffer())
354     Word1 = CBufferSize;
355   else if (isFeedback())
356     Word1 = llvm::to_underlying(Feedback.Type);
357   else if (isTyped()) {
358     uint32_t CompType = llvm::to_underlying(Typed.ElementTy);
359     uint32_t CompCount = Typed.ElementCount;
360     uint32_t SampleCount = isMultiSample() ? MultiSample.Count : 0;
361 
362     Word1 |= (CompType & 0xFF) << 0;
363     Word1 |= (CompCount & 0xFF) << 8;
364     Word1 |= (SampleCount & 0xFF) << 16;
365   }
366 
367   return {Word0, Word1};
368 }
369 
370 #define DEBUG_TYPE "dxil-resource"
371