Skip to content

Commit 71ae661

Browse files
author
Finn Plummer
committed
[HLSL][RootSignature] Add infastructure to parse parameters
- defines `ParamType` as a way to represent a reference to some parameter in a root signature - defines `ParseParam` and `ParseParams` as an infastructure to define how the parameters of a given struct should be parsed in an orderless manner
1 parent e4b9486 commit 71ae661

File tree

4 files changed

+92
-1
lines changed

4 files changed

+92
-1
lines changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1830,8 +1830,10 @@ def err_hlsl_virtual_function
18301830
def err_hlsl_virtual_inheritance
18311831
: Error<"virtual inheritance is unsupported in HLSL">;
18321832

1833-
// HLSL Root Siganture diagnostic messages
1833+
// HLSL Root Signature Parser Diagnostics
18341834
def err_hlsl_unexpected_end_of_params
18351835
: Error<"expected %0 to denote end of parameters, or, another valid parameter of %1">;
1836+
def err_hlsl_rootsig_repeat_param : Error<"specified the same parameter '%0' multiple times">;
1837+
def err_hlsl_rootsig_missing_param : Error<"did not specify mandatory parameter '%0'">;
18361838

18371839
} // end of Parser diagnostics

clang/include/clang/Parse/ParseHLSLRootSignature.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,38 @@ class RootSignatureParser {
6969
bool parseDescriptorTable();
7070
bool parseDescriptorTableClause();
7171

72+
/// Each unique ParamType will have a custom parse method defined that we can
73+
/// use to invoke the parameters.
74+
///
75+
/// This function will switch on the ParamType using std::visit and dispatch
76+
/// onto the corresponding parse method
77+
bool parseParam(llvm::hlsl::rootsig::ParamType Ref);
78+
79+
/// Parameter arguments (eg. `bReg`, `space`, ...) can be specified in any
80+
/// order, exactly once, and only a subset are mandatory. This function acts
81+
/// as the infastructure to do so in a declarative way.
82+
///
83+
/// For the example:
84+
/// SmallDenseMap<TokenKind, ParamType> Params = {
85+
/// TokenKind::bReg, &Clause.Register,
86+
/// TokenKind::kw_space, &Clause.Space
87+
/// };
88+
/// SmallDenseSet<TokenKind> Mandatory = {
89+
/// TokenKind::kw_numDescriptors
90+
/// };
91+
///
92+
/// We can read it is as:
93+
///
94+
/// when 'b0' is encountered, invoke the parse method for the type
95+
/// of &Clause.Register (Register *) and update the parameter
96+
/// when 'space' is encountered, invoke a parse method for the type
97+
/// of &Clause.Space (uint32_t *) and update the parameter
98+
///
99+
/// and 'bReg' must be specified
100+
bool parseParams(
101+
llvm::SmallDenseMap<TokenKind, llvm::hlsl::rootsig::ParamType> &Params,
102+
llvm::SmallDenseSet<TokenKind> &Mandatory);
103+
72104
/// Invoke the Lexer to consume a token and update CurToken with the result
73105
void consumeNextToken() { CurToken = Lexer.ConsumeToken(); }
74106

clang/lib/Parse/ParseHLSLRootSignature.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,57 @@ bool RootSignatureParser::parseDescriptorTableClause() {
118118
return false;
119119
}
120120

121+
// Helper struct so that we can use the overloaded notation of std::visit
122+
template <class... Ts> struct ParseMethods : Ts... { using Ts::operator()...; };
123+
template <class... Ts> ParseMethods(Ts...) -> ParseMethods<Ts...>;
124+
125+
bool RootSignatureParser::parseParam(ParamType Ref) {
126+
bool Error = true;
127+
std::visit(ParseMethods{}, Ref);
128+
129+
return Error;
130+
}
131+
132+
bool RootSignatureParser::parseParams(
133+
llvm::SmallDenseMap<TokenKind, ParamType> &Params,
134+
llvm::SmallDenseSet<TokenKind> &Mandatory) {
135+
136+
// Initialize a vector of possible keywords
137+
SmallVector<TokenKind> Keywords;
138+
for (auto Pair : Params)
139+
Keywords.push_back(Pair.first);
140+
141+
// Keep track of which keywords have been seen to report duplicates
142+
llvm::SmallDenseSet<TokenKind> Seen;
143+
144+
while (tryConsumeExpectedToken(Keywords)) {
145+
if (Seen.contains(CurToken.Kind)) {
146+
getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_repeat_param)
147+
<< CurToken.Kind;
148+
return true;
149+
}
150+
Seen.insert(CurToken.Kind);
151+
152+
if (parseParam(Params[CurToken.Kind]))
153+
return true;
154+
155+
if (!tryConsumeExpectedToken(TokenKind::pu_comma))
156+
break;
157+
}
158+
159+
bool AllMandatoryDefined = true;
160+
for (auto Kind : Mandatory) {
161+
bool SeenParam = Seen.contains(Kind);
162+
if (!SeenParam) {
163+
getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_missing_param)
164+
<< Kind;
165+
}
166+
AllMandatoryDefined &= SeenParam;
167+
}
168+
169+
return !AllMandatoryDefined;
170+
}
171+
121172
bool RootSignatureParser::peekExpectedToken(TokenKind Expected) {
122173
return peekExpectedToken(ArrayRef{Expected});
123174
}

llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ struct DescriptorTableClause {
3737
// Models RootElement : DescriptorTable | DescriptorTableClause
3838
using RootElement = std::variant<DescriptorTable, DescriptorTableClause>;
3939

40+
// ParamType is used as an 'any' type that will reference to a parameter in
41+
// RootElement. Each variant of ParamType is expected to have a Parse method
42+
// defined that will be dispatched on when we are attempting to parse a
43+
// parameter
44+
using ParamType = std::variant<std::monostate>;
45+
4046
} // namespace rootsig
4147
} // namespace hlsl
4248
} // namespace llvm

0 commit comments

Comments
 (0)