Skip to content

Commit

Permalink
[HLSL] Support register binding attribute on global variable
Browse files Browse the repository at this point in the history
Allow register binding attribute on variables.

Report warning when register binding attribute applies to local variable or static variable.
It will be ignored in this case.

Type check for register binding is tracked with #57886.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D134617
  • Loading branch information
python3kgae committed Oct 5, 2022
1 parent 549773f commit 15aa643
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 7 deletions.
8 changes: 7 additions & 1 deletion clang/include/clang/Basic/Attr.td
Expand Up @@ -133,6 +133,12 @@ def SharedVar : SubsetSubject<Var,
def GlobalVar : SubsetSubject<Var,
[{S->hasGlobalStorage()}], "global variables">;

def ExternalGlobalVar : SubsetSubject<Var,
[{S->hasGlobalStorage() &&
S->getStorageClass()!=StorageClass::SC_Static &&
!S->isLocalExternDecl()}],
"external global variables">;

def InlineFunction : SubsetSubject<Function,
[{S->isInlineSpecified()}], "inline functions">;

Expand Down Expand Up @@ -3992,7 +3998,7 @@ def HLSLSV_GroupIndex: HLSLAnnotationAttr {

def HLSLResourceBinding: InheritableAttr {
let Spellings = [HLSLSemantic<"register">];
let Subjects = SubjectList<[HLSLBufferObj, GlobalVar]>;
let Subjects = SubjectList<[HLSLBufferObj, ExternalGlobalVar]>;
let LangOpts = [HLSL];
let Args = [StringArgument<"Slot">, StringArgument<"Space", 1>];
let Documentation = [HLSLResourceBindingDocs];
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Parse/Parser.h
Expand Up @@ -2881,8 +2881,19 @@ class Parser : public CodeCompletionHandler {
Sema::AttributeCompletion Completion = Sema::AttributeCompletion::None,
const IdentifierInfo *EnclosingScope = nullptr);

void MaybeParseHLSLSemantics(Declarator &D,
SourceLocation *EndLoc = nullptr) {
assert(getLangOpts().HLSL && "MaybeParseHLSLSemantics is for HLSL only");
if (Tok.is(tok::colon)) {
ParsedAttributes Attrs(AttrFactory);
ParseHLSLSemantics(Attrs, EndLoc);
D.takeAttributes(Attrs);
}
}

void MaybeParseHLSLSemantics(ParsedAttributes &Attrs,
SourceLocation *EndLoc = nullptr) {
assert(getLangOpts().HLSL && "MaybeParseHLSLSemantics is for HLSL only");
if (getLangOpts().HLSL && Tok.is(tok::colon))
ParseHLSLSemantics(Attrs, EndLoc);
}
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/Parse/ParseDecl.cpp
Expand Up @@ -2054,6 +2054,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
return nullptr;
}

if (getLangOpts().HLSL)
MaybeParseHLSLSemantics(D);

if (Tok.is(tok::kw_requires))
ParseTrailingRequiresClause(D);

Expand Down Expand Up @@ -2223,6 +2226,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
DiagnoseAndSkipExtendedMicrosoftTypeAttributes();

ParseDeclarator(D);

if (getLangOpts().HLSL)
MaybeParseHLSLSemantics(D);

if (!D.isInvalidType()) {
// C++2a [dcl.decl]p1
// init-declarator:
Expand Down Expand Up @@ -7165,7 +7172,8 @@ void Parser::ParseParameterDeclarationClause(

// Parse GNU attributes, if present.
MaybeParseGNUAttributes(ParmDeclarator);
MaybeParseHLSLSemantics(DS.getAttributes());
if (getLangOpts().HLSL)
MaybeParseHLSLSemantics(DS.getAttributes());

if (Tok.is(tok::kw_requires)) {
// User tried to define a requires clause in a parameter declaration,
Expand Down
13 changes: 13 additions & 0 deletions clang/test/AST/HLSL/resource_binding_attr.hlsl
Expand Up @@ -22,3 +22,16 @@ float foo() {
// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} <col:14> 'float' lvalue Var 0x[[B]] 'b' 'float'
return a + b;
}

// CHECK: VarDecl 0x{{[0-9a-f]+}} <{{.*}}> col:17 UAV 'RWBuffer<float>':'hlsl::RWBuffer<>' callinit
// CHECK-NEXT:-CXXConstructExpr 0x{{[0-9a-f]+}} <col:17> 'RWBuffer<float>':'hlsl::RWBuffer<>' 'void ()'
// CHECK-NEXT:-HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:23> "u3" "space0"
RWBuffer<float> UAV : register(u3);

// CHECK: -VarDecl 0x{{[0-9a-f]+}} <{{.*}}> col:17 UAV1 'RWBuffer<float>':'hlsl::RWBuffer<>' callinit
// CHECK-NEXT:-CXXConstructExpr 0x{{[0-9a-f]+}} <col:17> 'RWBuffer<float>':'hlsl::RWBuffer<>' 'void ()'
// CHECK-NEXT:-HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:24> "u2" "space0"
// CHECK-NEXT:-VarDecl 0x{{[0-9a-f]+}} <col:1, col:38> col:38 UAV2 'RWBuffer<float>':'hlsl::RWBuffer<>' callinit
// CHECK-NEXT:-CXXConstructExpr 0x{{[0-9a-f]+}} <col:38> 'RWBuffer<float>':'hlsl::RWBuffer<>' 'void ()'
// CHECK-NEXT:-HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:45> "u4" "space0"
RWBuffer<float> UAV1 : register(u2), UAV2 : register(u4);
32 changes: 27 additions & 5 deletions clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -1,10 +1,6 @@
// 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}}
// expected-error@+1 {{invalid resource class specifier 'c' used; expected 'b', 's', 't', or 'u'}}
float a : register(c0, space1);

// expected-error@+1 {{invalid resource class specifier 'i' used; expected 'b', 's', 't', or 'u'}}
Expand Down Expand Up @@ -36,3 +32,29 @@ cbuffer C : 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 D : register(b 2, space 3) {}

// expected-warning@+1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
static RWBuffer<float> U : register(u5);

void foo() {
// expected-warning@+1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
RWBuffer<float> U : register(u3);
}
void foo2() {
// expected-warning@+1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
extern RWBuffer<float> U2 : register(u5);
}
// FIXME: expect-error once fix https://github.com/llvm/llvm-project/issues/57886.
float b : register(u0, space1);

// expected-warning@+1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
void bar(RWBuffer<float> U : register(u3)) {

}

struct S {
// FIXME: generate better error when support semantic on struct field.
// See https://github.com/llvm/llvm-project/issues/57889.
// expected-error@+1 {{expected expression}}
RWBuffer<float> U : register(u3);
};

0 comments on commit 15aa643

Please sign in to comment.