[llvm-branch-commits] [clang] [llvm] [HLSL] Allow resource annotations to specify only register space (PR #135287)
Helena Kotas via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Apr 11 12:21:53 PDT 2025
https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/135287
>From 6fb658a603f116f29e635e4802a8d77b896150ff Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 10 Apr 2025 17:31:57 -0700
Subject: [PATCH 1/4] [HLSL] Allow register annotations to specify only `space`
Specifying only `space` in a `register` annotation means the compiler should
implicitly assign a register slot to the resource from the provided virtual
register space.
---
clang/include/clang/Basic/Attr.td | 11 ++-
clang/lib/CodeGen/CGHLSLRuntime.cpp | 2 +-
clang/lib/Sema/SemaHLSL.cpp | 74 +++++++++++--------
.../test/AST/HLSL/resource_binding_attr.hlsl | 4 +
.../SemaHLSL/resource_binding_attr_error.hlsl | 4 +-
test.ll | 7 ++
6 files changed, 64 insertions(+), 38 deletions(-)
create mode 100644 test.ll
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index fd9e686485552..1fe37ad4e2d4d 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -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;
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 450213fcec676..e42bb8e16e80b 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -261,7 +261,7 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
BufDecl->getAttr<HLSLResourceBindingAttr>();
// FIXME: handle implicit binding if no binding attribute is found
// (llvm/llvm-project#110722)
- if (RBA)
+ if (RBA && !RBA->isImplicit())
initializeBufferFromBinding(CGM, BufGV, RBA->getSlotNumber(),
RBA->getSpaceNumber());
}
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 27959f61f1dc3..73b8c19840026 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1529,72 +1529,82 @@ void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) {
diag::err_incomplete_type))
return;
}
- StringRef Space = "space0";
+
StringRef Slot = "";
+ StringRef Space = "";
+ SourceLocation SlotLoc, SpaceLoc;
if (!AL.isArgIdent(0)) {
Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIdentifier;
return;
}
-
IdentifierLoc *Loc = AL.getArgAsIdent(0);
- StringRef Str = Loc->Ident->getName();
- SourceLocation ArgLoc = Loc->Loc;
- SourceLocation SpaceArgLoc;
- bool SpecifiedSpace = false;
if (AL.getNumArgs() == 2) {
- SpecifiedSpace = true;
- Slot = Str;
+ Slot = Loc->Ident->getName();
+ SlotLoc = Loc->Loc;
+
if (!AL.isArgIdent(1)) {
Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIdentifier;
return;
}
- IdentifierLoc *Loc = AL.getArgAsIdent(1);
+ Loc = AL.getArgAsIdent(1);
Space = Loc->Ident->getName();
- SpaceArgLoc = Loc->Loc;
+ SpaceLoc = Loc->Loc;
} else {
- Slot = Str;
+ StringRef Str = Loc->Ident->getName();
+ if (Str.starts_with("space")) {
+ Space = Str;
+ SpaceLoc = Loc->Loc;
+ } else {
+ Slot = Str;
+ SlotLoc = Loc->Loc;
+ Space = "space0";
+ }
}
- RegisterType RegType;
- unsigned SlotNum = 0;
+ RegisterType RegType = RegisterType::SRV;
+ int SlotNum = -1;
unsigned SpaceNum = 0;
- // Validate.
+ // Validate slot
if (!Slot.empty()) {
if (!convertToRegisterType(Slot, &RegType)) {
- Diag(ArgLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1);
+ Diag(SlotLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1);
return;
}
if (RegType == RegisterType::I) {
- Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_i);
+ Diag(SlotLoc, diag::warn_hlsl_deprecated_register_type_i);
return;
}
-
StringRef SlotNumStr = Slot.substr(1);
if (SlotNumStr.getAsInteger(10, SlotNum)) {
- Diag(ArgLoc, diag::err_hlsl_unsupported_register_number);
+ Diag(SlotLoc, diag::err_hlsl_unsupported_register_number);
return;
}
}
- if (!Space.starts_with("space")) {
- Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
- return;
- }
- StringRef SpaceNumStr = Space.substr(5);
- if (SpaceNumStr.getAsInteger(10, SpaceNum)) {
- Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
- return;
+ // Validate space
+ if (!Space.empty()) {
+ if (!Space.starts_with("space")) {
+ Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
+ return;
+ }
+ StringRef SpaceNumStr = Space.substr(5);
+ if (SpaceNumStr.getAsInteger(10, SpaceNum)) {
+ Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
+ return;
+ }
}
- if (!DiagnoseHLSLRegisterAttribute(SemaRef, ArgLoc, TheDecl, RegType,
- SpecifiedSpace))
- return;
+ // If we have slot, diagnose it is the right register type for the decl
+ if (SlotNum >= 0)
+ if (!DiagnoseHLSLRegisterAttribute(SemaRef, SlotLoc, TheDecl, RegType,
+ !SpaceLoc.isInvalid()))
+ return;
HLSLResourceBindingAttr *NewAttr =
HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
@@ -1967,7 +1977,7 @@ void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
for (const Decl *VD : DefaultCBufferDecls) {
const HLSLResourceBindingAttr *RBA =
VD->getAttr<HLSLResourceBindingAttr>();
- if (RBA &&
+ if (RBA && !RBA->isImplicit() &&
RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
DefaultCBuffer->setHasValidPackoffset(true);
break;
@@ -3227,7 +3237,7 @@ static bool initVarDeclWithCtor(Sema &S, VarDecl *VD,
static bool initGlobalResourceDecl(Sema &S, VarDecl *VD) {
HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
- if (!RBA)
+ if (!RBA || RBA->isImplicit())
// FIXME: add support for implicit binding (llvm/llvm-project#110722)
return false;
@@ -3310,7 +3320,7 @@ void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
for (Attr *A : VD->attrs()) {
HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
- if (!RBA)
+ if (!RBA || RBA->isImplicit())
continue;
RegisterType RT = RBA->getRegisterType();
diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl b/clang/test/AST/HLSL/resource_binding_attr.hlsl
index af43eddc45edd..c073cd4dc1476 100644
--- a/clang/test/AST/HLSL/resource_binding_attr.hlsl
+++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl
@@ -30,6 +30,10 @@ RWBuffer<float> UAV : register(u3);
// CHECK: HLSLResourceBindingAttr {{.*}} "u4" "space0"
RWBuffer<float> UAV1 : register(u2), UAV2 : register(u4);
+// CHECK: VarDecl {{.*}} UAV3 'RWBuffer<float>':'hlsl::RWBuffer<float>'
+// CHECK: HLSLResourceBindingAttr {{.*}} "" "space5"
+RWBuffer<float> UAV3 : register(space5);
+
//
// Default constants ($Globals) layout annotations
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
index 74aff79f0e37f..5f0ab66061315 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -22,8 +22,8 @@ cbuffer c : register(bf, s2) {
// expected-error at +1 {{expected identifier}}
cbuffer A : register() {}
-// expected-error at +1 {{register number should be an integer}}
-cbuffer B : register(space1) {}
+// expected-error at +1 {{invalid space specifier 'space' used; expected 'space' followed by an integer, like space1}}
+cbuffer B : register(space) {}
// expected-error at +1 {{wrong argument format for hlsl attribute, use b2 instead}}
cbuffer C : register(b 2) {}
diff --git a/test.ll b/test.ll
new file mode 100644
index 0000000000000..dc674289e3e74
--- /dev/null
+++ b/test.ll
@@ -0,0 +1,7 @@
+ByteAddressBuffer Buffer0: register(t0);
+RWBuffer<float> Buf : register(u0);
+
+[numthreads(4,1,1)]
+void main() {
+ Buf[0] = 10;
+}
>From c5c7ab8ace5d82a3f84c5b00738b1d7fd3b3b311 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 10 Apr 2025 18:13:35 -0700
Subject: [PATCH 2/4] remove condition - Space is never empty
---
clang/lib/Sema/SemaHLSL.cpp | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 73b8c19840026..786bfcb3acf7a 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1588,16 +1588,14 @@ void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) {
}
// Validate space
- if (!Space.empty()) {
- if (!Space.starts_with("space")) {
- Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
- return;
- }
- StringRef SpaceNumStr = Space.substr(5);
- if (SpaceNumStr.getAsInteger(10, SpaceNum)) {
- Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
- return;
- }
+ if (!Space.starts_with("space")) {
+ Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
+ return;
+ }
+ StringRef SpaceNumStr = Space.substr(5);
+ if (SpaceNumStr.getAsInteger(10, SpaceNum)) {
+ Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
+ return;
}
// If we have slot, diagnose it is the right register type for the decl
>From 7084cf1978d01f1d4295e3facacf667b3f020fb1 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 10 Apr 2025 18:16:31 -0700
Subject: [PATCH 3/4] remove unintentionally added file
---
test.ll | 7 -------
1 file changed, 7 deletions(-)
delete mode 100644 test.ll
diff --git a/test.ll b/test.ll
deleted file mode 100644
index dc674289e3e74..0000000000000
--- a/test.ll
+++ /dev/null
@@ -1,7 +0,0 @@
-ByteAddressBuffer Buffer0: register(t0);
-RWBuffer<float> Buf : register(u0);
-
-[numthreads(4,1,1)]
-void main() {
- Buf[0] = 10;
-}
>From b79e4ddae3485511dd75038a1e2be8210d041969 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Fri, 11 Apr 2025 12:21:09 -0700
Subject: [PATCH 4/4] Handle register(u-1);
---
clang/lib/Parse/ParseHLSL.cpp | 11 ++++++++---
clang/test/SemaHLSL/resource_binding_attr_error.hlsl | 3 +++
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp
index f4c109f9a81a2..6e8fd56fe5262 100644
--- a/clang/lib/Parse/ParseHLSL.cpp
+++ b/clang/lib/Parse/ParseHLSL.cpp
@@ -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)) {
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
index 5f0ab66061315..d126d25bd94f0 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -31,6 +31,9 @@ cbuffer C : register(b 2) {}
// expected-error at +1 {{wrong argument format for hlsl attribute, use b2 instead}}
cbuffer D : register(b 2, space3) {}
+// expected-error at +1 {{expected <numeric_constant>}}
+cbuffer E : register(u-1) {};
+
// expected-error at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
static MyTemplatedSRV<float> U : register(u5);
More information about the llvm-branch-commits
mailing list