python3kgae updated this revision to Diff 451262.
python3kgae added a comment.

Move resource binding attribute validation to Sema.


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/Parse/Parser.h
  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,25 @@
+// 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 {{register type is unsupported - available types are 'b', 's', 't', 'u'}}
+cbuffer a : register(i0) {
+
+}
+// expected-error@+1 {{expected space definition with syntax 'spaceX', where X is an integral value}}
+cbuffer a : register(b0, s2) {
+
+}
+// expected-error@+1 {{register number should be an integral numeric string}}
+cbuffer a : register(bf, s2) {
+
+}
+// expected-error@+1 {{space number should be an integral numeric string}}
+cbuffer a : register(b2, spaces) {
+
+}
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> CBuffer 3 2
+// 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> SRV 2 1
+// 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,98 @@
   return HLSLShaderAttr::Create(Context, ShaderType, AL);
 }
 
+static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
+                                          const ParsedAttr &AL) {
+  if (AL.getNumArgs() == 0) {
+    S.Diag(AL.getLoc(), diag::err_hlsl_empty_register_attr);
+    return;
+  }
+  StringRef Space = "space0";
+  StringRef Slot = "";
+
+  StringRef Str;
+  SourceLocation ArgLoc;
+  if (!AL.isArgIdent(0)) {
+    S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type);
+    return;
+  }
+
+  IdentifierLoc *Loc = AL.getArgAsIdent(0);
+  Str = Loc->Ident->getName();
+  ArgLoc = Loc->Loc;
+
+  SourceLocation SpaceArgLoc;
+  if (AL.getNumArgs() == 2) {
+    Slot = Str;
+    if (!AL.isArgIdent(1)) {
+      S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space);
+      return;
+    }
+
+    IdentifierLoc *Loc = AL.getArgAsIdent(1);
+    Space = Loc->Ident->getName();
+    SpaceArgLoc = Loc->Loc;
+  } else {
+    if (Str.startswith_insensitive("space")) {
+      Space = Str;
+      SpaceArgLoc = ArgLoc;
+    } 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);
+      return;
+    }
+    "register number should be an integral numeric string";
+    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_insensitive("space")) {
+    S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space);
+    return;
+  }
+  StringRef SpaceNum = Space.substr(5);
+  unsigned Num = 0;
+  if (SpaceNum.getAsInteger(10, Num)) {
+    S.Diag(SpaceArgLoc, diag::err_hlsl_unsupported_space_number);
+    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 +9005,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);
+  MaybeParseHLSLResourceBinding(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,9 +58,48 @@
   BufferScope.Exit();
   Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
 
+  Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs);
   return D;
 }
 
+void Parser::ParseHLSLResourceBinding(ParsedAttributes &Attrs,
+                                      SourceLocation *EndLoc) {
+  assert(Tok.is(tok::colon) && "Not a HLSL resource binding");
+  ConsumeToken();
+  SourceLocation NameLoc = ConsumeToken();
+
+  if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+                       "register")) {
+    SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+    return;
+  }
+  ArgsVector ArgExprs;
+  if (!Tok.is(tok::identifier)) {
+    Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+    SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+    return;
+  }
+  ArgExprs.push_back(ParseIdentifierLoc());
+
+  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;
+    }
+    ArgExprs.push_back(ParseIdentifierLoc());
+  }
+  if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
+    SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+    return;
+  }
+
+  Attrs.addNew(PP.getIdentifierInfo("register"), NameLoc, nullptr,
+               SourceLocation(), ArgExprs.data(), ArgExprs.size(),
+               ParsedAttr::AS_ContextSensitiveKeyword);
+}
+
 void Parser::ParseHLSLSemantics(ParsedAttributes &Attrs,
                                 SourceLocation *EndLoc) {
   assert(Tok.is(tok::colon) && "Not a HLSL Semantic");
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/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -2810,6 +2810,15 @@
       Sema::AttributeCompletion Completion = Sema::AttributeCompletion::None,
       const IdentifierInfo *EnclosingScope = nullptr);
 
+  void MaybeParseHLSLResourceBinding(ParsedAttributes &Attrs,
+                                     SourceLocation *EndLoc) {
+    if (getLangOpts().HLSL && Tok.is(tok::colon))
+      ParseHLSLResourceBinding(Attrs, EndLoc);
+  }
+
+  void ParseHLSLResourceBinding(ParsedAttributes &Attrs,
+                                SourceLocation *EndLoc);
+
   void MaybeParseHLSLSemantics(ParsedAttributes &Attrs,
                                SourceLocation *EndLoc = nullptr) {
     if (getLangOpts().HLSL && Tok.is(tok::colon))
@@ -2818,6 +2827,7 @@
 
   void ParseHLSLSemantics(ParsedAttributes &Attrs,
                           SourceLocation *EndLoc = nullptr);
+
   Decl *ParseHLSLBuffer(SourceLocation &DeclEnd,
                         SourceLocation InlineLoc = SourceLocation());
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11647,6 +11647,11 @@
 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_empty_register_attr : Error<"register attribute cannot be empty">;
+def err_hlsl_unsupported_register_type : Error<"register type is unrecognized; expected resource class specifier 'b', 's', 't', 'u'">;
+def err_hlsl_unsupported_register_number : Error<"register number should be an integer">;
+def err_hlsl_expected_space : Error<"expected space argument specified as 'spaceX', where X is an integer">;
+def err_hlsl_unsupported_space_number : Error<"space number should be an integer">;
 
 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 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,26 @@
   }];
 }
 
+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.
+
+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)}],
+                    "global functions">;
 
 def ClassTmpl : SubsetSubject<CXXRecord, [{S->getDescribedClassTemplate()}],
                               "class templates">;
@@ -4012,6 +4015,14 @@
   let Documentation = [HLSLSV_GroupIndexDocs];
 }
 
+def HLSLResourceBinding: InheritableAttr {
+  let Spellings = [Keyword<"register">];
+  let Subjects = SubjectList<[HLSLBufferObj, GlobalVar]>;
+  let LangOpts = [HLSL];
+  let Args = [StringArgument<"Slot", 1>, StringArgument<"Space", 1>];
+  let Documentation = [HLSLResourceBindingDocs];
+}
+
 def HLSLShader : InheritableAttr {
   let Spellings = [Microsoft<"shader">];
   let Subjects = SubjectList<[HLSLEntry]>;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to