Skip to content

[HLSL] Allow resource annotations to specify only register space #135287

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 16 commits into from
Apr 30, 2025
Merged
Show file tree
Hide file tree
Changes from 7 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
11 changes: 8 additions & 3 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -4751,20 +4751,25 @@ def HLSLResourceBinding: InheritableAttr {

private:
RegisterType RegType;
unsigned SlotNumber;
int SlotNumber; // -1 if the register slot was not specified
unsigned SpaceNumber;

public:
void setBinding(RegisterType RT, unsigned SlotNum, unsigned SpaceNum) {
void setBinding(RegisterType RT, int SlotNum, unsigned SpaceNum) {
RegType = RT;
SlotNumber = SlotNum;
SpaceNumber = SpaceNum;
}
bool isImplicit() const {
return SlotNumber < 0;
}
RegisterType getRegisterType() const {
assert(!isImplicit() && "binding does not have register slot");
return RegType;
}
unsigned getSlotNumber() const {
return SlotNumber;
assert(!isImplicit() && "binding does not have register slot");
return (unsigned)SlotNumber;
}
unsigned getSpaceNumber() const {
return SpaceNumber;
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -4789,6 +4789,18 @@ def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}

def HLSLResourceCreatePoisonHandle : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_resource_createpoisonhandle"];
let Attributes = [NoThrow];
let Prototype = "void(...)";
}

def HLSLResourceCreateHandleFromBinding : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_resource_createhandlefrombinding"];
let Attributes = [NoThrow];
let Prototype = "void(...)";
}

def HLSLAll : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_all"];
let Attributes = [NoThrow, Const];
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class SemaHLSL : public SemaBase {
HLSLParamModifierAttr::Spelling Spelling);
void ActOnTopLevelFunction(FunctionDecl *FD);
void ActOnVariableDeclarator(VarDecl *VD);
bool ActOnUninitializedVarDecl(VarDecl *D);
void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU);
void CheckEntryPoint(FunctionDecl *FD);
void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/CodeGen/CGHLSLBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,24 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
ArrayRef<Value *>{HandleOp, IndexOp});
}
case Builtin::BI__builtin_hlsl_resource_createpoisonhandle: {
llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
return llvm::PoisonValue::get(HandleTy);
}
case Builtin::BI__builtin_hlsl_resource_createhandlefrombinding: {
llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
Value *RegisterNoOp = EmitScalarExpr(E->getArg(1));
Value *SpaceNoOp = EmitScalarExpr(E->getArg(2));
Value *RangeOp = EmitScalarExpr(E->getArg(3));
Value *IndexOp = EmitScalarExpr(E->getArg(4));
// FIXME: NonUniformResourceIndex bit is not yet implemented
Value *NonUniform =
llvm::ConstantInt::get(llvm::Type::getInt1Ty(getLLVMContext()), false);
return Builder.CreateIntrinsic(
HandleTy, CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(),
ArrayRef<Value *>{SpaceNoOp, RegisterNoOp, RangeOp, IndexOp,
NonUniform});
}
case Builtin::BI__builtin_hlsl_all: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
return Builder.CreateIntrinsic(
Expand Down
77 changes: 29 additions & 48 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ using namespace llvm;

using llvm::hlsl::CBufferRowSizeInBytes;

static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
unsigned Slot, unsigned Space);
static void initializeBufferFromBinding(CodeGenModule &CGM,
llvm::GlobalVariable *GV, unsigned Slot,
unsigned Space);

namespace {

Expand Down Expand Up @@ -255,14 +256,14 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
// Add globals for constant buffer elements and create metadata nodes
emitBufferGlobalsAndMetadata(BufDecl, BufGV);

// Resource initialization
// Initialize cbuffer from binding (implicit or explicit)
const HLSLResourceBindingAttr *RBA =
BufDecl->getAttr<HLSLResourceBindingAttr>();
// FIXME: handle implicit binding if no binding attribute is found
// (llvm/llvm-project#110722)
if (RBA)
createResourceInitFn(CGM, BufGV, RBA->getSlotNumber(),
RBA->getSpaceNumber());
if (RBA && !RBA->isImplicit())
initializeBufferFromBinding(CGM, BufGV, RBA->getSlotNumber(),
RBA->getSpaceNumber());
}

llvm::TargetExtType *
Expand Down Expand Up @@ -494,15 +495,15 @@ void CGHLSLRuntime::generateGlobalCtorDtorCalls() {
}
}

static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
unsigned Slot, unsigned Space) {
LLVMContext &Ctx = CGM.getLLVMContext();
llvm::Type *Int1Ty = llvm::Type::getInt1Ty(Ctx);
static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
Intrinsic::ID IntrID,
ArrayRef<llvm::Value *> Args) {

LLVMContext &Ctx = CGM.getLLVMContext();
llvm::Function *InitResFunc = llvm::Function::Create(
llvm::FunctionType::get(CGM.VoidTy, false),
llvm::GlobalValue::InternalLinkage,
("_init_resource_" + GV->getName()).str(), CGM.getModule());
("_init_buffer_" + GV->getName()).str(), CGM.getModule());
InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);

llvm::BasicBlock *EntryBB =
Expand All @@ -511,28 +512,12 @@ static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
const DataLayout &DL = CGM.getModule().getDataLayout();
Builder.SetInsertPoint(EntryBB);

// Make sure the global variable is resource handle (cbuffer) or
// resource class (=class where the first element is a resource handle).
// Make sure the global variable is buffer resource handle
llvm::Type *HandleTy = GV->getValueType();
assert((HandleTy->isTargetExtTy() ||
(HandleTy->isStructTy() &&
HandleTy->getStructElementType(0)->isTargetExtTy())) &&
"unexpected type of the global");
if (!HandleTy->isTargetExtTy())
HandleTy = HandleTy->getStructElementType(0);
assert(HandleTy->isTargetExtTy() && "unexpected type of the buffer global");

llvm::Value *Args[] = {
llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */
llvm::ConstantInt::get(CGM.IntTy, Slot), /* lower_bound */
// FIXME: resource arrays are not yet implemented
llvm::ConstantInt::get(CGM.IntTy, 1), /* range_size */
llvm::ConstantInt::get(CGM.IntTy, 0), /* index */
// FIXME: NonUniformResourceIndex bit is not yet implemented
llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */
};
llvm::Value *CreateHandle = Builder.CreateIntrinsic(
/*ReturnType=*/HandleTy,
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(), Args, nullptr,
/*ReturnType=*/HandleTy, IntrID, Args, nullptr,
Twine(GV->getName()).concat("_h"));

llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0);
Expand All @@ -543,24 +528,20 @@ static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
CGM.AddCXXGlobalInit(InitResFunc);
}

void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
llvm::GlobalVariable *GV) {

// If the global variable has resource binding, create an init function
// for the resource
const HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
if (!RBA)
// FIXME: collect unbound resources for implicit binding resolution later
// on?
return;

if (!VD->getType().getTypePtr()->isHLSLResourceRecord())
// FIXME: Only simple declarations of resources are supported for now.
// Arrays of resources or resources in user defined classes are
// not implemented yet.
return;

createResourceInitFn(CGM, GV, RBA->getSlotNumber(), RBA->getSpaceNumber());
static void initializeBufferFromBinding(CodeGenModule &CGM,
llvm::GlobalVariable *GV, unsigned Slot,
unsigned Space) {
llvm::Type *Int1Ty = llvm::Type::getInt1Ty(CGM.getLLVMContext());
llvm::Value *Args[] = {
llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */
llvm::ConstantInt::get(CGM.IntTy, Slot), /* lower_bound */
llvm::ConstantInt::get(CGM.IntTy, 1), /* range_size */
llvm::ConstantInt::get(CGM.IntTy, 0), /* index */
llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */
};
initializeBuffer(CGM, GV,
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(),
Args);
}

llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
Expand Down
1 change: 0 additions & 1 deletion clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ class CGHLSLRuntime {

void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn);
void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn);
void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var);

llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);

Expand Down
3 changes: 0 additions & 3 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5698,9 +5698,6 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
getCUDARuntime().handleVarRegistration(D, *GV);
}

if (LangOpts.HLSL)
getHLSLRuntime().handleGlobalVarDefinition(D, GV);

GV->setInitializer(Init);
if (emitter)
emitter->finalize(GV);
Expand Down
11 changes: 8 additions & 3 deletions clang/lib/Parse/ParseHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,16 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
SourceLocation SlotLoc = Tok.getLocation();
ArgExprs.push_back(ParseIdentifierLoc());

// Add numeric_constant for fix-it.
if (SlotStr.size() == 1 && Tok.is(tok::numeric_constant))
if (SlotStr.size() == 1) {
if (!Tok.is(tok::numeric_constant)) {
Diag(Tok.getLocation(), diag::err_expected) << tok::numeric_constant;
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
// Add numeric_constant for fix-it.
fixSeparateAttrArgAndNumber(SlotStr, SlotLoc, Tok, ArgExprs, *this,
Actions.Context, PP);

}
if (Tok.is(tok::comma)) {
ConsumeToken(); // consume comma
if (!Tok.is(tok::identifier)) {
Expand Down
36 changes: 32 additions & 4 deletions clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ void BuiltinTypeMethodBuilder::createDecl() {

// create params & set them to the function prototype
SmallVector<ParmVarDecl *> ParmDecls;
unsigned CurScopeDepth = DeclBuilder.SemaRef.getCurScope()->getDepth();
auto FnProtoLoc =
Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>();
for (int I = 0, E = Params.size(); I != E; I++) {
Expand All @@ -414,6 +415,7 @@ void BuiltinTypeMethodBuilder::createDecl() {
HLSLParamModifierAttr::Create(AST, SourceRange(), MP.Modifier);
Parm->addAttr(Mod);
}
Parm->setScopeInfo(CurScopeDepth, I);
ParmDecls.push_back(Parm);
FnProtoLoc.setParam(I, Parm);
}
Expand Down Expand Up @@ -447,10 +449,14 @@ BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
FD->getNameInfo(), AST.BuiltinFnTy, VK_PRValue);

auto *ImpCast = ImplicitCastExpr::Create(
AST, AST.getPointerType(FD->getType()), CK_BuiltinFnToFnPtr, DRE, nullptr,
VK_PRValue, FPOptionsOverride());

if (ReturnType.isNull())
ReturnType = FD->getReturnType();

Expr *Call = CallExpr::Create(AST, DRE, Args, ReturnType, VK_PRValue,
Expr *Call = CallExpr::Create(AST, ImpCast, Args, ReturnType, VK_PRValue,
SourceLocation(), FPOptionsOverride());
StmtsList.push_back(Call);
return *this;
Expand Down Expand Up @@ -632,11 +638,33 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() {
if (Record->isCompleteDefinition())
return *this;

// FIXME: initialize handle to poison value; this can be added after
// resource constructor from binding is implemented, otherwise the handle
// value will get overwritten.
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
QualType HandleType = getResourceHandleField()->getType();
return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy,
false, true)
.callBuiltin("__builtin_hlsl_resource_createpoisonhandle", HandleType,
PH::Handle)
.assign(PH::Handle, PH::LastStmt)
.finalize();
}

BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addHandleConstructorFromBinding() {
if (Record->isCompleteDefinition())
return *this;

using PH = BuiltinTypeMethodBuilder::PlaceHolder;
ASTContext &AST = SemaRef.getASTContext();
QualType HandleType = getResourceHandleField()->getType();

return BuiltinTypeMethodBuilder(*this, "", AST.VoidTy, false, true)
.addParam("registerNo", AST.UnsignedIntTy)
.addParam("spaceNo", AST.UnsignedIntTy)
.addParam("range", AST.IntTy)
.addParam("index", AST.UnsignedIntTy)
.callBuiltin("__builtin_hlsl_resource_createhandlefrombinding",
HandleType, PH::Handle, PH::_0, PH::_1, PH::_2, PH::_3)
.assign(PH::Handle, PH::LastStmt)
.finalize();
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class BuiltinTypeDeclBuilder {

// Builtin types methods
BuiltinTypeDeclBuilder &addDefaultHandleConstructor();
BuiltinTypeDeclBuilder &addHandleConstructorFromBinding();

// Builtin types methods
BuiltinTypeDeclBuilder &addLoadMethods();
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
bool RawBuffer) {
return BuiltinTypeDeclBuilder(S, Decl)
.addHandleMember(RC, IsROV, RawBuffer)
.addDefaultHandleConstructor();
.addDefaultHandleConstructor()
.addHandleConstructorFromBinding();
}

// This function is responsible for constructing the constraint expression for
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14345,10 +14345,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
Var->getType().getAddressSpace() == LangAS::opencl_local)
return;

// In HLSL, objects in the hlsl_constant address space are initialized
// externally, so don't synthesize an implicit initializer.
if (getLangOpts().HLSL &&
Var->getType().getAddressSpace() == LangAS::hlsl_constant)
// Handle HLSL uninitialized decls
if (getLangOpts().HLSL && HLSL().ActOnUninitializedVarDecl(Var))
return;

// C++03 [dcl.init]p9:
Expand Down
Loading