Skip to content

Commit e479220

Browse files
committed
[HLSL][RootSignature] Add parsing infastructure for StaticSampler
- define StaticSampler in-memory representation - implement the infastructure for parsing parameters of StaticSampler - define and implement parsing of the `s` reg to demonstrate functionality - add unit tests
1 parent eebdf42 commit e479220

File tree

4 files changed

+107
-5
lines changed

4 files changed

+107
-5
lines changed

clang/include/clang/Parse/ParseHLSLRootSignature.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class RootSignatureParser {
7777
std::optional<llvm::hlsl::rootsig::DescriptorTable> parseDescriptorTable();
7878
std::optional<llvm::hlsl::rootsig::DescriptorTableClause>
7979
parseDescriptorTableClause();
80+
std::optional<llvm::hlsl::rootsig::StaticSampler> parseStaticSampler();
8081

8182
/// Parameter arguments (eg. `bReg`, `space`, ...) can be specified in any
8283
/// order and only exactly once. The following methods define a
@@ -108,6 +109,11 @@ class RootSignatureParser {
108109
std::optional<ParsedClauseParams>
109110
parseDescriptorTableClauseParams(RootSignatureToken::Kind RegType);
110111

112+
struct ParsedStaticSamplerParams {
113+
std::optional<llvm::hlsl::rootsig::Register> Reg;
114+
};
115+
std::optional<ParsedStaticSamplerParams> parseStaticSamplerParams();
116+
111117
// Common parsing methods
112118
std::optional<uint32_t> parseUIntParam();
113119
std::optional<llvm::hlsl::rootsig::Register> parseRegister();

clang/lib/Parse/ParseHLSLRootSignature.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ bool RootSignatureParser::parse() {
5555
return true;
5656
Elements.push_back(*RootParam);
5757
}
58+
59+
if (tryConsumeExpectedToken(TokenKind::kw_StaticSampler)) {
60+
auto Sampler = parseStaticSampler();
61+
if (!Sampler.has_value())
62+
return true;
63+
Elements.push_back(*Sampler);
64+
}
5865
} while (tryConsumeExpectedToken(TokenKind::pu_comma));
5966

6067
return consumeExpectedToken(TokenKind::end_of_stream,
@@ -348,6 +355,37 @@ RootSignatureParser::parseDescriptorTableClause() {
348355
return Clause;
349356
}
350357

358+
std::optional<StaticSampler> RootSignatureParser::parseStaticSampler() {
359+
assert(CurToken.TokKind == TokenKind::kw_StaticSampler &&
360+
"Expects to only be invoked starting at given keyword");
361+
362+
if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,
363+
CurToken.TokKind))
364+
return std::nullopt;
365+
366+
StaticSampler Sampler;
367+
368+
auto Params = parseStaticSamplerParams();
369+
if (!Params.has_value())
370+
return std::nullopt;
371+
372+
// Check mandatory parameters were provided
373+
if (!Params->Reg.has_value()) {
374+
getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_missing_param)
375+
<< TokenKind::sReg;
376+
return std::nullopt;
377+
}
378+
379+
Sampler.Reg = Params->Reg.value();
380+
381+
if (consumeExpectedToken(TokenKind::pu_r_paren,
382+
diag::err_hlsl_unexpected_end_of_params,
383+
/*param of=*/TokenKind::kw_StaticSampler))
384+
return std::nullopt;
385+
386+
return Sampler;
387+
}
388+
351389
// Parameter arguments (eg. `bReg`, `space`, ...) can be specified in any
352390
// order and only exactly once. The following methods will parse through as
353391
// many arguments as possible reporting an error if a duplicate is seen.
@@ -606,6 +644,30 @@ RootSignatureParser::parseDescriptorTableClauseParams(TokenKind RegType) {
606644
return Params;
607645
}
608646

647+
std::optional<RootSignatureParser::ParsedStaticSamplerParams>
648+
RootSignatureParser::parseStaticSamplerParams() {
649+
assert(CurToken.TokKind == TokenKind::pu_l_paren &&
650+
"Expects to only be invoked starting at given token");
651+
652+
ParsedStaticSamplerParams Params;
653+
do {
654+
// `s` POS_INT
655+
if (tryConsumeExpectedToken(TokenKind::sReg)) {
656+
if (Params.Reg.has_value()) {
657+
getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_repeat_param)
658+
<< CurToken.TokKind;
659+
return std::nullopt;
660+
}
661+
auto Reg = parseRegister();
662+
if (!Reg.has_value())
663+
return std::nullopt;
664+
Params.Reg = Reg;
665+
}
666+
} while (tryConsumeExpectedToken(TokenKind::pu_comma));
667+
668+
return Params;
669+
}
670+
609671
std::optional<uint32_t> RootSignatureParser::parseUIntParam() {
610672
assert(CurToken.TokKind == TokenKind::pu_equal &&
611673
"Expects to only be invoked starting at given keyword");

clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,34 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) {
223223
ASSERT_TRUE(Consumer->isSatisfied());
224224
}
225225

226+
TEST_F(ParseHLSLRootSignatureTest, ValidParseStaticSamplerTest) {
227+
const llvm::StringLiteral Source = R"cc(
228+
StaticSampler(s0)
229+
)cc";
230+
231+
TrivialModuleLoader ModLoader;
232+
auto PP = createPP(Source, ModLoader);
233+
auto TokLoc = SourceLocation();
234+
235+
hlsl::RootSignatureLexer Lexer(Source, TokLoc);
236+
SmallVector<RootElement> Elements;
237+
hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
238+
239+
// Test no diagnostics produced
240+
Consumer->setNoDiag();
241+
242+
ASSERT_FALSE(Parser.parse());
243+
244+
ASSERT_EQ(Elements.size(), 1u);
245+
246+
RootElement Elem = Elements[0];
247+
ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
248+
ASSERT_EQ(std::get<StaticSampler>(Elem).Reg.ViewType, RegisterType::SReg);
249+
ASSERT_EQ(std::get<StaticSampler>(Elem).Reg.Number, 0u);
250+
251+
ASSERT_TRUE(Consumer->isSatisfied());
252+
}
253+
226254
TEST_F(ParseHLSLRootSignatureTest, ValidSamplerFlagsTest) {
227255
// This test will checks we can set the valid enum for Sampler descriptor
228256
// range flags

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,23 +158,29 @@ struct DescriptorTableClause {
158158
void dump(raw_ostream &OS) const;
159159
};
160160

161+
struct StaticSampler {
162+
Register Reg;
163+
};
164+
161165
/// Models RootElement : RootFlags | RootConstants | RootParam
162-
/// | DescriptorTable | DescriptorTableClause
166+
/// | DescriptorTable | DescriptorTableClause | StaticSampler
163167
///
164168
/// A Root Signature is modeled in-memory by an array of RootElements. These
165169
/// aim to map closely to their DSL grammar reprsentation defined in the spec.
166170
///
167171
/// Each optional parameter has its default value defined in the struct, and,
168172
/// each mandatory parameter does not have a default initialization.
169173
///
170-
/// For the variants RootFlags, RootConstants and DescriptorTableClause: each
171-
/// data member maps directly to a parameter in the grammar.
174+
/// For the variants RootFlags, RootConstants, RootParam, StaticSampler and
175+
/// DescriptorTableClause: each data member maps directly to a parameter in the
176+
/// grammar.
172177
///
173178
/// The DescriptorTable is modelled by having its Clauses as the previous
174179
/// RootElements in the array, and it holds a data member for the Visibility
175180
/// parameter.
176-
using RootElement = std::variant<RootFlags, RootConstants, RootParam,
177-
DescriptorTable, DescriptorTableClause>;
181+
using RootElement =
182+
std::variant<RootFlags, RootConstants, RootParam, DescriptorTable,
183+
DescriptorTableClause, StaticSampler>;
178184
void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> Elements);
179185

180186
class MetadataBuilder {

0 commit comments

Comments
 (0)