1//=== ParseHLSLRootSignatureTest.cpp - Parse Root Signature tests ---------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/Basic/Diagnostic.h"
10#include "clang/Basic/DiagnosticOptions.h"
11#include "clang/Basic/FileManager.h"
12#include "clang/Basic/LangOptions.h"
13#include "clang/Basic/SourceLocation.h"
14#include "clang/Basic/SourceManager.h"
15#include "clang/Basic/TargetInfo.h"
16#include "clang/Lex/HeaderSearch.h"
17#include "clang/Lex/HeaderSearchOptions.h"
18#include "clang/Lex/Lexer.h"
19#include "clang/Lex/ModuleLoader.h"
20#include "clang/Lex/Preprocessor.h"
21#include "clang/Lex/PreprocessorOptions.h"
22
23#include "clang/Lex/LexHLSLRootSignature.h"
24#include "clang/Parse/ParseHLSLRootSignature.h"
25#include "gtest/gtest.h"
26
27using namespace clang;
28using namespace llvm::hlsl::rootsig;
29
30namespace {
31
32// Diagnostic helper for helper tests
33class ExpectedDiagConsumer : public DiagnosticConsumer {
34 virtual void anchor() {}
35
36 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
37 const Diagnostic &Info) override {
38 if (!FirstDiag || !ExpectedDiagID.has_value()) {
39 Satisfied = false;
40 return;
41 }
42 FirstDiag = false;
43
44 Satisfied = ExpectedDiagID.value() == Info.getID();
45 }
46
47 bool FirstDiag = true;
48 bool Satisfied = false;
49 std::optional<unsigned> ExpectedDiagID;
50
51public:
52 void setNoDiag() {
53 Satisfied = true;
54 ExpectedDiagID = std::nullopt;
55 }
56
57 void setExpected(unsigned DiagID) {
58 Satisfied = false;
59 ExpectedDiagID = DiagID;
60 }
61
62 bool isSatisfied() { return Satisfied; }
63};
64
65// The test fixture.
66class ParseHLSLRootSignatureTest : public ::testing::Test {
67protected:
68 ParseHLSLRootSignatureTest()
69 : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
70 Consumer(new ExpectedDiagConsumer()), Diags(DiagID, DiagOpts, Consumer),
71 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
72 // This is an arbitrarily chosen target triple to create the target info.
73 TargetOpts->Triple = "dxil";
74 Target = TargetInfo::CreateTargetInfo(Diags, Opts&: *TargetOpts);
75 }
76
77 std::unique_ptr<Preprocessor> createPP(StringRef Source,
78 TrivialModuleLoader &ModLoader) {
79 std::unique_ptr<llvm::MemoryBuffer> Buf =
80 llvm::MemoryBuffer::getMemBuffer(InputData: Source);
81 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: std::move(Buf)));
82
83 HeaderSearchOptions SearchOpts;
84 HeaderSearch HeaderInfo(SearchOpts, SourceMgr, Diags, LangOpts,
85 Target.get());
86 auto PP = std::make_unique<Preprocessor>(
87 args&: PPOpts, args&: Diags, args&: LangOpts, args&: SourceMgr, args&: HeaderInfo, args&: ModLoader,
88 /*IILookup =*/args: nullptr, /*OwnsHeaderSearch =*/args: false);
89 PP->Initialize(Target: *Target);
90 PP->EnterMainSourceFile();
91 return PP;
92 }
93
94 FileSystemOptions FileMgrOpts;
95 FileManager FileMgr;
96 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
97 DiagnosticOptions DiagOpts;
98 ExpectedDiagConsumer *Consumer;
99 DiagnosticsEngine Diags;
100 SourceManager SourceMgr;
101 LangOptions LangOpts;
102 PreprocessorOptions PPOpts;
103 std::shared_ptr<TargetOptions> TargetOpts;
104 IntrusiveRefCntPtr<TargetInfo> Target;
105};
106
107// Valid Parser Tests
108
109TEST_F(ParseHLSLRootSignatureTest, ValidParseEmptyTest) {
110 const llvm::StringLiteral Source = R"cc()cc";
111
112 TrivialModuleLoader ModLoader;
113 auto PP = createPP(Source, ModLoader);
114 auto TokLoc = SourceLocation();
115
116 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
117 SmallVector<RootElement> Elements;
118 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
119
120 // Test no diagnostics produced
121 Consumer->setNoDiag();
122
123 ASSERT_FALSE(Parser.parse());
124 ASSERT_EQ((int)Elements.size(), 0);
125
126 ASSERT_TRUE(Consumer->isSatisfied());
127}
128
129TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) {
130 const llvm::StringLiteral Source = R"cc(
131 DescriptorTable(
132 CBV(b0),
133 SRV(space = 3, offset = 32, t42, flags = 0, numDescriptors = 4),
134 visibility = SHADER_VISIBILITY_PIXEL,
135 Sampler(s987, space = +2, offset = DESCRIPTOR_RANGE_OFFSET_APPEND),
136 UAV(u4294967294, numDescriptors = unbounded,
137 flags = Descriptors_Volatile | Data_Volatile
138 | Data_Static_While_Set_At_Execute | Data_Static
139 | Descriptors_Static_Keeping_Buffer_Bounds_Checks
140 )
141 ),
142 DescriptorTable()
143 )cc";
144
145 TrivialModuleLoader ModLoader;
146 auto PP = createPP(Source, ModLoader);
147 auto TokLoc = SourceLocation();
148
149 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
150 SmallVector<RootElement> Elements;
151 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
152
153 // Test no diagnostics produced
154 Consumer->setNoDiag();
155
156 ASSERT_FALSE(Parser.parse());
157
158 // First Descriptor Table with 4 elements
159 RootElement Elem = Elements[0];
160 ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
161 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::CBuffer);
162 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Reg.ViewType,
163 RegisterType::BReg);
164 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Reg.Number, 0u);
165 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, 1u);
166 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, 0u);
167 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
168 DescriptorTableOffsetAppend);
169 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
170 DescriptorRangeFlags::DataStaticWhileSetAtExecute);
171
172 Elem = Elements[1];
173 ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
174 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::SRV);
175 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Reg.ViewType,
176 RegisterType::TReg);
177 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Reg.Number, 42u);
178 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, 4u);
179 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, 3u);
180 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset, 32u);
181 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
182 DescriptorRangeFlags::None);
183
184 Elem = Elements[2];
185 ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
186 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::Sampler);
187 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Reg.ViewType,
188 RegisterType::SReg);
189 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Reg.Number, 987u);
190 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, 1u);
191 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, 2u);
192 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
193 DescriptorTableOffsetAppend);
194 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
195 DescriptorRangeFlags::None);
196
197 Elem = Elements[3];
198 ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
199 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::UAV);
200 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Reg.ViewType,
201 RegisterType::UReg);
202 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Reg.Number, 4294967294u);
203 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors,
204 NumDescriptorsUnbounded);
205 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, 0u);
206 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
207 DescriptorTableOffsetAppend);
208 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
209 DescriptorRangeFlags::ValidFlags);
210
211 Elem = Elements[4];
212 ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
213 ASSERT_EQ(std::get<DescriptorTable>(Elem).NumClauses, (uint32_t)4);
214 ASSERT_EQ(std::get<DescriptorTable>(Elem).Visibility,
215 ShaderVisibility::Pixel);
216
217 // Empty Descriptor Table
218 Elem = Elements[5];
219 ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
220 ASSERT_EQ(std::get<DescriptorTable>(Elem).NumClauses, 0u);
221 ASSERT_EQ(std::get<DescriptorTable>(Elem).Visibility, ShaderVisibility::All);
222
223 ASSERT_TRUE(Consumer->isSatisfied());
224}
225
226TEST_F(ParseHLSLRootSignatureTest, ValidParseStaticSamplerTest) {
227 const llvm::StringLiteral Source = R"cc(
228 StaticSampler(s0),
229 StaticSampler(s0, maxAnisotropy = 3, space = 4,
230 visibility = SHADER_VISIBILITY_DOMAIN,
231 minLOD = 4.2f, mipLODBias = 0.23e+3,
232 addressW = TEXTURE_ADDRESS_CLAMP,
233 addressV = TEXTURE_ADDRESS_BORDER,
234 filter = FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT,
235 maxLOD = 9000, addressU = TEXTURE_ADDRESS_MIRROR,
236 comparisonFunc = COMPARISON_NOT_EQUAL,
237 borderColor = STATIC_BORDER_COLOR_OPAQUE_BLACK_UINT
238 )
239 )cc";
240
241 TrivialModuleLoader ModLoader;
242 auto PP = createPP(Source, ModLoader);
243 auto TokLoc = SourceLocation();
244
245 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
246 SmallVector<RootElement> Elements;
247 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
248
249 // Test no diagnostics produced
250 Consumer->setNoDiag();
251
252 ASSERT_FALSE(Parser.parse());
253
254 ASSERT_EQ(Elements.size(), 2u);
255
256 // Check default values are as expected
257 RootElement Elem = Elements[0];
258 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
259 ASSERT_EQ(std::get<StaticSampler>(Elem).Reg.ViewType, RegisterType::SReg);
260 ASSERT_EQ(std::get<StaticSampler>(Elem).Reg.Number, 0u);
261 ASSERT_EQ(std::get<StaticSampler>(Elem).Filter, SamplerFilter::Anisotropic);
262 ASSERT_EQ(std::get<StaticSampler>(Elem).AddressU, TextureAddressMode::Wrap);
263 ASSERT_EQ(std::get<StaticSampler>(Elem).AddressV, TextureAddressMode::Wrap);
264 ASSERT_EQ(std::get<StaticSampler>(Elem).AddressW, TextureAddressMode::Wrap);
265 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 0.f);
266 ASSERT_EQ(std::get<StaticSampler>(Elem).MaxAnisotropy, 16u);
267 ASSERT_EQ(std::get<StaticSampler>(Elem).CompFunc, ComparisonFunc::LessEqual);
268 ASSERT_EQ(std::get<StaticSampler>(Elem).BorderColor,
269 StaticBorderColor::OpaqueWhite);
270 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MinLOD, 0.f);
271 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MaxLOD, 3.402823466e+38f);
272 ASSERT_EQ(std::get<StaticSampler>(Elem).Space, 0u);
273 ASSERT_EQ(std::get<StaticSampler>(Elem).Visibility, ShaderVisibility::All);
274
275 // Check values can be set as expected
276 Elem = Elements[1];
277 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
278 ASSERT_EQ(std::get<StaticSampler>(Elem).Reg.ViewType, RegisterType::SReg);
279 ASSERT_EQ(std::get<StaticSampler>(Elem).Reg.Number, 0u);
280 ASSERT_EQ(std::get<StaticSampler>(Elem).Filter,
281 SamplerFilter::MaximumMinPointMagLinearMipPoint);
282 ASSERT_EQ(std::get<StaticSampler>(Elem).AddressU, TextureAddressMode::Mirror);
283 ASSERT_EQ(std::get<StaticSampler>(Elem).AddressV, TextureAddressMode::Border);
284 ASSERT_EQ(std::get<StaticSampler>(Elem).AddressW, TextureAddressMode::Clamp);
285 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 230.f);
286 ASSERT_EQ(std::get<StaticSampler>(Elem).MaxAnisotropy, 3u);
287 ASSERT_EQ(std::get<StaticSampler>(Elem).CompFunc, ComparisonFunc::NotEqual);
288 ASSERT_EQ(std::get<StaticSampler>(Elem).BorderColor,
289 StaticBorderColor::OpaqueBlackUint);
290 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MinLOD, 4.2f);
291 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MaxLOD, 9000.f);
292 ASSERT_EQ(std::get<StaticSampler>(Elem).Space, 4u);
293 ASSERT_EQ(std::get<StaticSampler>(Elem).Visibility, ShaderVisibility::Domain);
294
295 ASSERT_TRUE(Consumer->isSatisfied());
296}
297
298TEST_F(ParseHLSLRootSignatureTest, ValidParseFloatsTest) {
299 const llvm::StringLiteral Source = R"cc(
300 StaticSampler(s0, mipLODBias = 0),
301 StaticSampler(s0, mipLODBias = +1),
302 StaticSampler(s0, mipLODBias = -1),
303 StaticSampler(s0, mipLODBias = 42.),
304 StaticSampler(s0, mipLODBias = +4.2),
305 StaticSampler(s0, mipLODBias = -.42),
306 StaticSampler(s0, mipLODBias = .42e+3),
307 StaticSampler(s0, mipLODBias = 42E-12),
308 StaticSampler(s0, mipLODBias = 42.f),
309 StaticSampler(s0, mipLODBias = 4.2F),
310 StaticSampler(s0, mipLODBias = 42.e+10f),
311 StaticSampler(s0, mipLODBias = -2147483648),
312 StaticSampler(s0, mipLODBias = 2147483648),
313 )cc";
314
315 TrivialModuleLoader ModLoader;
316 auto PP = createPP(Source, ModLoader);
317 auto TokLoc = SourceLocation();
318
319 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
320 SmallVector<RootElement> Elements;
321 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
322
323 // Test no diagnostics produced
324 Consumer->setNoDiag();
325
326 ASSERT_FALSE(Parser.parse());
327
328 RootElement Elem = Elements[0];
329 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
330 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 0.f);
331
332 Elem = Elements[1];
333 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
334 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 1.f);
335
336 Elem = Elements[2];
337 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
338 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, -1.f);
339
340 Elem = Elements[3];
341 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
342 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 42.f);
343
344 Elem = Elements[4];
345 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
346 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 4.2f);
347
348 Elem = Elements[5];
349 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
350 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, -.42f);
351
352 Elem = Elements[6];
353 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
354 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 420.f);
355
356 Elem = Elements[7];
357 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
358 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 0.000000000042f);
359
360 Elem = Elements[8];
361 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
362 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 42.f);
363
364 Elem = Elements[9];
365 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
366 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 4.2f);
367
368 Elem = Elements[10];
369 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
370 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 420000000000.f);
371
372 Elem = Elements[11];
373 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
374 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, -2147483648.f);
375
376 Elem = Elements[12];
377 ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
378 ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 2147483648.f);
379
380 ASSERT_TRUE(Consumer->isSatisfied());
381}
382
383TEST_F(ParseHLSLRootSignatureTest, ValidSamplerFlagsTest) {
384 // This test will checks we can set the valid enum for Sampler descriptor
385 // range flags
386 const llvm::StringLiteral Source = R"cc(
387 DescriptorTable(Sampler(s0, flags = DESCRIPTORS_VOLATILE))
388 )cc";
389
390 TrivialModuleLoader ModLoader;
391 auto PP = createPP(Source, ModLoader);
392 auto TokLoc = SourceLocation();
393
394 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
395 SmallVector<RootElement> Elements;
396 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
397
398 // Test no diagnostics produced
399 Consumer->setNoDiag();
400
401 ASSERT_FALSE(Parser.parse());
402
403 RootElement Elem = Elements[0];
404 ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
405 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::Sampler);
406 ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
407 DescriptorRangeFlags::ValidSamplerFlags);
408
409 ASSERT_TRUE(Consumer->isSatisfied());
410}
411
412TEST_F(ParseHLSLRootSignatureTest, ValidParseRootConsantsTest) {
413 const llvm::StringLiteral Source = R"cc(
414 RootConstants(num32BitConstants = 1, b0),
415 RootConstants(b42, space = 3, num32BitConstants = 4294967295,
416 visibility = SHADER_VISIBILITY_HULL
417 )
418 )cc";
419
420 TrivialModuleLoader ModLoader;
421 auto PP = createPP(Source, ModLoader);
422 auto TokLoc = SourceLocation();
423
424 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
425 SmallVector<RootElement> Elements;
426 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
427
428 // Test no diagnostics produced
429 Consumer->setNoDiag();
430
431 ASSERT_FALSE(Parser.parse());
432
433 ASSERT_EQ(Elements.size(), 2u);
434
435 RootElement Elem = Elements[0];
436 ASSERT_TRUE(std::holds_alternative<RootConstants>(Elem));
437 ASSERT_EQ(std::get<RootConstants>(Elem).Num32BitConstants, 1u);
438 ASSERT_EQ(std::get<RootConstants>(Elem).Reg.ViewType, RegisterType::BReg);
439 ASSERT_EQ(std::get<RootConstants>(Elem).Reg.Number, 0u);
440 ASSERT_EQ(std::get<RootConstants>(Elem).Space, 0u);
441 ASSERT_EQ(std::get<RootConstants>(Elem).Visibility, ShaderVisibility::All);
442
443 Elem = Elements[1];
444 ASSERT_TRUE(std::holds_alternative<RootConstants>(Elem));
445 ASSERT_EQ(std::get<RootConstants>(Elem).Num32BitConstants, 4294967295u);
446 ASSERT_EQ(std::get<RootConstants>(Elem).Reg.ViewType, RegisterType::BReg);
447 ASSERT_EQ(std::get<RootConstants>(Elem).Reg.Number, 42u);
448 ASSERT_EQ(std::get<RootConstants>(Elem).Space, 3u);
449 ASSERT_EQ(std::get<RootConstants>(Elem).Visibility, ShaderVisibility::Hull);
450
451 ASSERT_TRUE(Consumer->isSatisfied());
452}
453
454TEST_F(ParseHLSLRootSignatureTest, ValidParseRootFlagsTest) {
455 const llvm::StringLiteral Source = R"cc(
456 RootFlags(),
457 RootFlags(0),
458 RootFlags(
459 deny_domain_shader_root_access |
460 deny_pixel_shader_root_access |
461 local_root_signature |
462 cbv_srv_uav_heap_directly_indexed |
463 deny_amplification_shader_root_access |
464 deny_geometry_shader_root_access |
465 deny_hull_shader_root_access |
466 deny_mesh_shader_root_access |
467 allow_stream_output |
468 sampler_heap_directly_indexed |
469 allow_input_assembler_input_layout |
470 deny_vertex_shader_root_access
471 )
472 )cc";
473
474 TrivialModuleLoader ModLoader;
475 auto PP = createPP(Source, ModLoader);
476 auto TokLoc = SourceLocation();
477
478 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
479 SmallVector<RootElement> Elements;
480 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
481
482 // Test no diagnostics produced
483 Consumer->setNoDiag();
484
485 ASSERT_FALSE(Parser.parse());
486
487 ASSERT_EQ(Elements.size(), 3u);
488
489 RootElement Elem = Elements[0];
490 ASSERT_TRUE(std::holds_alternative<RootFlags>(Elem));
491 ASSERT_EQ(std::get<RootFlags>(Elem), RootFlags::None);
492
493 Elem = Elements[1];
494 ASSERT_TRUE(std::holds_alternative<RootFlags>(Elem));
495 ASSERT_EQ(std::get<RootFlags>(Elem), RootFlags::None);
496
497 Elem = Elements[2];
498 ASSERT_TRUE(std::holds_alternative<RootFlags>(Elem));
499 ASSERT_EQ(std::get<RootFlags>(Elem), RootFlags::ValidFlags);
500
501 ASSERT_TRUE(Consumer->isSatisfied());
502}
503
504TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) {
505 const llvm::StringLiteral Source = R"cc(
506 CBV(b0),
507 SRV(space = 4, t42, visibility = SHADER_VISIBILITY_GEOMETRY,
508 flags = DATA_VOLATILE | DATA_STATIC | DATA_STATIC_WHILE_SET_AT_EXECUTE
509 ),
510 UAV(visibility = SHADER_VISIBILITY_HULL, u34893247),
511 CBV(b0, flags = 0),
512 )cc";
513
514 TrivialModuleLoader ModLoader;
515 auto PP = createPP(Source, ModLoader);
516 auto TokLoc = SourceLocation();
517
518 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
519 SmallVector<RootElement> Elements;
520 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
521
522 // Test no diagnostics produced
523 Consumer->setNoDiag();
524
525 ASSERT_FALSE(Parser.parse());
526
527 ASSERT_EQ(Elements.size(), 4u);
528
529 RootElement Elem = Elements[0];
530 ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem));
531 ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::CBuffer);
532 ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.ViewType, RegisterType::BReg);
533 ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 0u);
534 ASSERT_EQ(std::get<RootDescriptor>(Elem).Space, 0u);
535 ASSERT_EQ(std::get<RootDescriptor>(Elem).Visibility, ShaderVisibility::All);
536 ASSERT_EQ(std::get<RootDescriptor>(Elem).Flags,
537 RootDescriptorFlags::DataStaticWhileSetAtExecute);
538
539 Elem = Elements[1];
540 ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem));
541 ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::SRV);
542 ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.ViewType, RegisterType::TReg);
543 ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 42u);
544 ASSERT_EQ(std::get<RootDescriptor>(Elem).Space, 4u);
545 ASSERT_EQ(std::get<RootDescriptor>(Elem).Visibility,
546 ShaderVisibility::Geometry);
547 ASSERT_EQ(std::get<RootDescriptor>(Elem).Flags,
548 RootDescriptorFlags::ValidFlags);
549
550 Elem = Elements[2];
551 ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem));
552 ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::UAV);
553 ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.ViewType, RegisterType::UReg);
554 ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 34893247u);
555 ASSERT_EQ(std::get<RootDescriptor>(Elem).Space, 0u);
556 ASSERT_EQ(std::get<RootDescriptor>(Elem).Visibility, ShaderVisibility::Hull);
557 ASSERT_EQ(std::get<RootDescriptor>(Elem).Flags,
558 RootDescriptorFlags::DataVolatile);
559 ASSERT_EQ(std::get<RootDescriptor>(Elem).Flags,
560 RootDescriptorFlags::DataVolatile);
561
562 Elem = Elements[3];
563 ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::CBuffer);
564 ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.ViewType, RegisterType::BReg);
565 ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 0u);
566 ASSERT_EQ(std::get<RootDescriptor>(Elem).Space, 0u);
567 ASSERT_EQ(std::get<RootDescriptor>(Elem).Visibility, ShaderVisibility::All);
568 ASSERT_EQ(std::get<RootDescriptor>(Elem).Flags, RootDescriptorFlags::None);
569
570 ASSERT_TRUE(Consumer->isSatisfied());
571}
572
573TEST_F(ParseHLSLRootSignatureTest, ValidTrailingCommaTest) {
574 // This test will checks we can handling trailing commas ','
575 const llvm::StringLiteral Source = R"cc(
576 DescriptorTable(
577 CBV(b0, ),
578 SRV(t42),
579 )
580 )cc";
581
582 TrivialModuleLoader ModLoader;
583 auto PP = createPP(Source, ModLoader);
584 auto TokLoc = SourceLocation();
585
586 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
587 SmallVector<RootElement> Elements;
588 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
589
590 // Test no diagnostics produced
591 Consumer->setNoDiag();
592
593 ASSERT_FALSE(Parser.parse());
594
595 ASSERT_TRUE(Consumer->isSatisfied());
596}
597
598// Invalid Parser Tests
599
600TEST_F(ParseHLSLRootSignatureTest, InvalidParseUnexpectedTokenTest) {
601 const llvm::StringLiteral Source = R"cc(
602 DescriptorTable()
603 space
604 )cc";
605
606 TrivialModuleLoader ModLoader;
607 auto PP = createPP(Source, ModLoader);
608 auto TokLoc = SourceLocation();
609
610 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
611 SmallVector<RootElement> Elements;
612 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
613
614 // Test correct diagnostic produced
615 Consumer->setExpected(diag::err_hlsl_unexpected_end_of_params);
616 ASSERT_TRUE(Parser.parse());
617
618 ASSERT_TRUE(Consumer->isSatisfied());
619}
620
621TEST_F(ParseHLSLRootSignatureTest, InvalidParseInvalidTokenTest) {
622 const llvm::StringLiteral Source = R"cc(
623 notAnIdentifier
624 )cc";
625
626 TrivialModuleLoader ModLoader;
627 auto PP = createPP(Source, ModLoader);
628 auto TokLoc = SourceLocation();
629
630 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
631 SmallVector<RootElement> Elements;
632 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
633
634 // Test correct diagnostic produced - invalid token
635 Consumer->setExpected(diag::err_hlsl_unexpected_end_of_params);
636 ASSERT_TRUE(Parser.parse());
637
638 ASSERT_TRUE(Consumer->isSatisfied());
639}
640
641TEST_F(ParseHLSLRootSignatureTest, InvalidParseUnexpectedEndOfStreamTest) {
642 const llvm::StringLiteral Source = R"cc(
643 DescriptorTable
644 )cc";
645
646 TrivialModuleLoader ModLoader;
647 auto PP = createPP(Source, ModLoader);
648 auto TokLoc = SourceLocation();
649
650 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
651 SmallVector<RootElement> Elements;
652 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
653
654 // Test correct diagnostic produced - end of stream
655 Consumer->setExpected(diag::err_expected_after);
656
657 ASSERT_TRUE(Parser.parse());
658
659 ASSERT_TRUE(Consumer->isSatisfied());
660}
661
662TEST_F(ParseHLSLRootSignatureTest, InvalidMissingDTParameterTest) {
663 // This test will check that the parsing fails due a mandatory
664 // parameter (register) not being specified
665 const llvm::StringLiteral Source = R"cc(
666 DescriptorTable(
667 CBV()
668 )
669 )cc";
670
671 TrivialModuleLoader ModLoader;
672 auto PP = createPP(Source, ModLoader);
673 auto TokLoc = SourceLocation();
674
675 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
676 SmallVector<RootElement> Elements;
677 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
678
679 // Test correct diagnostic produced
680 Consumer->setExpected(diag::err_hlsl_rootsig_missing_param);
681 ASSERT_TRUE(Parser.parse());
682
683 ASSERT_TRUE(Consumer->isSatisfied());
684}
685
686TEST_F(ParseHLSLRootSignatureTest, InvalidMissingRDParameterTest) {
687 // This test will check that the parsing fails due a mandatory
688 // parameter (register) not being specified
689 const llvm::StringLiteral Source = R"cc(
690 SRV()
691 )cc";
692
693 TrivialModuleLoader ModLoader;
694 auto PP = createPP(Source, ModLoader);
695 auto TokLoc = SourceLocation();
696
697 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
698 SmallVector<RootElement> Elements;
699 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
700
701 // Test correct diagnostic produced
702 Consumer->setExpected(diag::err_hlsl_rootsig_missing_param);
703 ASSERT_TRUE(Parser.parse());
704
705 ASSERT_TRUE(Consumer->isSatisfied());
706}
707
708TEST_F(ParseHLSLRootSignatureTest, InvalidMissingRCParameterTest) {
709 // This test will check that the parsing fails due a mandatory
710 // parameter (num32BitConstants) not being specified
711 const llvm::StringLiteral Source = R"cc(
712 RootConstants(b0)
713 )cc";
714
715 TrivialModuleLoader ModLoader;
716 auto PP = createPP(Source, ModLoader);
717 auto TokLoc = SourceLocation();
718
719 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
720 SmallVector<RootElement> Elements;
721 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
722
723 // Test correct diagnostic produced
724 Consumer->setExpected(diag::err_hlsl_rootsig_missing_param);
725 ASSERT_TRUE(Parser.parse());
726
727 ASSERT_TRUE(Consumer->isSatisfied());
728}
729
730TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedMandatoryDTParameterTest) {
731 // This test will check that the parsing fails due the same mandatory
732 // parameter being specified multiple times
733 const llvm::StringLiteral Source = R"cc(
734 DescriptorTable(
735 CBV(b32, b84)
736 )
737 )cc";
738
739 TrivialModuleLoader ModLoader;
740 auto PP = createPP(Source, ModLoader);
741 auto TokLoc = SourceLocation();
742
743 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
744 SmallVector<RootElement> Elements;
745 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
746
747 // Test correct diagnostic produced
748 Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param);
749 ASSERT_TRUE(Parser.parse());
750
751 ASSERT_TRUE(Consumer->isSatisfied());
752}
753
754TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedMandatoryRCParameterTest) {
755 // This test will check that the parsing fails due the same mandatory
756 // parameter being specified multiple times
757 const llvm::StringLiteral Source = R"cc(
758 RootConstants(num32BitConstants = 32, num32BitConstants = 24)
759 )cc";
760
761 TrivialModuleLoader ModLoader;
762 auto PP = createPP(Source, ModLoader);
763 auto TokLoc = SourceLocation();
764
765 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
766 SmallVector<RootElement> Elements;
767 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
768
769 // Test correct diagnostic produced
770 Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param);
771 ASSERT_TRUE(Parser.parse());
772
773 ASSERT_TRUE(Consumer->isSatisfied());
774}
775
776TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedOptionalDTParameterTest) {
777 // This test will check that the parsing fails due the same optional
778 // parameter being specified multiple times
779 const llvm::StringLiteral Source = R"cc(
780 DescriptorTable(
781 CBV(space = 2, space = 0)
782 )
783 )cc";
784
785 TrivialModuleLoader ModLoader;
786 auto PP = createPP(Source, ModLoader);
787 auto TokLoc = SourceLocation();
788
789 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
790 SmallVector<RootElement> Elements;
791 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
792
793 // Test correct diagnostic produced
794 Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param);
795 ASSERT_TRUE(Parser.parse());
796
797 ASSERT_TRUE(Consumer->isSatisfied());
798}
799
800TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedOptionalRCParameterTest) {
801 // This test will check that the parsing fails due the same optional
802 // parameter being specified multiple times
803 const llvm::StringLiteral Source = R"cc(
804 RootConstants(
805 visibility = Shader_Visibility_All,
806 b0, num32BitConstants = 1,
807 visibility = Shader_Visibility_Pixel
808 )
809 )cc";
810
811 TrivialModuleLoader ModLoader;
812 auto PP = createPP(Source, ModLoader);
813 auto TokLoc = SourceLocation();
814
815 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
816 SmallVector<RootElement> Elements;
817 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
818
819 // Test correct diagnostic produced
820 Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param);
821 ASSERT_TRUE(Parser.parse());
822
823 ASSERT_TRUE(Consumer->isSatisfied());
824}
825
826TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedNumberTest) {
827 // This test will check that the lexing fails due to an integer overflow
828 const llvm::StringLiteral Source = R"cc(
829 DescriptorTable(
830 CBV(b4294967296)
831 )
832 )cc";
833
834 TrivialModuleLoader ModLoader;
835 auto PP = createPP(Source, ModLoader);
836 auto TokLoc = SourceLocation();
837
838 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
839 SmallVector<RootElement> Elements;
840 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
841
842 // Test correct diagnostic produced
843 Consumer->setExpected(diag::err_hlsl_number_literal_overflow);
844 ASSERT_TRUE(Parser.parse());
845
846 ASSERT_TRUE(Consumer->isSatisfied());
847}
848
849TEST_F(ParseHLSLRootSignatureTest, InvalidParseOverflowedNegativeNumberTest) {
850 // This test will check that parsing fails due to a unsigned integer having
851 // too large of a magnitude to be interpreted as its negative
852 const llvm::StringLiteral Source = R"cc(
853 StaticSampler(s0, mipLODBias = -4294967295)
854 )cc";
855
856 TrivialModuleLoader ModLoader;
857 auto PP = createPP(Source, ModLoader);
858 auto TokLoc = SourceLocation();
859
860 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
861 SmallVector<RootElement> Elements;
862 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
863
864 // Test correct diagnostic produced
865 Consumer->setExpected(diag::err_hlsl_number_literal_overflow);
866 ASSERT_TRUE(Parser.parse());
867
868 ASSERT_TRUE(Consumer->isSatisfied());
869}
870
871TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedFloatTest) {
872 // This test will check that the lexing fails due to a float overflow
873 const llvm::StringLiteral Source = R"cc(
874 StaticSampler(s0, mipLODBias = 3.402823467e+38F)
875 )cc";
876
877 TrivialModuleLoader ModLoader;
878 auto PP = createPP(Source, ModLoader);
879 auto TokLoc = SourceLocation();
880
881 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
882 SmallVector<RootElement> Elements;
883 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
884
885 // Test correct diagnostic produced
886 Consumer->setExpected(diag::err_hlsl_number_literal_overflow);
887 ASSERT_TRUE(Parser.parse());
888
889 ASSERT_TRUE(Consumer->isSatisfied());
890}
891
892TEST_F(ParseHLSLRootSignatureTest, InvalidLexNegOverflowedFloatTest) {
893 // This test will check that the lexing fails due to negative float overflow
894 const llvm::StringLiteral Source = R"cc(
895 StaticSampler(s0, mipLODBias = -3.402823467e+38F)
896 )cc";
897
898 TrivialModuleLoader ModLoader;
899 auto PP = createPP(Source, ModLoader);
900 auto TokLoc = SourceLocation();
901
902 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
903 SmallVector<RootElement> Elements;
904 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
905
906 // Test correct diagnostic produced
907 Consumer->setExpected(diag::err_hlsl_number_literal_overflow);
908 ASSERT_TRUE(Parser.parse());
909
910 ASSERT_TRUE(Consumer->isSatisfied());
911}
912
913TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedDoubleTest) {
914 // This test will check that the lexing fails due to an overflow of double
915 const llvm::StringLiteral Source = R"cc(
916 StaticSampler(s0, mipLODBias = 1.e+500)
917 )cc";
918
919 TrivialModuleLoader ModLoader;
920 auto PP = createPP(Source, ModLoader);
921 auto TokLoc = SourceLocation();
922
923 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
924 SmallVector<RootElement> Elements;
925 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
926
927 // Test correct diagnostic produced
928 Consumer->setExpected(diag::err_hlsl_number_literal_overflow);
929 ASSERT_TRUE(Parser.parse());
930
931 ASSERT_TRUE(Consumer->isSatisfied());
932}
933
934TEST_F(ParseHLSLRootSignatureTest, InvalidLexUnderflowFloatTest) {
935 // This test will check that the lexing fails due to double underflow
936 const llvm::StringLiteral Source = R"cc(
937 StaticSampler(s0, mipLODBias = 10e-309)
938 )cc";
939
940 TrivialModuleLoader ModLoader;
941 auto PP = createPP(Source, ModLoader);
942 auto TokLoc = SourceLocation();
943
944 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
945 SmallVector<RootElement> Elements;
946 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
947
948 // Test correct diagnostic produced
949 Consumer->setExpected(diag::err_hlsl_number_literal_underflow);
950 ASSERT_TRUE(Parser.parse());
951
952 ASSERT_TRUE(Consumer->isSatisfied());
953}
954
955TEST_F(ParseHLSLRootSignatureTest, InvalidNonZeroFlagsTest) {
956 // This test will check that parsing fails when a non-zero integer literal
957 // is given to flags
958 const llvm::StringLiteral Source = R"cc(
959 DescriptorTable(
960 CBV(b0, flags = 3)
961 )
962 )cc";
963
964 TrivialModuleLoader ModLoader;
965 auto PP = createPP(Source, ModLoader);
966 auto TokLoc = SourceLocation();
967
968 hlsl::RootSignatureLexer Lexer(Source, TokLoc);
969 SmallVector<RootElement> Elements;
970 hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
971
972 // Test correct diagnostic produced
973 Consumer->setExpected(diag::err_hlsl_rootsig_non_zero_flag);
974 ASSERT_TRUE(Parser.parse());
975
976 ASSERT_TRUE(Consumer->isSatisfied());
977}
978
979} // anonymous namespace
980

source code of clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp