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