[clang] 1fdf952 - [HLSL] Add Semantic syntax, and SV_GroupIndex
Chris Bieneman via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 14 08:22:10 PDT 2022
Author: Chris Bieneman
Date: 2022-04-14T10:21:58-05:00
New Revision: 1fdf952deeb9a02aa34794af3c1a7d13a30e068e
URL: https://github.com/llvm/llvm-project/commit/1fdf952deeb9a02aa34794af3c1a7d13a30e068e
DIFF: https://github.com/llvm/llvm-project/commit/1fdf952deeb9a02aa34794af3c1a7d13a30e068e.diff
LOG: [HLSL] Add Semantic syntax, and SV_GroupIndex
HLSL has a language feature called Semantics which get attached to
declarations like attributes and are used in a variety of ways.
One example of semantic use is here with the `SV_GroupIndex` semantic
which, when applied to an input for a compute shader is pre-populated
by the driver with a flattened thread index.
Differential Revision: https://reviews.llvm.org/D122699
# Conflicts:
# clang/include/clang/Basic/Attr.td
# clang/include/clang/Basic/AttrDocs.td
Added:
clang/lib/Parse/ParseHLSL.cpp
clang/test/ParserHLSL/lit.local.cfg
clang/test/ParserHLSL/semantic_parsing.hlsl
clang/test/SemaHLSL/Semantics/entry_parameter.hlsl
Modified:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/AttributeCommonInfo.h
clang/include/clang/Basic/Attributes.h
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Parse/Parser.h
clang/lib/Parse/CMakeLists.txt
clang/lib/Parse/ParseDecl.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/utils/TableGen/ClangAttrEmitter.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index dee9ede951745..727e6180b41b2 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -300,6 +300,9 @@ class Clang<string name, bit allowInC = 1> : Spelling<name, "Clang"> {
bit AllowInC = allowInC;
}
+// HLSL Semantic spellings
+class HLSLSemantic<string name> : Spelling<name, "HLSLSemantic">;
+
class Accessor<string name, list<Spelling> spellings> {
string Name = name;
list<Spelling> Spellings = spellings;
@@ -3958,6 +3961,13 @@ def HLSLNumThreads: InheritableAttr {
let Documentation = [NumThreadsDocs];
}
+def HLSLSV_GroupIndex: InheritableAttr {
+ let Spellings = [HLSLSemantic<"SV_GroupIndex">];
+ let Subjects = SubjectList<[ParmVar, GlobalVar]>;
+ let LangOpts = [HLSL];
+ let Documentation = [HLSLSV_GroupIndexDocs];
+}
+
def RandomizeLayout : InheritableAttr {
let Spellings = [GCC<"randomize_layout">];
let Subjects = SubjectList<[Record]>;
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 6a8b2e600f949..cda143eeb1ca1 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -6411,3 +6411,14 @@ instructs the compiler that this structure should not have its field layout
randomized.
}];
}
+
+def HLSLSV_GroupIndexDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The ``SV_GroupIndex`` semantic, when applied to an input parameter, specifies a
+data binding to map the group index to the specified parameter. This attribute
+is only supported in compute shaders.
+
+The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-groupindex
+ }];
+}
diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h
index 4be598e109fd8..478b9df371209 100644
--- a/clang/include/clang/Basic/AttributeCommonInfo.h
+++ b/clang/include/clang/Basic/AttributeCommonInfo.h
@@ -48,6 +48,9 @@ class AttributeCommonInfo {
// without adding related code to TableGen/ClangAttrEmitter.cpp.
/// Context-sensitive version of a keyword attribute.
AS_ContextSensitiveKeyword,
+
+ /// <vardecl> : <semantic>
+ AS_HLSLSemantic,
};
enum Kind {
#define PARSED_ATTR(NAME) AT_##NAME,
diff --git a/clang/include/clang/Basic/Attributes.h b/clang/include/clang/Basic/Attributes.h
index c69633decd572..4afb6a1b9ca25 100644
--- a/clang/include/clang/Basic/Attributes.h
+++ b/clang/include/clang/Basic/Attributes.h
@@ -28,7 +28,9 @@ enum class AttrSyntax {
// Is the identifier known as a C-style attribute?
C,
// Is the identifier known as a pragma attribute?
- Pragma
+ Pragma,
+ // Is the identifier known as a HLSL semantic?
+ HLSLSemantic,
};
/// Return the version number associated with the attribute if we
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 1640a75391831..d8d78dfa0befa 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1594,4 +1594,10 @@ def warn_max_tokens_total : Warning<
def note_max_tokens_total_override : Note<"total token limit set here">;
+// HLSL Parser Diagnostics
+
+def err_expected_semantic_identifier : Error<
+ "expected HLSL Semantic identifier">;
+def err_unknown_hlsl_semantic : Error<"unknown HLSL semantic %0">;
+
} // end of Parser diagnostics
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index d6cb68aaadca7..8f28eb30ad1dc 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2786,6 +2786,15 @@ class Parser : public CodeCompletionHandler {
Sema::AttributeCompletion Completion = Sema::AttributeCompletion::None,
const IdentifierInfo *EnclosingScope = nullptr);
+ void MaybeParseHLSLSemantics(ParsedAttributes &Attrs,
+ SourceLocation *EndLoc = nullptr) {
+ if (getLangOpts().HLSL && Tok.is(tok::colon))
+ ParseHLSLSemantics(Attrs, EndLoc);
+ }
+
+ void ParseHLSLSemantics(ParsedAttributes &Attrs,
+ SourceLocation *EndLoc = nullptr);
+
void MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs) {
if ((getLangOpts().MicrosoftExt || getLangOpts().HLSL) &&
Tok.is(tok::l_square)) {
diff --git a/clang/lib/Parse/CMakeLists.txt b/clang/lib/Parse/CMakeLists.txt
index 43cd8f6e12a24..7e90b37386f9e 100644
--- a/clang/lib/Parse/CMakeLists.txt
+++ b/clang/lib/Parse/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_library(clangParse
ParseDeclCXX.cpp
ParseExpr.cpp
ParseExprCXX.cpp
+ ParseHLSL.cpp
ParseInit.cpp
ParseObjc.cpp
ParseOpenMP.cpp
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index f912d9d99efd9..ca55fa9311867 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -6965,6 +6965,7 @@ void Parser::ParseParameterDeclarationClause(
// Parse GNU attributes, if present.
MaybeParseGNUAttributes(ParmDeclarator);
+ MaybeParseHLSLSemantics(DS.getAttributes());
if (Tok.is(tok::kw_requires)) {
// User tried to define a requires clause in a parameter declaration,
diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp
new file mode 100644
index 0000000000000..ed1f81dc4ee8b
--- /dev/null
+++ b/clang/lib/Parse/ParseHLSL.cpp
@@ -0,0 +1,42 @@
+//===--- ParseHLSL.cpp - HLSL-specific parsing support --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the parsing logic for HLSL language features.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/AttributeCommonInfo.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
+
+using namespace clang;
+
+void Parser::ParseHLSLSemantics(ParsedAttributes &Attrs,
+ SourceLocation *EndLoc) {
+ assert(Tok.is(tok::colon) && "Not a HLSL Semantic");
+ ConsumeToken();
+
+ if (!Tok.is(tok::identifier)) {
+ 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) {
+ Diag(Loc, diag::err_unknown_hlsl_semantic) << II;
+ return;
+ }
+ Attrs.addNew(II, Loc, nullptr, SourceLocation(), nullptr, 0,
+ ParsedAttr::AS_HLSLSemantic);
+}
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 843ddbd7e3229..217c884f2858f 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -6925,6 +6925,21 @@ HLSLNumThreadsAttr *Sema::mergeHLSLNumThreadsAttr(Decl *D,
return ::new (Context) HLSLNumThreadsAttr(Context, AL, X, Y, Z);
}
+static void handleHLSLSVGroupIndexAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ using llvm::Triple;
+ Triple Target = S.Context.getTargetInfo().getTriple();
+ if (Target.getEnvironment() != Triple::Compute) {
+ uint32_t Pipeline =
+ (uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() -
+ (uint32_t)llvm::Triple::Pixel;
+ S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
+ << AL << Pipeline << "Compute";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, 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)
@@ -8797,6 +8812,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_HLSLNumThreads:
handleHLSLNumThreadsAttr(S, D, AL);
break;
+ case ParsedAttr::AT_HLSLSV_GroupIndex:
+ handleHLSLSVGroupIndexAttr(S, D, AL);
+ break;
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
diff --git a/clang/test/ParserHLSL/lit.local.cfg b/clang/test/ParserHLSL/lit.local.cfg
new file mode 100644
index 0000000000000..d637d6d68030d
--- /dev/null
+++ b/clang/test/ParserHLSL/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = ['.hlsl']
diff --git a/clang/test/ParserHLSL/semantic_parsing.hlsl b/clang/test/ParserHLSL/semantic_parsing.hlsl
new file mode 100644
index 0000000000000..34df1805c5a95
--- /dev/null
+++ b/clang/test/ParserHLSL/semantic_parsing.hlsl
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s -verify
+
+// expected-error at +1 {{expected HLSL Semantic identifier}}
+void Entry(int GI : ) { }
+
+// expected-error at +1 {{unknown HLSL semantic 'SV_IWantAPony'}}
+void Pony(int GI : SV_IWantAPony) { }
diff --git a/clang/test/SemaHLSL/Semantics/entry_parameter.hlsl b/clang/test/SemaHLSL/Semantics/entry_parameter.hlsl
new file mode 100644
index 0000000000000..bbbd022cb5cdb
--- /dev/null
+++ b/clang/test/SemaHLSL/Semantics/entry_parameter.hlsl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-mesh -x hlsl -ast-dump -verify -o - %s
+
+[numthreads(8,8, 1)]
+// expected-error at +1 {{attribute 'SV_GroupIndex' is unsupported in Mesh shaders, requires Compute}}
+void CSMain(int GI : SV_GroupIndex) {
+// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain 'void (int)'
+// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:17 GI 'int'
+// CHECK-NEXT: HLSLSV_GroupIndexAttr
+}
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index b77554cbb6d39..2c0d46e6647a4 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -1493,6 +1493,9 @@ writePrettyPrintFunction(const Record &R,
Spelling += Namespace;
Spelling += " ";
}
+ } else if (Variety == "HLSLSemantic") {
+ Prefix = ":";
+ Suffix = "";
} else {
llvm_unreachable("Unknown attribute syntax variety!");
}
@@ -3300,7 +3303,7 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
// Separate all of the attributes out into four group: generic, C++11, GNU,
// and declspecs. Then generate a big switch statement for each of them.
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
- std::vector<Record *> Declspec, Microsoft, GNU, Pragma;
+ std::vector<Record *> Declspec, Microsoft, GNU, Pragma, HLSLSemantic;
std::map<std::string, std::vector<Record *>> CXX, C2x;
// Walk over the list of all attributes, and split them out based on the
@@ -3321,6 +3324,8 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
C2x[SI.nameSpace()].push_back(R);
else if (Variety == "Pragma")
Pragma.push_back(R);
+ else if (Variety == "HLSLSemantic")
+ HLSLSemantic.push_back(R);
}
}
@@ -3338,6 +3343,9 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
OS << "case AttrSyntax::Pragma:\n";
OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma");
+ OS << "case AttrSyntax::HLSLSemantic:\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
+ GenerateHasAttrSpellingStringSwitch(HLSLSemantic, OS, "HLSLSemantic");
auto fn = [&OS](const char *Spelling, const char *Variety,
const std::map<std::string, std::vector<Record *>> &List) {
OS << "case AttrSyntax::" << Variety << ": {\n";
@@ -4286,7 +4294,7 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
std::vector<StringMatcher::StringPair> GNU, Declspec, Microsoft, CXX11,
- Keywords, Pragma, C2x;
+ Keywords, Pragma, C2x, HLSLSemantic;
std::set<std::string> Seen;
for (const auto *A : Attrs) {
const Record &Attr = *A;
@@ -4338,6 +4346,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
Matches = &Keywords;
else if (Variety == "Pragma")
Matches = &Pragma;
+ else if (Variety == "HLSLSemantic")
+ Matches = &HLSLSemantic;
assert(Matches && "Unsupported spelling variety found");
@@ -4373,6 +4383,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
StringMatcher("Name", Keywords, OS).Emit();
OS << " } else if (AttributeCommonInfo::AS_Pragma == Syntax) {\n";
StringMatcher("Name", Pragma, OS).Emit();
+ OS << " } else if (AttributeCommonInfo::AS_HLSLSemantic == Syntax) {\n";
+ StringMatcher("Name", HLSLSemantic, OS).Emit();
OS << " }\n";
OS << " return AttributeCommonInfo::UnknownAttribute;\n"
<< "}\n";
@@ -4482,7 +4494,7 @@ void EmitClangAttrDocTable(RecordKeeper &Records, raw_ostream &OS) {
}
}
-enum class SpellingKind {
+enum class SpellingKind : size_t {
GNU,
CXX11,
C2x,
@@ -4490,8 +4502,10 @@ enum class SpellingKind {
Microsoft,
Keyword,
Pragma,
+ HLSLSemantic,
+ NumSpellingKinds
};
-static const size_t NumSpellingKinds = (size_t)SpellingKind::Pragma + 1;
+static const size_t NumSpellingKinds = (size_t)SpellingKind::NumSpellingKinds;
class SpellingList {
std::vector<std::string> Spellings[NumSpellingKinds];
@@ -4509,7 +4523,8 @@ class SpellingList {
.Case("Declspec", SpellingKind::Declspec)
.Case("Microsoft", SpellingKind::Microsoft)
.Case("Keyword", SpellingKind::Keyword)
- .Case("Pragma", SpellingKind::Pragma);
+ .Case("Pragma", SpellingKind::Pragma)
+ .Case("HLSLSemantic", SpellingKind::HLSLSemantic);
std::string Name;
if (!Spelling.nameSpace().empty()) {
switch (Kind) {
@@ -4610,8 +4625,8 @@ static void WriteDocumentation(RecordKeeper &Records,
// List what spelling syntaxes the attribute supports.
OS << ".. csv-table:: Supported Syntaxes\n";
OS << " :header: \"GNU\", \"C++11\", \"C2x\", \"``__declspec``\",";
- OS << " \"Keyword\", \"``#pragma``\", \"``#pragma clang attribute``\"\n\n";
- OS << " \"";
+ OS << " \"Keyword\", \"``#pragma``\", \"``#pragma clang attribute``\",";
+ OS << " \"HLSL Semantic\"\n\n \"";
for (size_t Kind = 0; Kind != NumSpellingKinds; ++Kind) {
SpellingKind K = (SpellingKind)Kind;
// TODO: List Microsoft (IDL-style attribute) spellings once we fully
More information about the cfe-commits
mailing list