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
isUAV() const16 bool ResourceInfo::isUAV() const { return RC == ResourceClass::UAV; }
17
isCBuffer() const18 bool ResourceInfo::isCBuffer() const { return RC == ResourceClass::CBuffer; }
19
isSampler() const20 bool ResourceInfo::isSampler() const { return RC == ResourceClass::Sampler; }
21
isStruct() const22 bool ResourceInfo::isStruct() const {
23 return Kind == ResourceKind::StructuredBuffer;
24 }
25
isTyped() const26 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
isFeedback() const55 bool ResourceInfo::isFeedback() const {
56 return Kind == ResourceKind::FeedbackTexture2D ||
57 Kind == ResourceKind::FeedbackTexture2DArray;
58 }
59
isMultiSample() const60 bool ResourceInfo::isMultiSample() const {
61 return Kind == ResourceKind::Texture2DMS ||
62 Kind == ResourceKind::Texture2DMSArray;
63 }
64
SRV(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,ElementType ElementTy,uint32_t ElementCount,ResourceKind Kind)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
RawBuffer(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID)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
StructuredBuffer(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,uint32_t Stride,Align Alignment)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
Texture2DMS(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,ElementType ElementTy,uint32_t ElementCount,uint32_t SampleCount)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
Texture2DMSArray(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,ElementType ElementTy,uint32_t ElementCount,uint32_t SampleCount)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
UAV(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,ElementType ElementTy,uint32_t ElementCount,bool GloballyCoherent,bool IsROV,ResourceKind Kind)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
RWRawBuffer(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,bool GloballyCoherent,bool IsROV)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
RWStructuredBuffer(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,uint32_t Stride,Align Alignment,bool GloballyCoherent,bool IsROV,bool HasCounter)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
RWTexture2DMS(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,ElementType ElementTy,uint32_t ElementCount,uint32_t SampleCount,bool GloballyCoherent)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
RWTexture2DMSArray(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,ElementType ElementTy,uint32_t ElementCount,uint32_t SampleCount,bool GloballyCoherent)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
FeedbackTexture2D(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,SamplerFeedbackType FeedbackTy)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
FeedbackTexture2DArray(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,SamplerFeedbackType FeedbackTy)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
CBuffer(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,uint32_t Size)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
Sampler(Value * Symbol,StringRef Name,ResourceBinding Binding,uint32_t UniqueID,SamplerType SamplerTy)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
operator ==(const ResourceInfo & RHS) const240 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
getAsMetadata(LLVMContext & Ctx) const266 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
getAnnotateProps() const328 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