forked from OSchip/llvm-project
[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
This commit is contained in:
parent
4f1065156b
commit
1fdf952dee
|
@ -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]>;
|
||||
|
|
|
@ -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
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -48,6 +48,9 @@ public:
|
|||
// 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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2786,6 +2786,15 @@ private:
|
|||
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)) {
|
||||
|
|
|
@ -12,6 +12,7 @@ add_clang_library(clangParse
|
|||
ParseDeclCXX.cpp
|
||||
ParseExpr.cpp
|
||||
ParseExprCXX.cpp
|
||||
ParseHLSL.cpp
|
||||
ParseInit.cpp
|
||||
ParseObjc.cpp
|
||||
ParseOpenMP.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,
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
config.suffixes = ['.hlsl']
|
|
@ -0,0 +1,7 @@
|
|||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s -verify
|
||||
|
||||
// expected-error@+1 {{expected HLSL Semantic identifier}}
|
||||
void Entry(int GI : ) { }
|
||||
|
||||
// expected-error@+1 {{unknown HLSL semantic 'SV_IWantAPony'}}
|
||||
void Pony(int GI : SV_IWantAPony) { }
|
|
@ -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@+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
|
||||
}
|
|
@ -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 @@ public:
|
|||
.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
|
||||
|
|
Loading…
Reference in New Issue