python3kgae updated this revision to Diff 452232.
python3kgae marked an inline comment as done.
python3kgae added a comment.
Limit to lower case.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D130033/new/
https://reviews.llvm.org/D130033
Files:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/Parse/ParseHLSL.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/AST/HLSL/resource_binding_attr.hlsl
clang/test/SemaHLSL/resource_binding_attr_error.hlsl
Index: clang/test/SemaHLSL/resource_binding_attr_error.hlsl
===================================================================
--- /dev/null
+++ clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
+
+// expected-error@+5 {{expected ';' after top level declarator}}
+// expected-error@+4 {{expected ')'}}
+// expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{a type specifier is required for all declarations}}
+// expected-error@+1 {{illegal storage class on file-scoped variable}}
+float a : register(c0, space1);
+
+// expected-error@+1 {{invalid resource class specifier 'i' used; expected 'b', 's', 't', or 'u'}}
+cbuffer a : register(i0) {
+
+}
+// expected-error@+1 {{invalid space specifier 's2' used; expected 'space' followed by an integer, like space1}}
+cbuffer a : register(b0, s2) {
+
+}
+// expected-error@+1 {{register number should be an integer}}
+cbuffer a : register(bf, s2) {
+
+}
+// expected-error@+1 {{invalid space specifier 'spaces' used; expected 'space' followed by an integer, like space1}}
+cbuffer a : register(b2, spaces) {
+
+}
+
+// expected-error@+1 {{expected identifier}}
+cbuffer A : register() {}
+
+// expected-error@+1 {{register number should be an integer}}
+cbuffer B : register(space1) {}
+
+// expected-error@+1 {{wrong argument format for hlsl attribute, use b2 instead}}
+cbuffer B : register(b 2) {}
+
+// expected-error@+2 {{wrong argument format for hlsl attribute, use b2 instead}}
+// expected-error@+1 {{wrong argument format for hlsl attribute, use space3 instead}}
+cbuffer B : register(b 2, space 3) {}
Index: clang/test/AST/HLSL/resource_binding_attr.hlsl
===================================================================
--- /dev/null
+++ clang/test/AST/HLSL/resource_binding_attr.hlsl
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -ast-dump -o - %s | FileCheck %s
+
+// CHECK:HLSLBufferDecl 0x[[CB:[0-9a-f]+]] {{.*}} line:6:9 cbuffer CB
+// CHECK-NEXT:HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:14> "b3" "space2"
+// CHECK-NEXT:VarDecl 0x[[A:[0-9a-f]+]] {{.*}} col:9 used a 'float'
+cbuffer CB : register(b3, space2) {
+ float a;
+}
+
+// CHECK:HLSLBufferDecl 0x[[TB:[0-9a-f]+]] {{.*}} line:13:9 tbuffer TB
+// CHECK-NEXT:HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:14> "t2" "space1"
+// CHECK-NEXT:VarDecl 0x[[B:[0-9a-f]+]] {{.*}} col:9 used b 'float'
+tbuffer TB : register(t2, space1) {
+ float b;
+}
+
+float foo() {
+// CHECK: BinaryOperator 0x{{[0-9a-f]+}} <col:10, col:14> 'float' '+'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-f]+}} <col:10> 'float' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} <col:10> 'float' lvalue Var 0x[[A]] 'a' 'float'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-f]+}} <col:14> 'float' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} <col:14> 'float' lvalue Var 0x[[B]] 'b' 'float'
+ return a + b;
+}
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -6934,6 +6934,90 @@
return HLSLShaderAttr::Create(Context, ShaderType, AL);
}
+static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ StringRef Space = "space0";
+ StringRef Slot = "";
+
+ if (!AL.isArgIdent(0)) {
+ S.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;
+ if (AL.getNumArgs() == 2) {
+ Slot = Str;
+ if (!AL.isArgIdent(1)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ IdentifierLoc *Loc = AL.getArgAsIdent(1);
+ Space = Loc->Ident->getName();
+ SpaceArgLoc = Loc->Loc;
+ } else {
+ Slot = Str;
+ }
+
+ // Validate.
+ if (!Slot.empty()) {
+ switch (Slot[0]) {
+ case 'u':
+ case 'b':
+ case 's':
+ case 't':
+ break;
+ default:
+ S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type)
+ << Slot.substr(0, 1);
+ return;
+ }
+
+ StringRef SlotNum = Slot.substr(1);
+ unsigned Num = 0;
+ if (SlotNum.getAsInteger(10, Num)) {
+ S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_number);
+ return;
+ }
+ }
+
+ if (!Space.startswith("space")) {
+ S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
+ return;
+ }
+ StringRef SpaceNum = Space.substr(5);
+ unsigned Num = 0;
+ if (SpaceNum.getAsInteger(10, Num)) {
+ S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
+ return;
+ }
+
+ // FIXME: check reg type match decl.
+ HLSLResourceBindingAttr *NewAttr =
+ S.mergeHLSLResourceBindingAttr(D, AL, Slot, Space);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
+HLSLResourceBindingAttr *
+Sema::mergeHLSLResourceBindingAttr(Decl *D, const AttributeCommonInfo &AL,
+ StringRef Slot, StringRef Space) {
+ if (HLSLResourceBindingAttr *NT = D->getAttr<HLSLResourceBindingAttr>()) {
+ if (NT->getSlot() != Slot || NT->getSpace() != Space) {
+ Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
+ Diag(AL.getLoc(), diag::note_conflicting_attribute);
+ }
+ return nullptr;
+ }
+ return HLSLResourceBindingAttr::Create(Context, Slot, Space, AL);
+}
+
static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.LangOpts.CPlusPlus) {
S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
@@ -8913,6 +8997,9 @@
case ParsedAttr::AT_HLSLShader:
handleHLSLShaderAttr(S, D, AL);
break;
+ case ParsedAttr::AT_HLSLResourceBinding:
+ handleHLSLResourceBindingAttr(S, D, AL);
+ break;
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -2889,6 +2889,9 @@
S.mergeHLSLNumThreadsAttr(D, *NT, NT->getX(), NT->getY(), NT->getZ());
else if (const auto *SA = dyn_cast<HLSLShaderAttr>(Attr))
NewAttr = S.mergeHLSLShaderAttr(D, *SA, SA->getType());
+ else if (const auto *RB = dyn_cast<HLSLResourceBindingAttr>(Attr))
+ NewAttr =
+ S.mergeHLSLResourceBindingAttr(D, *RB, RB->getSlot(), RB->getSpace());
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
Index: clang/lib/Parse/ParseHLSL.cpp
===================================================================
--- clang/lib/Parse/ParseHLSL.cpp
+++ clang/lib/Parse/ParseHLSL.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Attr.h"
#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
@@ -32,6 +33,9 @@
IdentifierInfo *Identifier = Tok.getIdentifierInfo();
SourceLocation IdentifierLoc = ConsumeToken(); // consume identifier
+ ParsedAttributes Attrs(AttrFactory);
+ MaybeParseHLSLSemantics(Attrs, nullptr);
+
ParseScope BufferScope(this, Scope::DeclScope);
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen()) {
@@ -43,8 +47,6 @@
Identifier, IdentifierLoc,
T.getOpenLocation());
- // FIXME: support attribute on cbuffer/tbuffer.
-
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
ParsedAttributes Attrs(AttrFactory);
// FIXME: support attribute on constants inside cbuffer/tbuffer.
@@ -56,30 +58,102 @@
BufferScope.Exit();
Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
+ Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs);
return D;
}
+static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc,
+ Token Tok, ArgsVector &ArgExprs,
+ Parser &P, ASTContext &Ctx,
+ Preprocessor &PP) {
+ StringRef Num = StringRef(Tok.getLiteralData(), Tok.getLength());
+ SourceLocation EndNumLoc = Tok.getEndLoc();
+
+ P.ConsumeToken(); // consume constant.
+ std::string FixedArg = ArgStr.str() + Num.str();
+ P.Diag(ArgLoc, diag::err_hlsl_separate_attr_arg_and_number)
+ << FixedArg
+ << FixItHint::CreateReplacement(SourceRange(ArgLoc, EndNumLoc), FixedArg);
+ ArgsUnion &Slot = ArgExprs.back();
+ Slot = IdentifierLoc::create(Ctx, ArgLoc, PP.getIdentifierInfo(FixedArg));
+}
+
void Parser::ParseHLSLSemantics(ParsedAttributes &Attrs,
SourceLocation *EndLoc) {
+ // FIXME: HLSLSemantic is shared for Semantic and resource binding which is
+ // confusing. Need a better name to avoid misunderstanding.
assert(Tok.is(tok::colon) && "Not a HLSL Semantic");
ConsumeToken();
- if (!Tok.is(tok::identifier)) {
+ IdentifierInfo *II = nullptr;
+ if (Tok.is(tok::kw_register))
+ II = PP.getIdentifierInfo("register");
+ else if (Tok.is(tok::identifier))
+ II = Tok.getIdentifierInfo();
+
+ if (!II) {
Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);
return;
}
- IdentifierInfo *II = Tok.getIdentifierInfo();
SourceLocation Loc = ConsumeToken();
if (EndLoc)
*EndLoc = Tok.getLocation();
ParsedAttr::Kind AttrKind =
ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLSemantic);
- if (AttrKind == ParsedAttr::UnknownAttribute) {
+ ArgsVector ArgExprs;
+ switch (AttrKind) {
+ case ParsedAttr::AT_HLSLResourceBinding: {
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ StringRef SlotStr = Tok.getIdentifierInfo()->getName();
+ SourceLocation SlotLoc = Tok.getLocation();
+ ArgExprs.push_back(ParseIdentifierLoc());
+
+ // Add numeric_constant for fix-it.
+ if (SlotStr.size() == 1 && Tok.is(tok::numeric_constant))
+ fixSeparateAttrArgAndNumber(SlotStr, SlotLoc, Tok, ArgExprs, *this,
+ Actions.Context, PP);
+
+ if (Tok.is(tok::comma)) {
+ ConsumeToken(); // consume comma
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ StringRef SpaceStr = Tok.getIdentifierInfo()->getName();
+ SourceLocation SpaceLoc = Tok.getLocation();
+ ArgExprs.push_back(ParseIdentifierLoc());
+
+ // Add numeric_constant for fix-it.
+ if (SpaceStr.equals("space") && Tok.is(tok::numeric_constant))
+ fixSeparateAttrArgAndNumber(SpaceStr, SpaceLoc, Tok, ArgExprs, *this,
+ Actions.Context, PP);
+ }
+ if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ } break;
+ case ParsedAttr::UnknownAttribute:
Diag(Loc, diag::err_unknown_hlsl_semantic) << II;
return;
+ case ParsedAttr::AT_HLSLSV_GroupIndex:
+ break;
+ default:
+ llvm_unreachable("invalid HLSL Semantic");
+ break;
}
- Attrs.addNew(II, Loc, nullptr, SourceLocation(), nullptr, 0,
- ParsedAttr::AS_HLSLSemantic);
+
+ Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(),
+ ArgExprs.size(), ParsedAttr::AS_HLSLSemantic);
}
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -3584,6 +3584,9 @@
int X, int Y, int Z);
HLSLShaderAttr *mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL,
HLSLShaderAttr::ShaderType ShaderType);
+ HLSLResourceBindingAttr *
+ mergeHLSLResourceBindingAttr(Decl *D, const AttributeCommonInfo &AL,
+ StringRef Slot, StringRef Space);
void mergeDeclAttributes(NamedDecl *New, Decl *Old,
AvailabilityMergeKind AMK = AMK_Redeclaration);
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11647,7 +11647,9 @@
def err_hlsl_numthreads_invalid : Error<"total number of threads cannot exceed %0">;
def err_hlsl_missing_numthreads : Error<"missing numthreads attribute for %0 shader entry">;
def err_hlsl_attribute_param_mismatch : Error<"%0 attribute parameters do not match the previous declaration">;
-
+def err_hlsl_unsupported_register_type : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
+def err_hlsl_unsupported_register_number : Error<"register number should be an integer">;
+def err_hlsl_expected_space : Error<"invalid space specifier '%0' used; expected 'space' followed by an integer, like space1">;
def err_hlsl_pointers_unsupported : Error<
"%select{pointers|references}0 are unsupported in HLSL">;
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1606,6 +1606,7 @@
def err_expected_semantic_identifier : Error<
"expected HLSL Semantic identifier">;
def err_unknown_hlsl_semantic : Error<"unknown HLSL semantic %0">;
+def err_hlsl_separate_attr_arg_and_number : Error<"wrong argument format for hlsl attribute, use %0 instead">;
def ext_hlsl_access_specifiers : ExtWarn<
"access specifiers are a clang HLSL extension">,
InGroup<HLSLExtension>;
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -6538,6 +6538,28 @@
}];
}
+def HLSLResourceBindingDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The resource binding attribute sets the virtual register and logical register space for a resource.
+Attribute spelling in HLSL is: ``register(slot [, space])``.
+``slot`` takes the format ``[type][number]``,
+where ``type`` is a single character specifying the resource type and ``number`` is the virtual register number.
+
+Register types are:
+t for shader resource views (SRV),
+s for samplers,
+u for unordered access views (UAV),
+b for constant buffer views (CBV).
+
+Register space is specified in the format ``space[number]`` and defaults to ``space0`` if omitted.
+Here're resource binding examples with and without space:
+``RWBuffer<float> Uav : register(u3, space1)``
+``Buffer<float> Buf : register(t1)``
+The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3d12/resource-binding-in-hlsl
+ }];
+}
+
def AnnotateTypeDocs : Documentation {
let Category = DocCatType;
let Heading = "annotate_type";
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -145,6 +145,9 @@
: SubsetSubject<Function,
[{S->isExternallyVisible() && !isa<CXXMethodDecl>(S)}],
"global functions">;
+def HLSLBufferObj : SubsetSubject<HLSLBuffer,
+ [{isa<HLSLBufferDecl>(S)}],
+ "cbuffer/tbuffer">;
def ClassTmpl : SubsetSubject<CXXRecord, [{S->getDescribedClassTemplate()}],
"class templates">;
@@ -4012,6 +4015,14 @@
let Documentation = [HLSLSV_GroupIndexDocs];
}
+def HLSLResourceBinding: InheritableAttr {
+ let Spellings = [HLSLSemantic<"register">];
+ let Subjects = SubjectList<[HLSLBufferObj, GlobalVar]>;
+ let LangOpts = [HLSL];
+ let Args = [StringArgument<"Slot">, StringArgument<"Space", 1>];
+ let Documentation = [HLSLResourceBindingDocs];
+}
+
def HLSLShader : InheritableAttr {
let Spellings = [Microsoft<"shader">];
let Subjects = SubjectList<[HLSLEntry]>;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits