1 | //=== LexHLSLRootSignatureTest.cpp - Lex 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/Lex/LexHLSLRootSignature.h" |
10 | #include "gtest/gtest.h" |
11 | |
12 | using namespace clang; |
13 | using TokenKind = hlsl::RootSignatureToken::Kind; |
14 | |
15 | namespace { |
16 | |
17 | // The test fixture. |
18 | class LexHLSLRootSignatureTest : public ::testing::Test { |
19 | protected: |
20 | LexHLSLRootSignatureTest() {} |
21 | |
22 | void checkTokens(hlsl::RootSignatureLexer &Lexer, |
23 | SmallVector<hlsl::RootSignatureToken> &Computed, |
24 | SmallVector<TokenKind> &Expected) { |
25 | for (unsigned I = 0, E = Expected.size(); I != E; ++I) { |
26 | // Skip these to help with the macro generated test |
27 | if (Expected[I] == TokenKind::invalid || |
28 | Expected[I] == TokenKind::end_of_stream) |
29 | continue; |
30 | hlsl::RootSignatureToken Result = Lexer.consumeToken(); |
31 | ASSERT_EQ(Result.TokKind, Expected[I]); |
32 | Computed.push_back(Elt: Result); |
33 | } |
34 | hlsl::RootSignatureToken EndOfStream = Lexer.consumeToken(); |
35 | ASSERT_EQ(EndOfStream.TokKind, TokenKind::end_of_stream); |
36 | ASSERT_TRUE(Lexer.isEndOfBuffer()); |
37 | } |
38 | }; |
39 | |
40 | // Lexing Tests |
41 | |
42 | TEST_F(LexHLSLRootSignatureTest, ValidLexNumbersTest) { |
43 | // This test will check that we can lex different number tokens |
44 | const llvm::StringLiteral Source = R"cc( |
45 | -42 42 +42 +2147483648 |
46 | 42. 4.2 .42 |
47 | 42f 4.2F |
48 | .42e+3 4.2E-12 |
49 | 42.e+10f |
50 | )cc" ; |
51 | |
52 | auto TokLoc = SourceLocation(); |
53 | |
54 | hlsl::RootSignatureLexer Lexer(Source, TokLoc); |
55 | |
56 | SmallVector<hlsl::RootSignatureToken> Tokens; |
57 | SmallVector<TokenKind> Expected = { |
58 | TokenKind::pu_minus, TokenKind::int_literal, |
59 | TokenKind::int_literal, TokenKind::pu_plus, |
60 | TokenKind::int_literal, TokenKind::pu_plus, |
61 | TokenKind::int_literal, TokenKind::float_literal, |
62 | TokenKind::float_literal, TokenKind::float_literal, |
63 | TokenKind::float_literal, TokenKind::float_literal, |
64 | TokenKind::float_literal, TokenKind::float_literal, |
65 | TokenKind::float_literal, |
66 | }; |
67 | checkTokens(Lexer, Computed&: Tokens, Expected); |
68 | |
69 | // Sample negative: int component |
70 | hlsl::RootSignatureToken IntToken = Tokens[1]; |
71 | ASSERT_EQ(IntToken.NumSpelling, "42" ); |
72 | |
73 | // Sample unsigned int |
74 | IntToken = Tokens[2]; |
75 | ASSERT_EQ(IntToken.NumSpelling, "42" ); |
76 | |
77 | // Sample positive: int component |
78 | IntToken = Tokens[4]; |
79 | ASSERT_EQ(IntToken.NumSpelling, "42" ); |
80 | |
81 | // Sample positive int that would overflow the signed representation but |
82 | // is treated as an unsigned integer instead |
83 | IntToken = Tokens[6]; |
84 | ASSERT_EQ(IntToken.NumSpelling, "2147483648" ); |
85 | |
86 | // Sample decimal end |
87 | hlsl::RootSignatureToken FloatToken = Tokens[7]; |
88 | ASSERT_EQ(FloatToken.NumSpelling, "42." ); |
89 | |
90 | // Sample decimal middle |
91 | FloatToken = Tokens[8]; |
92 | ASSERT_EQ(FloatToken.NumSpelling, "4.2" ); |
93 | |
94 | // Sample decimal start |
95 | FloatToken = Tokens[9]; |
96 | ASSERT_EQ(FloatToken.NumSpelling, ".42" ); |
97 | |
98 | // Sample float lower |
99 | FloatToken = Tokens[10]; |
100 | ASSERT_EQ(FloatToken.NumSpelling, "42f" ); |
101 | |
102 | // Sample float upper |
103 | FloatToken = Tokens[11]; |
104 | ASSERT_EQ(FloatToken.NumSpelling, "4.2F" ); |
105 | |
106 | // Sample exp + |
107 | FloatToken = Tokens[12]; |
108 | ASSERT_EQ(FloatToken.NumSpelling, ".42e+3" ); |
109 | |
110 | // Sample exp - |
111 | FloatToken = Tokens[13]; |
112 | ASSERT_EQ(FloatToken.NumSpelling, "4.2E-12" ); |
113 | |
114 | // Sample all combined |
115 | FloatToken = Tokens[14]; |
116 | ASSERT_EQ(FloatToken.NumSpelling, "42.e+10f" ); |
117 | } |
118 | |
119 | TEST_F(LexHLSLRootSignatureTest, ValidLexAllTokensTest) { |
120 | // This test will check that we can lex all defined tokens as defined in |
121 | // HLSLRootSignatureTokenKinds.def, plus some additional integer variations |
122 | const llvm::StringLiteral Source = R"cc( |
123 | 42 42.0f |
124 | |
125 | b0 t43 u987 s234 |
126 | |
127 | (),|=+- |
128 | |
129 | RootSignature |
130 | |
131 | RootFlags DescriptorTable RootConstants StaticSampler |
132 | |
133 | num32BitConstants |
134 | |
135 | CBV SRV UAV Sampler |
136 | space visibility flags |
137 | numDescriptors offset |
138 | |
139 | filter mipLODBias addressU addressV addressW |
140 | maxAnisotropy comparisonFunc borderColor |
141 | minLOD maxLOD |
142 | |
143 | unbounded |
144 | DESCRIPTOR_RANGE_OFFSET_APPEND |
145 | |
146 | allow_input_assembler_input_layout |
147 | deny_vertex_shader_root_access |
148 | deny_hull_shader_root_access |
149 | deny_domain_shader_root_access |
150 | deny_geometry_shader_root_access |
151 | deny_pixel_shader_root_access |
152 | deny_amplification_shader_root_access |
153 | deny_mesh_shader_root_access |
154 | allow_stream_output |
155 | local_root_signature |
156 | cbv_srv_uav_heap_directly_indexed |
157 | sampler_heap_directly_indexed |
158 | |
159 | DATA_VOLATILE |
160 | DATA_STATIC_WHILE_SET_AT_EXECUTE |
161 | DATA_STATIC |
162 | DESCRIPTORS_VOLATILE |
163 | DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS |
164 | |
165 | shader_visibility_all |
166 | shader_visibility_vertex |
167 | shader_visibility_hull |
168 | shader_visibility_domain |
169 | shader_visibility_geometry |
170 | shader_visibility_pixel |
171 | shader_visibility_amplification |
172 | shader_visibility_mesh |
173 | |
174 | FILTER_MIN_MAG_MIP_POINT |
175 | FILTER_MIN_MAG_POINT_MIP_LINEAR |
176 | FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT |
177 | FILTER_MIN_POINT_MAG_MIP_LINEAR |
178 | FILTER_MIN_LINEAR_MAG_MIP_POINT |
179 | FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR |
180 | FILTER_MIN_MAG_LINEAR_MIP_POINT |
181 | FILTER_MIN_MAG_MIP_LINEAR |
182 | FILTER_ANISOTROPIC |
183 | FILTER_COMPARISON_MIN_MAG_MIP_POINT |
184 | FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR |
185 | FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT |
186 | FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR |
187 | FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT |
188 | FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR |
189 | FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT |
190 | FILTER_COMPARISON_MIN_MAG_MIP_LINEAR |
191 | FILTER_COMPARISON_ANISOTROPIC |
192 | FILTER_MINIMUM_MIN_MAG_MIP_POINT |
193 | FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR |
194 | FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT |
195 | FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR |
196 | FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT |
197 | FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR |
198 | FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT |
199 | FILTER_MINIMUM_MIN_MAG_MIP_LINEAR |
200 | FILTER_MINIMUM_ANISOTROPIC |
201 | FILTER_MAXIMUM_MIN_MAG_MIP_POINT |
202 | FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR |
203 | FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT |
204 | FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR |
205 | FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT |
206 | FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR |
207 | FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT |
208 | FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR |
209 | FILTER_MAXIMUM_ANISOTROPIC |
210 | |
211 | TEXTURE_ADDRESS_WRAP |
212 | TEXTURE_ADDRESS_MIRROR |
213 | TEXTURE_ADDRESS_CLAMP |
214 | TEXTURE_ADDRESS_BORDER |
215 | TEXTURE_ADDRESS_MIRRORONCE |
216 | |
217 | comparison_never |
218 | comparison_less |
219 | comparison_equal |
220 | comparison_less_equal |
221 | comparison_greater |
222 | comparison_not_equal |
223 | comparison_greater_equal |
224 | comparison_always |
225 | |
226 | STATIC_BORDER_COLOR_TRANSPARENT_BLACK |
227 | STATIC_BORDER_COLOR_OPAQUE_BLACK |
228 | STATIC_BORDER_COLOR_OPAQUE_WHITE |
229 | STATIC_BORDER_COLOR_OPAQUE_BLACK_UINT |
230 | STATIC_BORDER_COLOR_OPAQUE_WHITE_UINT |
231 | )cc" ; |
232 | auto TokLoc = SourceLocation(); |
233 | hlsl::RootSignatureLexer Lexer(Source, TokLoc); |
234 | |
235 | SmallVector<hlsl::RootSignatureToken> Tokens; |
236 | SmallVector<TokenKind> Expected = { |
237 | #define TOK(NAME, SPELLING) TokenKind::NAME, |
238 | #include "clang/Lex/HLSLRootSignatureTokenKinds.def" |
239 | }; |
240 | |
241 | checkTokens(Lexer, Computed&: Tokens, Expected); |
242 | } |
243 | |
244 | TEST_F(LexHLSLRootSignatureTest, ValidCaseInsensitiveKeywordsTest) { |
245 | // This test will check that we can lex keywords in an case-insensitive |
246 | // manner |
247 | const llvm::StringLiteral Source = R"cc( |
248 | DeScRiPtOrTaBlE |
249 | |
250 | CBV srv UAV sampler |
251 | SPACE visibility FLAGS |
252 | numDescriptors OFFSET |
253 | )cc" ; |
254 | auto TokLoc = SourceLocation(); |
255 | hlsl::RootSignatureLexer Lexer(Source, TokLoc); |
256 | |
257 | SmallVector<hlsl::RootSignatureToken> Tokens; |
258 | SmallVector<TokenKind> Expected = { |
259 | TokenKind::kw_DescriptorTable, |
260 | TokenKind::kw_CBV, |
261 | TokenKind::kw_SRV, |
262 | TokenKind::kw_UAV, |
263 | TokenKind::kw_Sampler, |
264 | TokenKind::kw_space, |
265 | TokenKind::kw_visibility, |
266 | TokenKind::kw_flags, |
267 | TokenKind::kw_numDescriptors, |
268 | TokenKind::kw_offset, |
269 | }; |
270 | |
271 | checkTokens(Lexer, Computed&: Tokens, Expected); |
272 | } |
273 | |
274 | TEST_F(LexHLSLRootSignatureTest, ValidLexPeekTest) { |
275 | // This test will check that we the peek api is correctly used |
276 | const llvm::StringLiteral Source = R"cc( |
277 | )1 |
278 | )cc" ; |
279 | auto TokLoc = SourceLocation(); |
280 | hlsl::RootSignatureLexer Lexer(Source, TokLoc); |
281 | |
282 | // Test basic peek |
283 | hlsl::RootSignatureToken Res = Lexer.peekNextToken(); |
284 | ASSERT_EQ(Res.TokKind, TokenKind::pu_r_paren); |
285 | |
286 | // Ensure it doesn't peek past one element |
287 | Res = Lexer.peekNextToken(); |
288 | ASSERT_EQ(Res.TokKind, TokenKind::pu_r_paren); |
289 | |
290 | Res = Lexer.consumeToken(); |
291 | ASSERT_EQ(Res.TokKind, TokenKind::pu_r_paren); |
292 | |
293 | // Invoke after reseting the NextToken |
294 | Res = Lexer.peekNextToken(); |
295 | ASSERT_EQ(Res.TokKind, TokenKind::int_literal); |
296 | |
297 | // Ensure we can still consume the second token |
298 | Res = Lexer.consumeToken(); |
299 | ASSERT_EQ(Res.TokKind, TokenKind::int_literal); |
300 | |
301 | // Ensure end of stream token |
302 | Res = Lexer.peekNextToken(); |
303 | ASSERT_EQ(Res.TokKind, TokenKind::end_of_stream); |
304 | } |
305 | |
306 | } // anonymous namespace |
307 | |