Skip to content

Commit 9ff87eb

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 74ec038 commit 9ff87eb

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
@@ -120,6 +120,57 @@ bool RootSignatureParser::parseDescriptorTableClause() {
120120
return false;
121121
}
122122

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

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)