Skip to content

[HLSL] Remove old resource annotations #130338

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions clang/lib/CodeGen/CGDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1071,9 +1071,6 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit);
}

if (getLangOpts().HLSL)
CGM.getHLSLRuntime().annotateHLSLResource(D, Addr);

FinishFunction();
}

Expand Down
129 changes: 0 additions & 129 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,135 +291,6 @@ void CGHLSLRuntime::finishCodeGen() {
generateGlobalCtorDtorCalls();
}

void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
llvm::hlsl::ResourceClass RC,
llvm::hlsl::ResourceKind RK,
bool IsROV,
llvm::hlsl::ElementType ET,
BufferResBinding &Binding) {
llvm::Module &M = CGM.getModule();

NamedMDNode *ResourceMD = nullptr;
switch (RC) {
case llvm::hlsl::ResourceClass::UAV:
ResourceMD = M.getOrInsertNamedMetadata("hlsl.uavs");
break;
case llvm::hlsl::ResourceClass::SRV:
ResourceMD = M.getOrInsertNamedMetadata("hlsl.srvs");
break;
case llvm::hlsl::ResourceClass::CBuffer:
ResourceMD = M.getOrInsertNamedMetadata("hlsl.cbufs");
break;
default:
assert(false && "Unsupported buffer type!");
return;
}
assert(ResourceMD != nullptr &&
"ResourceMD must have been set by the switch above.");

llvm::hlsl::FrontendResource Res(
GV, RK, ET, IsROV, Binding.Reg.value_or(UINT_MAX), Binding.Space);
ResourceMD->addOperand(Res.getMetadata());
}

static llvm::hlsl::ElementType
calculateElementType(const ASTContext &Context, const clang::Type *ResourceTy) {
using llvm::hlsl::ElementType;

// TODO: We may need to update this when we add things like ByteAddressBuffer
// that don't have a template parameter (or, indeed, an element type).
const auto *TST = ResourceTy->getAs<TemplateSpecializationType>();
assert(TST && "Resource types must be template specializations");
ArrayRef<TemplateArgument> Args = TST->template_arguments();
assert(!Args.empty() && "Resource has no element type");

// At this point we have a resource with an element type, so we can assume
// that it's valid or we would have diagnosed the error earlier.
QualType ElTy = Args[0].getAsType();

// We should either have a basic type or a vector of a basic type.
if (const auto *VecTy = ElTy->getAs<clang::VectorType>())
ElTy = VecTy->getElementType();

if (ElTy->isSignedIntegerType()) {
switch (Context.getTypeSize(ElTy)) {
case 16:
return ElementType::I16;
case 32:
return ElementType::I32;
case 64:
return ElementType::I64;
}
} else if (ElTy->isUnsignedIntegerType()) {
switch (Context.getTypeSize(ElTy)) {
case 16:
return ElementType::U16;
case 32:
return ElementType::U32;
case 64:
return ElementType::U64;
}
} else if (ElTy->isSpecificBuiltinType(BuiltinType::Half))
return ElementType::F16;
else if (ElTy->isSpecificBuiltinType(BuiltinType::Float))
return ElementType::F32;
else if (ElTy->isSpecificBuiltinType(BuiltinType::Double))
return ElementType::F64;

// TODO: We need to handle unorm/snorm float types here once we support them
llvm_unreachable("Invalid element type for resource");
}

void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
const Type *Ty = D->getType()->getPointeeOrArrayElementType();
if (!Ty)
return;
const auto *RD = Ty->getAsCXXRecordDecl();
if (!RD)
return;
// the resource related attributes are on the handle member
// inside the record decl
for (auto *FD : RD->fields()) {
const auto *HLSLResAttr = FD->getAttr<HLSLResourceAttr>();
const HLSLAttributedResourceType *AttrResType =
dyn_cast<HLSLAttributedResourceType>(FD->getType().getTypePtr());
if (!HLSLResAttr || !AttrResType)
continue;

llvm::hlsl::ResourceClass RC = AttrResType->getAttrs().ResourceClass;
if (RC == llvm::hlsl::ResourceClass::UAV ||
RC == llvm::hlsl::ResourceClass::SRV)
// UAVs and SRVs have already been converted to use LLVM target types,
// we can disable generating of these resource annotations. This will
// enable progress on structured buffers with user defined types this
// resource annotations code does not handle and it crashes.
// This whole function is going to be removed as soon as cbuffers are
// converted to target types (llvm/llvm-project #114126).
return;

bool IsROV = AttrResType->getAttrs().IsROV;
llvm::hlsl::ResourceKind RK = HLSLResAttr->getResourceKind();
llvm::hlsl::ElementType ET = calculateElementType(CGM.getContext(), Ty);

BufferResBinding Binding(D->getAttr<HLSLResourceBindingAttr>());
addBufferResourceAnnotation(GV, RC, RK, IsROV, ET, Binding);
}
}

CGHLSLRuntime::BufferResBinding::BufferResBinding(
HLSLResourceBindingAttr *Binding) {
if (Binding) {
llvm::APInt RegInt(64, 0);
Binding->getSlot().substr(1).getAsInteger(10, RegInt);
Reg = RegInt.getLimitedValue();
llvm::APInt SpaceInt(64, 0);
Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
Space = SpaceInt.getLimitedValue();
} else {
Space = 0;
}
}

void clang::CodeGen::CGHLSLRuntime::setHLSLEntryAttributes(
const FunctionDecl *FD, llvm::Function *Fn) {
const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
Expand Down
15 changes: 0 additions & 15 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,6 @@ class CGHLSLRuntime {
// End of reserved area for HLSL intrinsic getters.
//===----------------------------------------------------------------------===//

struct BufferResBinding {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May I ask how the buffer register number 2 is being stored when this goes away?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The register number and space are used in the llvm.dx.resource.handlefrombinding intrinsic call when the code to initialize the resource is generated. Then in the LLVM backed the DXILResourceBindingAnalysis analyzes the code and collects information about all the shader resources and their bindings based on these calls. This info is then used by other LLVM passes to make sure we generate the correct "dx.resources" metadata in the DXIL container.

// The ID like 2 in register(b2, space1).
std::optional<unsigned> Reg;
// The Space like 1 is register(b2, space1).
// Default value is 0.
unsigned Space;
BufferResBinding(HLSLResourceBindingAttr *Attr);
};

protected:
CodeGenModule &CGM;

Expand All @@ -148,7 +139,6 @@ class CGHLSLRuntime {
convertHLSLSpecificType(const Type *T,
SmallVector<int32_t> *Packoffsets = nullptr);

void annotateHLSLResource(const VarDecl *D, llvm::GlobalVariable *GV);
void generateGlobalCtorDtorCalls();

void addBuffer(const HLSLBufferDecl *D);
Expand All @@ -169,11 +159,6 @@ class CGHLSLRuntime {
void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E);

private:
void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
llvm::hlsl::ResourceClass RC,
llvm::hlsl::ResourceKind RK, bool IsROV,
llvm::hlsl::ElementType ET,
BufferResBinding &Binding);
void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
llvm::GlobalVariable *BufGV);
llvm::Triple::ArchType getArch();
Expand Down
22 changes: 0 additions & 22 deletions llvm/include/llvm/Frontend/HLSL/HLSLResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,17 @@
#ifndef LLVM_FRONTEND_HLSL_HLSLRESOURCE_H
#define LLVM_FRONTEND_HLSL_HLSLRESOURCE_H

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DXILABI.h"

namespace llvm {
class GlobalVariable;
class MDNode;

namespace hlsl {

// For now we use DXIL ABI enum values directly. This may change in the future.
using dxil::ResourceClass;
using dxil::ElementType;
using dxil::ResourceKind;

const unsigned CBufferRowSizeInBytes = 16U;

class FrontendResource {
MDNode *Entry;

public:
FrontendResource(MDNode *E);
FrontendResource(GlobalVariable *GV, ResourceKind RK, ElementType ElTy,
bool IsROV, uint32_t ResIndex, uint32_t Space);

GlobalVariable *getGlobalVariable();
StringRef getSourceType();
ResourceKind getResourceKind();
ElementType getElementType();
bool getIsROV();
uint32_t getResourceIndex();
uint32_t getSpace();
MDNode *getMetadata() { return Entry; }
};
} // namespace hlsl
} // namespace llvm

Expand Down
54 changes: 2 additions & 52 deletions llvm/lib/Frontend/HLSL/HLSLResource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,59 +11,9 @@
//===----------------------------------------------------------------------===//

#include "llvm/Frontend/HLSL/HLSLResource.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Metadata.h"

using namespace llvm;
using namespace llvm::hlsl;

GlobalVariable *FrontendResource::getGlobalVariable() {
return cast<GlobalVariable>(
cast<ConstantAsMetadata>(Entry->getOperand(0))->getValue());
}

ResourceKind FrontendResource::getResourceKind() {
return static_cast<ResourceKind>(
cast<ConstantInt>(
cast<ConstantAsMetadata>(Entry->getOperand(1))->getValue())
->getLimitedValue());
}
ElementType FrontendResource::getElementType() {
return static_cast<ElementType>(
cast<ConstantInt>(
cast<ConstantAsMetadata>(Entry->getOperand(2))->getValue())
->getLimitedValue());
}
bool FrontendResource::getIsROV() {
return cast<ConstantInt>(
cast<ConstantAsMetadata>(Entry->getOperand(3))->getValue())
->getLimitedValue();
}
uint32_t FrontendResource::getResourceIndex() {
return cast<ConstantInt>(
cast<ConstantAsMetadata>(Entry->getOperand(4))->getValue())
->getLimitedValue();
}
uint32_t FrontendResource::getSpace() {
return cast<ConstantInt>(
cast<ConstantAsMetadata>(Entry->getOperand(5))->getValue())
->getLimitedValue();
}

FrontendResource::FrontendResource(MDNode *E) : Entry(E) {
assert(Entry->getNumOperands() == 6 && "Unexpected metadata shape");
}

FrontendResource::FrontendResource(GlobalVariable *GV, ResourceKind RK,
ElementType ElTy, bool IsROV,
uint32_t ResIndex, uint32_t Space) {
auto &Ctx = GV->getContext();
IRBuilder<> B(Ctx);
Entry = MDNode::get(
Ctx, {ValueAsMetadata::get(GV),
ConstantAsMetadata::get(B.getInt32(static_cast<int>(RK))),
ConstantAsMetadata::get(B.getInt32(static_cast<int>(ElTy))),
ConstantAsMetadata::get(B.getInt1(IsROV)),
ConstantAsMetadata::get(B.getInt32(ResIndex)),
ConstantAsMetadata::get(B.getInt32(Space))});
}
// Intentionally empty; this file can be removed when more cpp files are added
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind explaining why more cpp files being added later justifies the removal of this file later instead of now?
Is it because it's more convenient to unlink this file from the cmakelists when adding new cpp files and the cmakelists needs to be updated anyways?

Copy link
Member Author

@hekota hekota Mar 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HLSLResource.cpp is currently the only file in the FrontendHLSL library. If I remove it the library does not have any source files, and the compiler/linker is not happy about that. I don't want to remove the whole library because I know more changes are coming in here soon (#125131), so I have decided to just leave it in with a comment.

// to the HLSLFrontend lib.