llvm-project/llvm/lib/Target/DirectX/DXILResource.cpp
Xiang Li 220185552f [DirectX backend] Add analysis to collect DXILResources
Now only DXILTranslateMetadata uses DXILResources, so DXILResourceWrapper is only used by DXILTranslateMetadata.
Once we add lower for createHandle, DXILResourceWrapper will be used in more passes.
Also we can add resource index allocation in DXILResourceWrapper.

Reviewed By: beanz

Differential Revision: https://reviews.llvm.org/D135190
2022-10-06 19:34:29 -07:00

360 lines
11 KiB
C++

//===- DXILResource.cpp - DXIL Resource helper objects --------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file This file contains helper objects for working with DXIL Resources.
///
//===----------------------------------------------------------------------===//
#include "DXILResource.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
using namespace llvm;
using namespace llvm::dxil;
GlobalVariable *FrontendResource::getGlobalVariable() {
return cast<GlobalVariable>(
cast<ConstantAsMetadata>(Entry->getOperand(0))->getValue());
}
StringRef FrontendResource::getSourceType() {
return cast<MDString>(Entry->getOperand(1))->getString();
}
Constant *FrontendResource::getID() {
return cast<ConstantAsMetadata>(Entry->getOperand(2))->getValue();
}
void Resources::collectUAVs(Module &M) {
NamedMDNode *Entry = M.getNamedMetadata("hlsl.uavs");
if (!Entry || Entry->getNumOperands() == 0)
return;
uint32_t Counter = 0;
for (auto *UAV : Entry->operands()) {
UAVs.push_back(UAVResource(Counter++, FrontendResource(cast<MDNode>(UAV))));
}
}
void Resources::collect(Module &M) { collectUAVs(M); }
ResourceBase::ResourceBase(uint32_t I, FrontendResource R)
: ID(I), GV(R.getGlobalVariable()), Name(""), Space(0), LowerBound(0),
RangeSize(1) {
if (auto *ArrTy = dyn_cast<ArrayType>(GV->getInitializer()->getType()))
RangeSize = ArrTy->getNumElements();
}
StringRef ResourceBase::getComponentTypeName(ComponentType CompType) {
switch (CompType) {
case ComponentType::LastEntry:
case ComponentType::Invalid:
return "invalid";
case ComponentType::I1:
return "i1";
case ComponentType::I16:
return "i16";
case ComponentType::U16:
return "u16";
case ComponentType::I32:
return "i32";
case ComponentType::U32:
return "u32";
case ComponentType::I64:
return "i64";
case ComponentType::U64:
return "u64";
case ComponentType::F16:
return "f16";
case ComponentType::F32:
return "f32";
case ComponentType::F64:
return "f64";
case ComponentType::SNormF16:
return "snorm_f16";
case ComponentType::UNormF16:
return "unorm_f16";
case ComponentType::SNormF32:
return "snorm_f32";
case ComponentType::UNormF32:
return "unorm_f32";
case ComponentType::SNormF64:
return "snorm_f64";
case ComponentType::UNormF64:
return "unorm_f64";
case ComponentType::PackedS8x32:
return "p32i8";
case ComponentType::PackedU8x32:
return "p32u8";
}
}
void ResourceBase::printComponentType(Kinds Kind, ComponentType CompType,
unsigned alignment, raw_ostream &OS) {
switch (Kind) {
default:
// TODO: add vector size.
OS << right_justify(getComponentTypeName(CompType), alignment);
break;
case Kinds::RawBuffer:
OS << right_justify("byte", alignment);
break;
case Kinds::StructuredBuffer:
OS << right_justify("struct", alignment);
break;
case Kinds::CBuffer:
case Kinds::Sampler:
OS << right_justify("NA", alignment);
break;
case Kinds::Invalid:
case Kinds::NumEntries:
break;
}
}
StringRef ResourceBase::getKindName(Kinds Kind) {
switch (Kind) {
case Kinds::NumEntries:
case Kinds::Invalid:
return "invalid";
case Kinds::Texture1D:
return "1d";
case Kinds::Texture2D:
return "2d";
case Kinds::Texture2DMS:
return "2dMS";
case Kinds::Texture3D:
return "3d";
case Kinds::TextureCube:
return "cube";
case Kinds::Texture1DArray:
return "1darray";
case Kinds::Texture2DArray:
return "2darray";
case Kinds::Texture2DMSArray:
return "2darrayMS";
case Kinds::TextureCubeArray:
return "cubearray";
case Kinds::TypedBuffer:
return "buf";
case Kinds::RawBuffer:
return "rawbuf";
case Kinds::StructuredBuffer:
return "structbuf";
case Kinds::CBuffer:
return "cbuffer";
case Kinds::Sampler:
return "sampler";
case Kinds::TBuffer:
return "tbuffer";
case Kinds::RTAccelerationStructure:
return "ras";
case Kinds::FeedbackTexture2D:
return "fbtex2d";
case Kinds::FeedbackTexture2DArray:
return "fbtex2darray";
}
}
void ResourceBase::printKind(Kinds Kind, unsigned alignment, raw_ostream &OS,
bool SRV, bool HasCounter, uint32_t SampleCount) {
switch (Kind) {
default:
OS << right_justify(getKindName(Kind), alignment);
break;
case Kinds::RawBuffer:
case Kinds::StructuredBuffer:
if (SRV)
OS << right_justify("r/o", alignment);
else {
if (!HasCounter)
OS << right_justify("r/w", alignment);
else
OS << right_justify("r/w+cnt", alignment);
}
break;
case Kinds::TypedBuffer:
OS << right_justify("buf", alignment);
break;
case Kinds::Texture2DMS:
case Kinds::Texture2DMSArray: {
std::string dimName = getKindName(Kind).str();
if (SampleCount)
dimName += std::to_string(SampleCount);
OS << right_justify(dimName, alignment);
} break;
case Kinds::CBuffer:
case Kinds::Sampler:
OS << right_justify("NA", alignment);
break;
case Kinds::Invalid:
case Kinds::NumEntries:
break;
}
}
void ResourceBase::print(raw_ostream &OS, StringRef IDPrefix,
StringRef BindingPrefix) const {
std::string ResID = IDPrefix.str();
ResID += std::to_string(ID);
OS << right_justify(ResID, 8);
std::string Bind = BindingPrefix.str();
Bind += std::to_string(LowerBound);
if (Space)
Bind += ",space" + std::to_string(Space);
OS << right_justify(Bind, 15);
if (RangeSize != UINT_MAX)
OS << right_justify(std::to_string(RangeSize), 6) << "\n";
else
OS << right_justify("unbounded", 6) << "\n";
}
UAVResource::UAVResource(uint32_t I, FrontendResource R)
: ResourceBase(I, R), Shape(Kinds::Invalid), GloballyCoherent(false),
HasCounter(false), IsROV(false), ExtProps() {
parseSourceType(R.getSourceType());
}
void UAVResource::print(raw_ostream &OS) const {
OS << "; " << left_justify(Name, 31);
OS << right_justify("UAV", 10);
printComponentType(
Shape, ExtProps.ElementType.value_or(ComponentType::Invalid), 8, OS);
// FIXME: support SampleCount.
// See https://github.com/llvm/llvm-project/issues/58175
printKind(Shape, 12, OS, /*SRV*/ false, HasCounter);
// Print the binding part.
ResourceBase::print(OS, "U", "u");
}
// FIXME: Capture this in HLSL source. I would go do this right now, but I want
// to get this in first so that I can make sure to capture all the extra
// information we need to remove the source type string from here (See issue:
// https://github.com/llvm/llvm-project/issues/57991).
void UAVResource::parseSourceType(StringRef S) {
IsROV = S.startswith("RasterizerOrdered");
if (IsROV)
S = S.substr(strlen("RasterizerOrdered"));
if (S.startswith("RW"))
S = S.substr(strlen("RW"));
// Note: I'm deliberately not handling any of the Texture buffer types at the
// moment. I want to resolve the issue above before adding Texture or Sampler
// support.
Shape = StringSwitch<ResourceBase::Kinds>(S)
.StartsWith("Buffer<", Kinds::TypedBuffer)
.StartsWith("ByteAddressBuffer<", Kinds::RawBuffer)
.StartsWith("StructuredBuffer<", Kinds::StructuredBuffer)
.Default(Kinds::Invalid);
assert(Shape != Kinds::Invalid && "Unsupported buffer type");
S = S.substr(S.find("<") + 1);
constexpr size_t PrefixLen = StringRef("vector<").size();
if (S.startswith("vector<"))
S = S.substr(PrefixLen, S.find(",") - PrefixLen);
else
S = S.substr(0, S.find(">"));
ComponentType ElTy = StringSwitch<ResourceBase::ComponentType>(S)
.Case("bool", ComponentType::I1)
.Case("int16_t", ComponentType::I16)
.Case("uint16_t", ComponentType::U16)
.Case("int32_t", ComponentType::I32)
.Case("uint32_t", ComponentType::U32)
.Case("int64_t", ComponentType::I64)
.Case("uint64_t", ComponentType::U64)
.Case("half", ComponentType::F16)
.Case("float", ComponentType::F32)
.Case("double", ComponentType::F64)
.Default(ComponentType::Invalid);
if (ElTy != ComponentType::Invalid)
ExtProps.ElementType = ElTy;
}
MDNode *ResourceBase::ExtendedProperties::write(LLVMContext &Ctx) {
IRBuilder<> B(Ctx);
SmallVector<Metadata *> Entries;
if (ElementType) {
Entries.emplace_back(
ConstantAsMetadata::get(B.getInt32(TypedBufferElementType)));
Entries.emplace_back(ConstantAsMetadata::get(
B.getInt32(static_cast<uint32_t>(*ElementType))));
}
if (Entries.empty())
return nullptr;
return MDNode::get(Ctx, Entries);
}
void ResourceBase::write(LLVMContext &Ctx,
MutableArrayRef<Metadata *> Entries) {
IRBuilder<> B(Ctx);
Entries[0] = ConstantAsMetadata::get(B.getInt32(ID));
Entries[1] = ConstantAsMetadata::get(GV);
Entries[2] = MDString::get(Ctx, Name);
Entries[3] = ConstantAsMetadata::get(B.getInt32(Space));
Entries[4] = ConstantAsMetadata::get(B.getInt32(LowerBound));
Entries[5] = ConstantAsMetadata::get(B.getInt32(RangeSize));
}
MDNode *UAVResource::write() {
auto &Ctx = GV->getContext();
IRBuilder<> B(Ctx);
Metadata *Entries[11];
ResourceBase::write(Ctx, Entries);
Entries[6] =
ConstantAsMetadata::get(B.getInt32(static_cast<uint32_t>(Shape)));
Entries[7] = ConstantAsMetadata::get(B.getInt1(GloballyCoherent));
Entries[8] = ConstantAsMetadata::get(B.getInt1(HasCounter));
Entries[9] = ConstantAsMetadata::get(B.getInt1(IsROV));
Entries[10] = ExtProps.write(Ctx);
return MDNode::get(Ctx, Entries);
}
void Resources::write(Module &M) {
Metadata *ResourceMDs[4] = {nullptr, nullptr, nullptr, nullptr};
SmallVector<Metadata *> UAVMDs;
for (auto &UAV : UAVs)
UAVMDs.emplace_back(UAV.write());
if (!UAVMDs.empty())
ResourceMDs[1] = MDNode::get(M.getContext(), UAVMDs);
NamedMDNode *DXResMD = M.getOrInsertNamedMetadata("dx.resources");
DXResMD->addOperand(MDNode::get(M.getContext(), ResourceMDs));
NamedMDNode *Entry = M.getNamedMetadata("hlsl.uavs");
if (Entry)
Entry->eraseFromParent();
}
void Resources::print(raw_ostream &O) const {
O << ";\n"
<< "; Resource Bindings:\n"
<< ";\n"
<< "; Name Type Format Dim "
"ID HLSL Bind Count\n"
<< "; ------------------------------ ---------- ------- ----------- "
"------- -------------- ------\n";
for (auto &UAV : UAVs)
UAV.print(O);
}
void Resources::dump() const { print(dbgs()); }