xref: /llvm-project/llvm/lib/Target/DirectX/DXILResource.cpp (revision 58eec851cb47b298d47ad25ff7911150aed65564)
1618e5006SChris Bieneman //===- DXILResource.cpp - DXIL Resource helper objects --------------------===//
2618e5006SChris Bieneman //
3618e5006SChris Bieneman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4618e5006SChris Bieneman // See https://llvm.org/LICENSE.txt for license information.
5618e5006SChris Bieneman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6618e5006SChris Bieneman //
7618e5006SChris Bieneman //===----------------------------------------------------------------------===//
8618e5006SChris Bieneman ///
9618e5006SChris Bieneman /// \file This file contains helper objects for working with DXIL Resources.
10618e5006SChris Bieneman ///
11618e5006SChris Bieneman //===----------------------------------------------------------------------===//
12618e5006SChris Bieneman 
13618e5006SChris Bieneman #include "DXILResource.h"
14944f4b28SXiang Li #include "CBufferDataLayout.h"
15618e5006SChris Bieneman #include "llvm/ADT/StringSwitch.h"
16618e5006SChris Bieneman #include "llvm/IR/IRBuilder.h"
17618e5006SChris Bieneman #include "llvm/IR/Metadata.h"
18618e5006SChris Bieneman #include "llvm/IR/Module.h"
1922018555SXiang Li #include "llvm/Support/Debug.h"
2022018555SXiang Li #include "llvm/Support/Format.h"
21618e5006SChris Bieneman 
22618e5006SChris Bieneman using namespace llvm;
23618e5006SChris Bieneman using namespace llvm::dxil;
24618e5006SChris Bieneman 
25944f4b28SXiang Li template <typename T> void ResourceTable<T>::collect(Module &M) {
26944f4b28SXiang Li   NamedMDNode *Entry = M.getNamedMetadata(MDName);
27618e5006SChris Bieneman   if (!Entry || Entry->getNumOperands() == 0)
28618e5006SChris Bieneman     return;
29618e5006SChris Bieneman 
30618e5006SChris Bieneman   uint32_t Counter = 0;
31944f4b28SXiang Li   for (auto *Res : Entry->operands()) {
32ad713186SJustin Bogner     Data.push_back(T(Counter++, hlsl::FrontendResource(cast<MDNode>(Res))));
33618e5006SChris Bieneman   }
34618e5006SChris Bieneman }
35618e5006SChris Bieneman 
36944f4b28SXiang Li template <> void ResourceTable<ConstantBuffer>::collect(Module &M) {
37944f4b28SXiang Li   NamedMDNode *Entry = M.getNamedMetadata(MDName);
38944f4b28SXiang Li   if (!Entry || Entry->getNumOperands() == 0)
39944f4b28SXiang Li     return;
40944f4b28SXiang Li 
41944f4b28SXiang Li   uint32_t Counter = 0;
42944f4b28SXiang Li   for (auto *Res : Entry->operands()) {
43944f4b28SXiang Li     Data.push_back(
44ad713186SJustin Bogner         ConstantBuffer(Counter++, hlsl::FrontendResource(cast<MDNode>(Res))));
45944f4b28SXiang Li   }
46944f4b28SXiang Li   // FIXME: share CBufferDataLayout with CBuffer load lowering.
47944f4b28SXiang Li   //   See https://github.com/llvm/llvm-project/issues/58381
48944f4b28SXiang Li   CBufferDataLayout CBDL(M.getDataLayout(), /*IsLegacy*/ true);
49944f4b28SXiang Li   for (auto &CB : Data)
50944f4b28SXiang Li     CB.setSize(CBDL);
51944f4b28SXiang Li }
52944f4b28SXiang Li 
53944f4b28SXiang Li void Resources::collect(Module &M) {
54944f4b28SXiang Li   UAVs.collect(M);
55944f4b28SXiang Li   CBuffers.collect(M);
56944f4b28SXiang Li }
5722018555SXiang Li 
58ad713186SJustin Bogner ResourceBase::ResourceBase(uint32_t I, hlsl::FrontendResource R)
5913163dd8SXiang Li     : ID(I), GV(R.getGlobalVariable()), Name(""), Space(R.getSpace()),
6013163dd8SXiang Li       LowerBound(R.getResourceIndex()), RangeSize(1) {
61944f4b28SXiang Li   if (auto *ArrTy = dyn_cast<ArrayType>(GV->getValueType()))
62618e5006SChris Bieneman     RangeSize = ArrTy->getNumElements();
63618e5006SChris Bieneman }
64618e5006SChris Bieneman 
654f54d715SJustin Bogner StringRef ResourceBase::getElementTypeName(ElementType ElTy) {
664f54d715SJustin Bogner   switch (ElTy) {
674f54d715SJustin Bogner   case ElementType::Invalid:
6822018555SXiang Li     return "invalid";
694f54d715SJustin Bogner   case ElementType::I1:
7022018555SXiang Li     return "i1";
714f54d715SJustin Bogner   case ElementType::I16:
7222018555SXiang Li     return "i16";
734f54d715SJustin Bogner   case ElementType::U16:
7422018555SXiang Li     return "u16";
754f54d715SJustin Bogner   case ElementType::I32:
7622018555SXiang Li     return "i32";
774f54d715SJustin Bogner   case ElementType::U32:
7822018555SXiang Li     return "u32";
794f54d715SJustin Bogner   case ElementType::I64:
8022018555SXiang Li     return "i64";
814f54d715SJustin Bogner   case ElementType::U64:
8222018555SXiang Li     return "u64";
834f54d715SJustin Bogner   case ElementType::F16:
8422018555SXiang Li     return "f16";
854f54d715SJustin Bogner   case ElementType::F32:
8622018555SXiang Li     return "f32";
874f54d715SJustin Bogner   case ElementType::F64:
8822018555SXiang Li     return "f64";
894f54d715SJustin Bogner   case ElementType::SNormF16:
9022018555SXiang Li     return "snorm_f16";
914f54d715SJustin Bogner   case ElementType::UNormF16:
9222018555SXiang Li     return "unorm_f16";
934f54d715SJustin Bogner   case ElementType::SNormF32:
9422018555SXiang Li     return "snorm_f32";
954f54d715SJustin Bogner   case ElementType::UNormF32:
9622018555SXiang Li     return "unorm_f32";
974f54d715SJustin Bogner   case ElementType::SNormF64:
9822018555SXiang Li     return "snorm_f64";
994f54d715SJustin Bogner   case ElementType::UNormF64:
10022018555SXiang Li     return "unorm_f64";
1014f54d715SJustin Bogner   case ElementType::PackedS8x32:
10222018555SXiang Li     return "p32i8";
1034f54d715SJustin Bogner   case ElementType::PackedU8x32:
10422018555SXiang Li     return "p32u8";
10522018555SXiang Li   }
1064f54d715SJustin Bogner   llvm_unreachable("All ElementType enums are handled in switch");
10722018555SXiang Li }
10822018555SXiang Li 
109ad713186SJustin Bogner void ResourceBase::printElementType(ResourceKind Kind, ElementType ElTy,
1101fc78d66SXiang Li                                     unsigned Alignment, raw_ostream &OS) {
11122018555SXiang Li   switch (Kind) {
11222018555SXiang Li   default:
11322018555SXiang Li     // TODO: add vector size.
1144f54d715SJustin Bogner     OS << right_justify(getElementTypeName(ElTy), Alignment);
11522018555SXiang Li     break;
116ad713186SJustin Bogner   case ResourceKind::RawBuffer:
1171fc78d66SXiang Li     OS << right_justify("byte", Alignment);
11822018555SXiang Li     break;
119ad713186SJustin Bogner   case ResourceKind::StructuredBuffer:
1201fc78d66SXiang Li     OS << right_justify("struct", Alignment);
12122018555SXiang Li     break;
122ad713186SJustin Bogner   case ResourceKind::CBuffer:
123ad713186SJustin Bogner   case ResourceKind::Sampler:
1241fc78d66SXiang Li     OS << right_justify("NA", Alignment);
12522018555SXiang Li     break;
126ad713186SJustin Bogner   case ResourceKind::Invalid:
127ad713186SJustin Bogner   case ResourceKind::NumEntries:
12822018555SXiang Li     break;
12922018555SXiang Li   }
13022018555SXiang Li }
13122018555SXiang Li 
132ad713186SJustin Bogner StringRef ResourceBase::getKindName(ResourceKind Kind) {
13322018555SXiang Li   switch (Kind) {
134ad713186SJustin Bogner   case ResourceKind::NumEntries:
135ad713186SJustin Bogner   case ResourceKind::Invalid:
13622018555SXiang Li     return "invalid";
137ad713186SJustin Bogner   case ResourceKind::Texture1D:
13822018555SXiang Li     return "1d";
139ad713186SJustin Bogner   case ResourceKind::Texture2D:
14022018555SXiang Li     return "2d";
141ad713186SJustin Bogner   case ResourceKind::Texture2DMS:
14222018555SXiang Li     return "2dMS";
143ad713186SJustin Bogner   case ResourceKind::Texture3D:
14422018555SXiang Li     return "3d";
145ad713186SJustin Bogner   case ResourceKind::TextureCube:
14622018555SXiang Li     return "cube";
147ad713186SJustin Bogner   case ResourceKind::Texture1DArray:
14822018555SXiang Li     return "1darray";
149ad713186SJustin Bogner   case ResourceKind::Texture2DArray:
15022018555SXiang Li     return "2darray";
151ad713186SJustin Bogner   case ResourceKind::Texture2DMSArray:
15222018555SXiang Li     return "2darrayMS";
153ad713186SJustin Bogner   case ResourceKind::TextureCubeArray:
15422018555SXiang Li     return "cubearray";
155ad713186SJustin Bogner   case ResourceKind::TypedBuffer:
15622018555SXiang Li     return "buf";
157ad713186SJustin Bogner   case ResourceKind::RawBuffer:
15822018555SXiang Li     return "rawbuf";
159ad713186SJustin Bogner   case ResourceKind::StructuredBuffer:
16022018555SXiang Li     return "structbuf";
161ad713186SJustin Bogner   case ResourceKind::CBuffer:
16222018555SXiang Li     return "cbuffer";
163ad713186SJustin Bogner   case ResourceKind::Sampler:
16422018555SXiang Li     return "sampler";
165ad713186SJustin Bogner   case ResourceKind::TBuffer:
16622018555SXiang Li     return "tbuffer";
167ad713186SJustin Bogner   case ResourceKind::RTAccelerationStructure:
16822018555SXiang Li     return "ras";
169ad713186SJustin Bogner   case ResourceKind::FeedbackTexture2D:
17022018555SXiang Li     return "fbtex2d";
171ad713186SJustin Bogner   case ResourceKind::FeedbackTexture2DArray:
17222018555SXiang Li     return "fbtex2darray";
17322018555SXiang Li   }
174ad713186SJustin Bogner   llvm_unreachable("All ResourceKind enums are handled in switch");
17522018555SXiang Li }
17622018555SXiang Li 
177ad713186SJustin Bogner void ResourceBase::printKind(ResourceKind Kind, unsigned Alignment,
178ad713186SJustin Bogner                              raw_ostream &OS, bool SRV, bool HasCounter,
179ad713186SJustin Bogner                              uint32_t SampleCount) {
18022018555SXiang Li   switch (Kind) {
18122018555SXiang Li   default:
1821fc78d66SXiang Li     OS << right_justify(getKindName(Kind), Alignment);
18322018555SXiang Li     break;
18422018555SXiang Li 
185ad713186SJustin Bogner   case ResourceKind::RawBuffer:
186ad713186SJustin Bogner   case ResourceKind::StructuredBuffer:
18722018555SXiang Li     if (SRV)
1881fc78d66SXiang Li       OS << right_justify("r/o", Alignment);
18922018555SXiang Li     else {
19022018555SXiang Li       if (!HasCounter)
1911fc78d66SXiang Li         OS << right_justify("r/w", Alignment);
19222018555SXiang Li       else
1931fc78d66SXiang Li         OS << right_justify("r/w+cnt", Alignment);
19422018555SXiang Li     }
19522018555SXiang Li     break;
196ad713186SJustin Bogner   case ResourceKind::TypedBuffer:
1971fc78d66SXiang Li     OS << right_justify("buf", Alignment);
19822018555SXiang Li     break;
199ad713186SJustin Bogner   case ResourceKind::Texture2DMS:
200ad713186SJustin Bogner   case ResourceKind::Texture2DMSArray: {
2011fc78d66SXiang Li     std::string DimName = getKindName(Kind).str();
20222018555SXiang Li     if (SampleCount)
2031fc78d66SXiang Li       DimName += std::to_string(SampleCount);
2041fc78d66SXiang Li     OS << right_justify(DimName, Alignment);
20522018555SXiang Li   } break;
206ad713186SJustin Bogner   case ResourceKind::CBuffer:
207ad713186SJustin Bogner   case ResourceKind::Sampler:
2081fc78d66SXiang Li     OS << right_justify("NA", Alignment);
20922018555SXiang Li     break;
210ad713186SJustin Bogner   case ResourceKind::Invalid:
211ad713186SJustin Bogner   case ResourceKind::NumEntries:
21222018555SXiang Li     break;
21322018555SXiang Li   }
21422018555SXiang Li }
21522018555SXiang Li 
21622018555SXiang Li void ResourceBase::print(raw_ostream &OS, StringRef IDPrefix,
21722018555SXiang Li                          StringRef BindingPrefix) const {
21822018555SXiang Li   std::string ResID = IDPrefix.str();
21922018555SXiang Li   ResID += std::to_string(ID);
22022018555SXiang Li   OS << right_justify(ResID, 8);
22122018555SXiang Li 
22222018555SXiang Li   std::string Bind = BindingPrefix.str();
22322018555SXiang Li   Bind += std::to_string(LowerBound);
22422018555SXiang Li   if (Space)
22522018555SXiang Li     Bind += ",space" + std::to_string(Space);
22622018555SXiang Li 
22722018555SXiang Li   OS << right_justify(Bind, 15);
22822018555SXiang Li   if (RangeSize != UINT_MAX)
22922018555SXiang Li     OS << right_justify(std::to_string(RangeSize), 6) << "\n";
23022018555SXiang Li   else
23122018555SXiang Li     OS << right_justify("unbounded", 6) << "\n";
23222018555SXiang Li }
23322018555SXiang Li 
23422018555SXiang Li void UAVResource::print(raw_ostream &OS) const {
23522018555SXiang Li   OS << "; " << left_justify(Name, 31);
23622018555SXiang Li 
23722018555SXiang Li   OS << right_justify("UAV", 10);
23822018555SXiang Li 
2394f54d715SJustin Bogner   printElementType(Shape, ExtProps.ElementType.value_or(ElementType::Invalid),
2404f54d715SJustin Bogner                    8, OS);
24122018555SXiang Li 
24222018555SXiang Li   // FIXME: support SampleCount.
24322018555SXiang Li   // See https://github.com/llvm/llvm-project/issues/58175
24422018555SXiang Li   printKind(Shape, 12, OS, /*SRV*/ false, HasCounter);
24522018555SXiang Li   // Print the binding part.
24622018555SXiang Li   ResourceBase::print(OS, "U", "u");
24722018555SXiang Li }
24822018555SXiang Li 
249944f4b28SXiang Li ConstantBuffer::ConstantBuffer(uint32_t I, hlsl::FrontendResource R)
250944f4b28SXiang Li     : ResourceBase(I, R) {}
251944f4b28SXiang Li 
252944f4b28SXiang Li void ConstantBuffer::setSize(CBufferDataLayout &DL) {
253944f4b28SXiang Li   CBufferSizeInBytes = DL.getTypeAllocSizeInBytes(GV->getValueType());
254944f4b28SXiang Li }
255944f4b28SXiang Li 
256944f4b28SXiang Li void ConstantBuffer::print(raw_ostream &OS) const {
257944f4b28SXiang Li   OS << "; " << left_justify(Name, 31);
258944f4b28SXiang Li 
259944f4b28SXiang Li   OS << right_justify("cbuffer", 10);
260944f4b28SXiang Li 
261ad713186SJustin Bogner   printElementType(ResourceKind::CBuffer, ElementType::Invalid, 8, OS);
262944f4b28SXiang Li 
263ad713186SJustin Bogner   printKind(ResourceKind::CBuffer, 12, OS, /*SRV*/ false, /*HasCounter*/ false);
264944f4b28SXiang Li   // Print the binding part.
265944f4b28SXiang Li   ResourceBase::print(OS, "CB", "cb");
266944f4b28SXiang Li }
267944f4b28SXiang Li 
268944f4b28SXiang Li template <typename T> void ResourceTable<T>::print(raw_ostream &OS) const {
269944f4b28SXiang Li   for (auto &Res : Data)
270944f4b28SXiang Li     Res.print(OS);
271944f4b28SXiang Li }
272944f4b28SXiang Li 
2731fc78d66SXiang Li MDNode *ResourceBase::ExtendedProperties::write(LLVMContext &Ctx) const {
274618e5006SChris Bieneman   IRBuilder<> B(Ctx);
275618e5006SChris Bieneman   SmallVector<Metadata *> Entries;
276618e5006SChris Bieneman   if (ElementType) {
277618e5006SChris Bieneman     Entries.emplace_back(
278618e5006SChris Bieneman         ConstantAsMetadata::get(B.getInt32(TypedBufferElementType)));
279618e5006SChris Bieneman     Entries.emplace_back(ConstantAsMetadata::get(
280618e5006SChris Bieneman         B.getInt32(static_cast<uint32_t>(*ElementType))));
281618e5006SChris Bieneman   }
282618e5006SChris Bieneman   if (Entries.empty())
283618e5006SChris Bieneman     return nullptr;
284618e5006SChris Bieneman   return MDNode::get(Ctx, Entries);
285618e5006SChris Bieneman }
286618e5006SChris Bieneman 
287618e5006SChris Bieneman void ResourceBase::write(LLVMContext &Ctx,
2881fc78d66SXiang Li                          MutableArrayRef<Metadata *> Entries) const {
289618e5006SChris Bieneman   IRBuilder<> B(Ctx);
290618e5006SChris Bieneman   Entries[0] = ConstantAsMetadata::get(B.getInt32(ID));
291618e5006SChris Bieneman   Entries[1] = ConstantAsMetadata::get(GV);
292618e5006SChris Bieneman   Entries[2] = MDString::get(Ctx, Name);
293618e5006SChris Bieneman   Entries[3] = ConstantAsMetadata::get(B.getInt32(Space));
294618e5006SChris Bieneman   Entries[4] = ConstantAsMetadata::get(B.getInt32(LowerBound));
295618e5006SChris Bieneman   Entries[5] = ConstantAsMetadata::get(B.getInt32(RangeSize));
296618e5006SChris Bieneman }
297618e5006SChris Bieneman 
2981fc78d66SXiang Li MDNode *UAVResource::write() const {
299618e5006SChris Bieneman   auto &Ctx = GV->getContext();
300618e5006SChris Bieneman   IRBuilder<> B(Ctx);
301618e5006SChris Bieneman   Metadata *Entries[11];
302618e5006SChris Bieneman   ResourceBase::write(Ctx, Entries);
303618e5006SChris Bieneman   Entries[6] =
304618e5006SChris Bieneman       ConstantAsMetadata::get(B.getInt32(static_cast<uint32_t>(Shape)));
305618e5006SChris Bieneman   Entries[7] = ConstantAsMetadata::get(B.getInt1(GloballyCoherent));
306618e5006SChris Bieneman   Entries[8] = ConstantAsMetadata::get(B.getInt1(HasCounter));
307618e5006SChris Bieneman   Entries[9] = ConstantAsMetadata::get(B.getInt1(IsROV));
308618e5006SChris Bieneman   Entries[10] = ExtProps.write(Ctx);
309618e5006SChris Bieneman   return MDNode::get(Ctx, Entries);
310618e5006SChris Bieneman }
311618e5006SChris Bieneman 
312944f4b28SXiang Li MDNode *ConstantBuffer::write() const {
313944f4b28SXiang Li   auto &Ctx = GV->getContext();
314944f4b28SXiang Li   IRBuilder<> B(Ctx);
315944f4b28SXiang Li   Metadata *Entries[7];
316944f4b28SXiang Li   ResourceBase::write(Ctx, Entries);
317944f4b28SXiang Li 
318944f4b28SXiang Li   Entries[6] = ConstantAsMetadata::get(B.getInt32(CBufferSizeInBytes));
319944f4b28SXiang Li   return MDNode::get(Ctx, Entries);
320944f4b28SXiang Li }
321944f4b28SXiang Li 
322944f4b28SXiang Li template <typename T> MDNode *ResourceTable<T>::write(Module &M) const {
323944f4b28SXiang Li   if (Data.empty())
324944f4b28SXiang Li     return nullptr;
325944f4b28SXiang Li   SmallVector<Metadata *> MDs;
326944f4b28SXiang Li   for (auto &Res : Data)
327944f4b28SXiang Li     MDs.emplace_back(Res.write());
328944f4b28SXiang Li 
329944f4b28SXiang Li   NamedMDNode *Entry = M.getNamedMetadata(MDName);
330944f4b28SXiang Li   if (Entry)
331944f4b28SXiang Li     Entry->eraseFromParent();
332944f4b28SXiang Li 
333944f4b28SXiang Li   return MDNode::get(M.getContext(), MDs);
334944f4b28SXiang Li }
335944f4b28SXiang Li 
336*58eec851SJustin Bogner Metadata *Resources::writeUAVs(Module &M) const { return UAVs.write(M); }
337*58eec851SJustin Bogner void Resources::printUAVs(raw_ostream &OS) const { UAVs.print(OS); }
338*58eec851SJustin Bogner Metadata *Resources::writeCBuffers(Module &M) const {
339*58eec851SJustin Bogner   return CBuffers.write(M);
340b8615079SXiang Li }
341*58eec851SJustin Bogner void Resources::printCBuffers(raw_ostream &OS) const { CBuffers.print(OS); }
342618e5006SChris Bieneman 
343*58eec851SJustin Bogner void Resources::dump() const {
344*58eec851SJustin Bogner   printCBuffers(dbgs());
345*58eec851SJustin Bogner   printUAVs(dbgs());
346618e5006SChris Bieneman }
347