1 //===- DXILResource.cpp - DXIL Resource helper objects --------------------===//
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
7 //===----------------------------------------------------------------------===//
9 /// \file This file contains helper objects for working with DXIL Resources.
11 //===----------------------------------------------------------------------===//
13 #include "DXILResource.h"
14 #include "CBufferDataLayout.h"
15 #include "llvm/ADT/StringSwitch.h"
16 #include "llvm/IR/IRBuilder.h"
17 #include "llvm/IR/Metadata.h"
18 #include "llvm/IR/Module.h"
19 #include "llvm/Support/Debug.h"
20 #include "llvm/Support/Format.h"
23 using namespace llvm::dxil
;
25 template <typename T
> void ResourceTable
<T
>::collect(Module
&M
) {
26 NamedMDNode
*Entry
= M
.getNamedMetadata(MDName
);
27 if (!Entry
|| Entry
->getNumOperands() == 0)
31 for (auto *Res
: Entry
->operands()) {
32 Data
.push_back(T(Counter
++, hlsl::FrontendResource(cast
<MDNode
>(Res
))));
36 template <> void ResourceTable
<ConstantBuffer
>::collect(Module
&M
) {
37 NamedMDNode
*Entry
= M
.getNamedMetadata(MDName
);
38 if (!Entry
|| Entry
->getNumOperands() == 0)
42 for (auto *Res
: Entry
->operands()) {
44 ConstantBuffer(Counter
++, hlsl::FrontendResource(cast
<MDNode
>(Res
))));
46 // FIXME: share CBufferDataLayout with CBuffer load lowering.
47 // See https://github.com/llvm/llvm-project/issues/58381
48 CBufferDataLayout
CBDL(M
.getDataLayout(), /*IsLegacy*/ true);
53 void Resources::collect(Module
&M
) {
58 ResourceBase::ResourceBase(uint32_t I
, hlsl::FrontendResource R
)
59 : ID(I
), GV(R
.getGlobalVariable()), Name(""), Space(R
.getSpace()),
60 LowerBound(R
.getResourceIndex()), RangeSize(1) {
61 if (auto *ArrTy
= dyn_cast
<ArrayType
>(GV
->getValueType()))
62 RangeSize
= ArrTy
->getNumElements();
65 StringRef
ResourceBase::getElementTypeName(ElementType ElTy
) {
67 case ElementType::Invalid
:
71 case ElementType::I16
:
73 case ElementType::U16
:
75 case ElementType::I32
:
77 case ElementType::U32
:
79 case ElementType::I64
:
81 case ElementType::U64
:
83 case ElementType::F16
:
85 case ElementType::F32
:
87 case ElementType::F64
:
89 case ElementType::SNormF16
:
91 case ElementType::UNormF16
:
93 case ElementType::SNormF32
:
95 case ElementType::UNormF32
:
97 case ElementType::SNormF64
:
99 case ElementType::UNormF64
:
101 case ElementType::PackedS8x32
:
103 case ElementType::PackedU8x32
:
106 llvm_unreachable("All ElementType enums are handled in switch");
109 void ResourceBase::printElementType(ResourceKind Kind
, ElementType ElTy
,
110 unsigned Alignment
, raw_ostream
&OS
) {
113 // TODO: add vector size.
114 OS
<< right_justify(getElementTypeName(ElTy
), Alignment
);
116 case ResourceKind::RawBuffer
:
117 OS
<< right_justify("byte", Alignment
);
119 case ResourceKind::StructuredBuffer
:
120 OS
<< right_justify("struct", Alignment
);
122 case ResourceKind::CBuffer
:
123 case ResourceKind::Sampler
:
124 OS
<< right_justify("NA", Alignment
);
126 case ResourceKind::Invalid
:
127 case ResourceKind::NumEntries
:
132 StringRef
ResourceBase::getKindName(ResourceKind Kind
) {
134 case ResourceKind::NumEntries
:
135 case ResourceKind::Invalid
:
137 case ResourceKind::Texture1D
:
139 case ResourceKind::Texture2D
:
141 case ResourceKind::Texture2DMS
:
143 case ResourceKind::Texture3D
:
145 case ResourceKind::TextureCube
:
147 case ResourceKind::Texture1DArray
:
149 case ResourceKind::Texture2DArray
:
151 case ResourceKind::Texture2DMSArray
:
153 case ResourceKind::TextureCubeArray
:
155 case ResourceKind::TypedBuffer
:
157 case ResourceKind::RawBuffer
:
159 case ResourceKind::StructuredBuffer
:
161 case ResourceKind::CBuffer
:
163 case ResourceKind::Sampler
:
165 case ResourceKind::TBuffer
:
167 case ResourceKind::RTAccelerationStructure
:
169 case ResourceKind::FeedbackTexture2D
:
171 case ResourceKind::FeedbackTexture2DArray
:
172 return "fbtex2darray";
174 llvm_unreachable("All ResourceKind enums are handled in switch");
177 void ResourceBase::printKind(ResourceKind Kind
, unsigned Alignment
,
178 raw_ostream
&OS
, bool SRV
, bool HasCounter
,
179 uint32_t SampleCount
) {
182 OS
<< right_justify(getKindName(Kind
), Alignment
);
185 case ResourceKind::RawBuffer
:
186 case ResourceKind::StructuredBuffer
:
188 OS
<< right_justify("r/o", Alignment
);
191 OS
<< right_justify("r/w", Alignment
);
193 OS
<< right_justify("r/w+cnt", Alignment
);
196 case ResourceKind::TypedBuffer
:
197 OS
<< right_justify("buf", Alignment
);
199 case ResourceKind::Texture2DMS
:
200 case ResourceKind::Texture2DMSArray
: {
201 std::string DimName
= getKindName(Kind
).str();
203 DimName
+= std::to_string(SampleCount
);
204 OS
<< right_justify(DimName
, Alignment
);
206 case ResourceKind::CBuffer
:
207 case ResourceKind::Sampler
:
208 OS
<< right_justify("NA", Alignment
);
210 case ResourceKind::Invalid
:
211 case ResourceKind::NumEntries
:
216 void ResourceBase::print(raw_ostream
&OS
, StringRef IDPrefix
,
217 StringRef BindingPrefix
) const {
218 std::string ResID
= IDPrefix
.str();
219 ResID
+= std::to_string(ID
);
220 OS
<< right_justify(ResID
, 8);
222 std::string Bind
= BindingPrefix
.str();
223 Bind
+= std::to_string(LowerBound
);
225 Bind
+= ",space" + std::to_string(Space
);
227 OS
<< right_justify(Bind
, 15);
228 if (RangeSize
!= UINT_MAX
)
229 OS
<< right_justify(std::to_string(RangeSize
), 6) << "\n";
231 OS
<< right_justify("unbounded", 6) << "\n";
234 void UAVResource::print(raw_ostream
&OS
) const {
235 OS
<< "; " << left_justify(Name
, 31);
237 OS
<< right_justify("UAV", 10);
239 printElementType(Shape
, ExtProps
.ElementType
.value_or(ElementType::Invalid
),
242 // FIXME: support SampleCount.
243 // See https://github.com/llvm/llvm-project/issues/58175
244 printKind(Shape
, 12, OS
, /*SRV*/ false, HasCounter
);
245 // Print the binding part.
246 ResourceBase::print(OS
, "U", "u");
249 ConstantBuffer::ConstantBuffer(uint32_t I
, hlsl::FrontendResource R
)
250 : ResourceBase(I
, R
) {}
252 void ConstantBuffer::setSize(CBufferDataLayout
&DL
) {
253 CBufferSizeInBytes
= DL
.getTypeAllocSizeInBytes(GV
->getValueType());
256 void ConstantBuffer::print(raw_ostream
&OS
) const {
257 OS
<< "; " << left_justify(Name
, 31);
259 OS
<< right_justify("cbuffer", 10);
261 printElementType(ResourceKind::CBuffer
, ElementType::Invalid
, 8, OS
);
263 printKind(ResourceKind::CBuffer
, 12, OS
, /*SRV*/ false, /*HasCounter*/ false);
264 // Print the binding part.
265 ResourceBase::print(OS
, "CB", "cb");
268 template <typename T
> void ResourceTable
<T
>::print(raw_ostream
&OS
) const {
269 for (auto &Res
: Data
)
273 MDNode
*ResourceBase::ExtendedProperties::write(LLVMContext
&Ctx
) const {
275 SmallVector
<Metadata
*> Entries
;
277 Entries
.emplace_back(
278 ConstantAsMetadata::get(B
.getInt32(TypedBufferElementType
)));
279 Entries
.emplace_back(ConstantAsMetadata::get(
280 B
.getInt32(static_cast<uint32_t>(*ElementType
))));
284 return MDNode::get(Ctx
, Entries
);
287 void ResourceBase::write(LLVMContext
&Ctx
,
288 MutableArrayRef
<Metadata
*> Entries
) const {
290 Entries
[0] = ConstantAsMetadata::get(B
.getInt32(ID
));
291 Entries
[1] = ConstantAsMetadata::get(GV
);
292 Entries
[2] = MDString::get(Ctx
, Name
);
293 Entries
[3] = ConstantAsMetadata::get(B
.getInt32(Space
));
294 Entries
[4] = ConstantAsMetadata::get(B
.getInt32(LowerBound
));
295 Entries
[5] = ConstantAsMetadata::get(B
.getInt32(RangeSize
));
298 MDNode
*UAVResource::write() const {
299 auto &Ctx
= GV
->getContext();
301 Metadata
*Entries
[11];
302 ResourceBase::write(Ctx
, Entries
);
304 ConstantAsMetadata::get(B
.getInt32(static_cast<uint32_t>(Shape
)));
305 Entries
[7] = ConstantAsMetadata::get(B
.getInt1(GloballyCoherent
));
306 Entries
[8] = ConstantAsMetadata::get(B
.getInt1(HasCounter
));
307 Entries
[9] = ConstantAsMetadata::get(B
.getInt1(IsROV
));
308 Entries
[10] = ExtProps
.write(Ctx
);
309 return MDNode::get(Ctx
, Entries
);
312 MDNode
*ConstantBuffer::write() const {
313 auto &Ctx
= GV
->getContext();
315 Metadata
*Entries
[7];
316 ResourceBase::write(Ctx
, Entries
);
318 Entries
[6] = ConstantAsMetadata::get(B
.getInt32(CBufferSizeInBytes
));
319 return MDNode::get(Ctx
, Entries
);
322 template <typename T
> MDNode
*ResourceTable
<T
>::write(Module
&M
) const {
325 SmallVector
<Metadata
*> MDs
;
326 for (auto &Res
: Data
)
327 MDs
.emplace_back(Res
.write());
329 NamedMDNode
*Entry
= M
.getNamedMetadata(MDName
);
331 Entry
->eraseFromParent();
333 return MDNode::get(M
.getContext(), MDs
);
336 void Resources::write(Module
&M
) const {
337 Metadata
*ResourceMDs
[4] = {nullptr, nullptr, nullptr, nullptr};
339 ResourceMDs
[1] = UAVs
.write(M
);
341 ResourceMDs
[2] = CBuffers
.write(M
);
343 bool HasResource
= ResourceMDs
[0] != nullptr || ResourceMDs
[1] != nullptr ||
344 ResourceMDs
[2] != nullptr || ResourceMDs
[3] != nullptr;
347 NamedMDNode
*DXResMD
= M
.getOrInsertNamedMetadata("dx.resources");
348 DXResMD
->addOperand(MDNode::get(M
.getContext(), ResourceMDs
));
351 NamedMDNode
*Entry
= M
.getNamedMetadata("hlsl.uavs");
353 Entry
->eraseFromParent();
356 void Resources::print(raw_ostream
&O
) const {
358 << "; Resource Bindings:\n"
360 << "; Name Type Format Dim "
361 "ID HLSL Bind Count\n"
362 << "; ------------------------------ ---------- ------- ----------- "
363 "------- -------------- ------\n";
369 void Resources::dump() const { print(dbgs()); }