1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <memory>
16
17 #include "src/ast/array_accessor_expression.h"
18 #include "src/ast/assignment_statement.h"
19 #include "src/ast/binary_expression.h"
20 #include "src/ast/decorated_variable.h"
21 #include "src/ast/float_literal.h"
22 #include "src/ast/identifier_expression.h"
23 #include "src/ast/member_accessor_expression.h"
24 #include "src/ast/module.h"
25 #include "src/ast/scalar_constructor_expression.h"
26 #include "src/ast/sint_literal.h"
27 #include "src/ast/stride_decoration.h"
28 #include "src/ast/struct.h"
29 #include "src/ast/struct_member.h"
30 #include "src/ast/struct_member_offset_decoration.h"
31 #include "src/ast/type/array_type.h"
32 #include "src/ast/type/f32_type.h"
33 #include "src/ast/type/i32_type.h"
34 #include "src/ast/type/matrix_type.h"
35 #include "src/ast/type/struct_type.h"
36 #include "src/ast/type/vector_type.h"
37 #include "src/ast/type_constructor_expression.h"
38 #include "src/context.h"
39 #include "src/type_determiner.h"
40 #include "src/writer/hlsl/test_helper.h"
41
42 namespace tint {
43 namespace writer {
44 namespace hlsl {
45 namespace {
46
47 using HlslGeneratorImplTest_MemberAccessor = TestHelper;
48
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor)49 TEST_F(HlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) {
50 ast::type::F32Type f32;
51
52 ast::StructMemberList members;
53 ast::StructMemberDecorationList deco;
54 deco.push_back(
55 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
56 members.push_back(
57 std::make_unique<ast::StructMember>("mem", &f32, std::move(deco)));
58
59 auto strct = std::make_unique<ast::Struct>();
60 strct->set_members(std::move(members));
61
62 ast::type::StructType s("Str", std::move(strct));
63
64 auto str_var = std::make_unique<ast::DecoratedVariable>(
65 std::make_unique<ast::Variable>("str", ast::StorageClass::kPrivate, &s));
66
67 auto str = std::make_unique<ast::IdentifierExpression>("str");
68 auto mem = std::make_unique<ast::IdentifierExpression>("mem");
69
70 ast::MemberAccessorExpression expr(std::move(str), std::move(mem));
71
72 td().RegisterVariableForTesting(str_var.get());
73 gen().register_global(str_var.get());
74 mod()->AddGlobalVariable(std::move(str_var));
75
76 ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
77 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
78 EXPECT_EQ(result(), "str.mem");
79 }
80
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Load)81 TEST_F(HlslGeneratorImplTest_MemberAccessor,
82 EmitExpression_MemberAccessor_StorageBuffer_Load) {
83 // struct Data {
84 // [[offset(0)]] a : i32;
85 // [[offset(4)]] b : f32;
86 // };
87 // var<storage_buffer> data : Data;
88 // data.b;
89 //
90 // -> asfloat(data.Load(4));
91 ast::type::F32Type f32;
92 ast::type::I32Type i32;
93
94 ast::StructMemberList members;
95 ast::StructMemberDecorationList a_deco;
96 a_deco.push_back(
97 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
98 members.push_back(
99 std::make_unique<ast::StructMember>("a", &i32, std::move(a_deco)));
100
101 ast::StructMemberDecorationList b_deco;
102 b_deco.push_back(
103 std::make_unique<ast::StructMemberOffsetDecoration>(4, Source{}));
104 members.push_back(
105 std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
106
107 auto str = std::make_unique<ast::Struct>();
108 str->set_members(std::move(members));
109
110 ast::type::StructType s("Data", std::move(str));
111
112 auto coord_var =
113 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
114 "data", ast::StorageClass::kStorageBuffer, &s));
115
116 ast::MemberAccessorExpression expr(
117 std::make_unique<ast::IdentifierExpression>("data"),
118 std::make_unique<ast::IdentifierExpression>("b"));
119
120 td().RegisterVariableForTesting(coord_var.get());
121 gen().register_global(coord_var.get());
122 mod()->AddGlobalVariable(std::move(coord_var));
123
124 ASSERT_TRUE(td().Determine()) << td().error();
125 ASSERT_TRUE(td().DetermineResultType(&expr));
126
127 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
128 EXPECT_EQ(result(), "asfloat(data.Load(4))");
129 }
130
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Load_Int)131 TEST_F(HlslGeneratorImplTest_MemberAccessor,
132 EmitExpression_MemberAccessor_StorageBuffer_Load_Int) {
133 // struct Data {
134 // [[offset(0)]] a : i32;
135 // [[offset(4)]] b : f32;
136 // };
137 // var<storage_buffer> data : Data;
138 // data.a;
139 //
140 // -> asint(data.Load(0));
141 ast::type::F32Type f32;
142 ast::type::I32Type i32;
143
144 ast::StructMemberList members;
145 ast::StructMemberDecorationList a_deco;
146 a_deco.push_back(
147 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
148 members.push_back(
149 std::make_unique<ast::StructMember>("a", &i32, std::move(a_deco)));
150
151 ast::StructMemberDecorationList b_deco;
152 b_deco.push_back(
153 std::make_unique<ast::StructMemberOffsetDecoration>(4, Source{}));
154 members.push_back(
155 std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
156
157 auto str = std::make_unique<ast::Struct>();
158 str->set_members(std::move(members));
159
160 ast::type::StructType s("Data", std::move(str));
161
162 auto coord_var =
163 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
164 "data", ast::StorageClass::kStorageBuffer, &s));
165
166 ast::MemberAccessorExpression expr(
167 std::make_unique<ast::IdentifierExpression>("data"),
168 std::make_unique<ast::IdentifierExpression>("a"));
169
170 td().RegisterVariableForTesting(coord_var.get());
171 gen().register_global(coord_var.get());
172 mod()->AddGlobalVariable(std::move(coord_var));
173
174 ASSERT_TRUE(td().Determine()) << td().error();
175 ASSERT_TRUE(td().DetermineResultType(&expr));
176
177 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
178 EXPECT_EQ(result(), "asint(data.Load(0))");
179 }
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Store_Matrix)180 TEST_F(HlslGeneratorImplTest_MemberAccessor,
181 EmitExpression_MemberAccessor_StorageBuffer_Store_Matrix) {
182 // struct Data {
183 // [[offset(0)]] z : f32;
184 // [[offset(4)]] a : mat2x3<f32>;
185 // };
186 // var<storage_buffer> data : Data;
187 // mat2x3<f32> b;
188 // data.a = b;
189 //
190 // -> matrix<float, 3, 2> _tint_tmp = b;
191 // data.Store3(4 + 0, asuint(_tint_tmp[0]));
192 // data.Store3(4 + 16, asuint(_tint_tmp[1]));
193 ast::type::F32Type f32;
194 ast::type::I32Type i32;
195 ast::type::MatrixType mat(&f32, 3, 2);
196
197 ast::StructMemberList members;
198 ast::StructMemberDecorationList a_deco;
199 a_deco.push_back(
200 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
201 members.push_back(
202 std::make_unique<ast::StructMember>("z", &i32, std::move(a_deco)));
203
204 ast::StructMemberDecorationList b_deco;
205 b_deco.push_back(
206 std::make_unique<ast::StructMemberOffsetDecoration>(4, Source{}));
207 members.push_back(
208 std::make_unique<ast::StructMember>("a", &mat, std::move(b_deco)));
209
210 auto str = std::make_unique<ast::Struct>();
211 str->set_members(std::move(members));
212
213 ast::type::StructType s("Data", std::move(str));
214
215 auto b_var =
216 std::make_unique<ast::Variable>("b", ast::StorageClass::kPrivate, &mat);
217
218 auto coord_var = std::make_unique<ast::Variable>(
219 "data", ast::StorageClass::kStorageBuffer, &s);
220
221 auto lhs = std::make_unique<ast::MemberAccessorExpression>(
222 std::make_unique<ast::IdentifierExpression>("data"),
223 std::make_unique<ast::IdentifierExpression>("a"));
224 auto rhs = std::make_unique<ast::IdentifierExpression>("b");
225
226 ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
227
228 td().RegisterVariableForTesting(coord_var.get());
229 td().RegisterVariableForTesting(b_var.get());
230 gen().register_global(coord_var.get());
231 gen().register_global(b_var.get());
232 mod()->AddGlobalVariable(std::move(coord_var));
233 mod()->AddGlobalVariable(std::move(b_var));
234
235 ASSERT_TRUE(td().Determine()) << td().error();
236 ASSERT_TRUE(td().DetermineResultType(&assign));
237
238 ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
239 EXPECT_EQ(result(), R"(matrix<float, 3, 2> _tint_tmp = b;
240 data.Store3(4 + 0, asuint(_tint_tmp[0]));
241 data.Store3(4 + 16, asuint(_tint_tmp[1]));
242 )");
243 }
244
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Store_Matrix_Empty)245 TEST_F(HlslGeneratorImplTest_MemberAccessor,
246 EmitExpression_MemberAccessor_StorageBuffer_Store_Matrix_Empty) {
247 // struct Data {
248 // [[offset(0)]] z : f32;
249 // [[offset(4)]] a : mat2x3<f32>;
250 // };
251 // var<storage_buffer> data : Data;
252 // data.a = mat2x3<f32>();
253 //
254 // -> matrix<float, 3, 2> _tint_tmp = matrix<float, 3, 2>(0.0f, 0.0f, 0.0f,
255 // 0.0f, 0.0f, 0.0f);
256 // data.Store3(4 + 0, asuint(_tint_tmp[0]);
257 // data.Store3(4 + 16, asuint(_tint_tmp[1]));
258 ast::type::F32Type f32;
259 ast::type::I32Type i32;
260 ast::type::MatrixType mat(&f32, 3, 2);
261
262 ast::StructMemberList members;
263 ast::StructMemberDecorationList a_deco;
264 a_deco.push_back(
265 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
266 members.push_back(
267 std::make_unique<ast::StructMember>("z", &i32, std::move(a_deco)));
268
269 ast::StructMemberDecorationList b_deco;
270 b_deco.push_back(
271 std::make_unique<ast::StructMemberOffsetDecoration>(4, Source{}));
272 members.push_back(
273 std::make_unique<ast::StructMember>("a", &mat, std::move(b_deco)));
274
275 auto str = std::make_unique<ast::Struct>();
276 str->set_members(std::move(members));
277
278 ast::type::StructType s("Data", std::move(str));
279
280 auto coord_var =
281 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
282 "data", ast::StorageClass::kStorageBuffer, &s));
283
284 auto lhs = std::make_unique<ast::MemberAccessorExpression>(
285 std::make_unique<ast::IdentifierExpression>("data"),
286 std::make_unique<ast::IdentifierExpression>("a"));
287 auto rhs = std::make_unique<ast::TypeConstructorExpression>(
288 &mat, ast::ExpressionList{});
289
290 ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
291
292 td().RegisterVariableForTesting(coord_var.get());
293 gen().register_global(coord_var.get());
294 mod()->AddGlobalVariable(std::move(coord_var));
295
296 ASSERT_TRUE(td().Determine()) << td().error();
297 ASSERT_TRUE(td().DetermineResultType(&assign));
298
299 ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
300 EXPECT_EQ(
301 result(),
302 R"(matrix<float, 3, 2> _tint_tmp = matrix<float, 3, 2>(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
303 data.Store3(4 + 0, asuint(_tint_tmp[0]));
304 data.Store3(4 + 16, asuint(_tint_tmp[1]));
305 )");
306 }
307
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix)308 TEST_F(HlslGeneratorImplTest_MemberAccessor,
309 EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix) {
310 // struct Data {
311 // [[offset(0)]] z : f32;
312 // [[offset(4)]] a : mat3x2<f32>;
313 // };
314 // var<storage_buffer> data : Data;
315 // data.a;
316 //
317 // -> asfloat(matrix<uint, 2, 3>(data.Load2(4 + 0), data.Load2(4 + 8),
318 // data.Load2(4 + 16)));
319 ast::type::F32Type f32;
320 ast::type::I32Type i32;
321 ast::type::MatrixType mat(&f32, 2, 3);
322
323 ast::StructMemberList members;
324 ast::StructMemberDecorationList a_deco;
325 a_deco.push_back(
326 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
327 members.push_back(
328 std::make_unique<ast::StructMember>("z", &i32, std::move(a_deco)));
329
330 ast::StructMemberDecorationList b_deco;
331 b_deco.push_back(
332 std::make_unique<ast::StructMemberOffsetDecoration>(4, Source{}));
333 members.push_back(
334 std::make_unique<ast::StructMember>("a", &mat, std::move(b_deco)));
335
336 auto str = std::make_unique<ast::Struct>();
337 str->set_members(std::move(members));
338
339 ast::type::StructType s("Data", std::move(str));
340
341 auto coord_var =
342 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
343 "data", ast::StorageClass::kStorageBuffer, &s));
344
345 ast::MemberAccessorExpression expr(
346 std::make_unique<ast::IdentifierExpression>("data"),
347 std::make_unique<ast::IdentifierExpression>("a"));
348
349 td().RegisterVariableForTesting(coord_var.get());
350 gen().register_global(coord_var.get());
351 mod()->AddGlobalVariable(std::move(coord_var));
352
353 ASSERT_TRUE(td().Determine()) << td().error();
354 ASSERT_TRUE(td().DetermineResultType(&expr));
355
356 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
357 EXPECT_EQ(result(),
358 "asfloat(matrix<uint, 2, 3>(data.Load2(4 + 0), data.Load2(4 + 8), "
359 "data.Load2(4 + 16)))");
360 }
361
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix_Nested)362 TEST_F(HlslGeneratorImplTest_MemberAccessor,
363 EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix_Nested) {
364 // struct Data {
365 // [[offset(0)]] z : f32;
366 // [[offset(4)]] a : mat2x3<f32;
367 // };
368 // struct Outer {
369 // [[offset(0)]] c : f32;
370 // [[offset(4)]] b : Data;
371 // };
372 // var<storage_buffer> data : Outer;
373 // data.b.a;
374 //
375 // -> asfloat(matrix<uint, 3, 2>(data.Load3(4 + 0), data.Load3(4 + 16)));
376 ast::type::F32Type f32;
377 ast::type::I32Type i32;
378 ast::type::MatrixType mat(&f32, 3, 2);
379
380 ast::StructMemberList members;
381 ast::StructMemberDecorationList a_deco;
382 a_deco.push_back(
383 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
384 members.push_back(
385 std::make_unique<ast::StructMember>("z", &i32, std::move(a_deco)));
386
387 ast::StructMemberDecorationList b_deco;
388 b_deco.push_back(
389 std::make_unique<ast::StructMemberOffsetDecoration>(4, Source{}));
390 members.push_back(
391 std::make_unique<ast::StructMember>("a", &mat, std::move(b_deco)));
392
393 auto str = std::make_unique<ast::Struct>();
394 str->set_members(std::move(members));
395
396 ast::type::StructType s("Data", std::move(str));
397
398 auto coord_var =
399 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
400 "data", ast::StorageClass::kStorageBuffer, &s));
401
402 ast::MemberAccessorExpression expr(
403 std::make_unique<ast::IdentifierExpression>("data"),
404 std::make_unique<ast::IdentifierExpression>("a"));
405
406 td().RegisterVariableForTesting(coord_var.get());
407 gen().register_global(coord_var.get());
408 mod()->AddGlobalVariable(std::move(coord_var));
409
410 ASSERT_TRUE(td().Determine()) << td().error();
411 ASSERT_TRUE(td().DetermineResultType(&expr));
412
413 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
414 EXPECT_EQ(
415 result(),
416 "asfloat(matrix<uint, 3, 2>(data.Load3(4 + 0), data.Load3(4 + 16)))");
417 }
418
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix_By3_Is_16_Bytes)419 TEST_F(
420 HlslGeneratorImplTest_MemberAccessor,
421 EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix_By3_Is_16_Bytes) {
422 // struct Data {
423 // [[offset(4)]] a : mat3x3<f32;
424 // };
425 // var<storage_buffer> data : Data;
426 // data.a;
427 //
428 // -> asfloat(matrix<uint, 3, 3>(data.Load3(0), data.Load3(16),
429 // data.Load3(32)));
430 ast::type::F32Type f32;
431 ast::type::I32Type i32;
432 ast::type::MatrixType mat(&f32, 3, 3);
433
434 ast::StructMemberList members;
435 ast::StructMemberDecorationList deco;
436 deco.push_back(
437 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
438 members.push_back(
439 std::make_unique<ast::StructMember>("a", &mat, std::move(deco)));
440
441 auto str = std::make_unique<ast::Struct>();
442 str->set_members(std::move(members));
443
444 ast::type::StructType s("Data", std::move(str));
445
446 auto coord_var =
447 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
448 "data", ast::StorageClass::kStorageBuffer, &s));
449
450 ast::MemberAccessorExpression expr(
451 std::make_unique<ast::IdentifierExpression>("data"),
452 std::make_unique<ast::IdentifierExpression>("a"));
453
454 td().RegisterVariableForTesting(coord_var.get());
455 gen().register_global(coord_var.get());
456 mod()->AddGlobalVariable(std::move(coord_var));
457
458 ASSERT_TRUE(td().Determine()) << td().error();
459 ASSERT_TRUE(td().DetermineResultType(&expr));
460
461 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
462 EXPECT_EQ(result(),
463 "asfloat(matrix<uint, 3, 3>(data.Load3(0 + 0), data.Load3(0 + 16), "
464 "data.Load3(0 + 32)))");
465 }
466
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix_Single_Element)467 TEST_F(HlslGeneratorImplTest_MemberAccessor,
468 EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix_Single_Element) {
469 // struct Data {
470 // [[offset(0)]] z : f32;
471 // [[offset(16)]] a : mat4x3<f32>;
472 // };
473 // var<storage_buffer> data : Data;
474 // data.a[2][1];
475 //
476 // -> asfloat(data.Load((2 * 16) + (1 * 4) + 16)))
477 ast::type::F32Type f32;
478 ast::type::I32Type i32;
479 ast::type::MatrixType mat(&f32, 3, 4);
480
481 ast::StructMemberList members;
482 ast::StructMemberDecorationList a_deco;
483 a_deco.push_back(
484 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
485 members.push_back(
486 std::make_unique<ast::StructMember>("z", &i32, std::move(a_deco)));
487
488 ast::StructMemberDecorationList b_deco;
489 b_deco.push_back(
490 std::make_unique<ast::StructMemberOffsetDecoration>(16, Source{}));
491 members.push_back(
492 std::make_unique<ast::StructMember>("a", &mat, std::move(b_deco)));
493
494 auto str = std::make_unique<ast::Struct>();
495 str->set_members(std::move(members));
496
497 ast::type::StructType s("Data", std::move(str));
498
499 auto coord_var =
500 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
501 "data", ast::StorageClass::kStorageBuffer, &s));
502
503 ast::ArrayAccessorExpression expr(
504 std::make_unique<ast::ArrayAccessorExpression>(
505 std::make_unique<ast::MemberAccessorExpression>(
506 std::make_unique<ast::IdentifierExpression>("data"),
507 std::make_unique<ast::IdentifierExpression>("a")),
508 std::make_unique<ast::ScalarConstructorExpression>(
509 std::make_unique<ast::SintLiteral>(&i32, 2))),
510 std::make_unique<ast::ScalarConstructorExpression>(
511 std::make_unique<ast::SintLiteral>(&i32, 1)));
512
513 td().RegisterVariableForTesting(coord_var.get());
514 gen().register_global(coord_var.get());
515 mod()->AddGlobalVariable(std::move(coord_var));
516
517 ASSERT_TRUE(td().Determine()) << td().error();
518 ASSERT_TRUE(td().DetermineResultType(&expr));
519
520 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
521 EXPECT_EQ(result(), "asfloat(data.Load((4 * 1) + (16 * 2) + 16))");
522 }
523
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_ArrayAccessor_StorageBuffer_Load_Int_FromArray)524 TEST_F(HlslGeneratorImplTest_MemberAccessor,
525 EmitExpression_ArrayAccessor_StorageBuffer_Load_Int_FromArray) {
526 // struct Data {
527 // [[offset(0)]] a : [[stride(4)]] array<i32, 5>;
528 // };
529 // var<storage_buffer> data : Data;
530 // data.a[2];
531 //
532 // -> asint(data.Load((2 * 4));
533 ast::type::F32Type f32;
534 ast::type::I32Type i32;
535 ast::type::ArrayType ary(&i32, 5);
536 ast::ArrayDecorationList decos;
537 decos.push_back(std::make_unique<ast::StrideDecoration>(4, Source{}));
538 ary.set_decorations(std::move(decos));
539
540 ast::StructMemberList members;
541 ast::StructMemberDecorationList a_deco;
542 a_deco.push_back(
543 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
544 members.push_back(
545 std::make_unique<ast::StructMember>("a", &ary, std::move(a_deco)));
546
547 auto str = std::make_unique<ast::Struct>();
548 str->set_members(std::move(members));
549
550 ast::type::StructType s("Data", std::move(str));
551
552 auto coord_var =
553 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
554 "data", ast::StorageClass::kStorageBuffer, &s));
555
556 ast::ArrayAccessorExpression expr(
557 std::make_unique<ast::MemberAccessorExpression>(
558 std::make_unique<ast::IdentifierExpression>("data"),
559 std::make_unique<ast::IdentifierExpression>("a")),
560 std::make_unique<ast::ScalarConstructorExpression>(
561 std::make_unique<ast::SintLiteral>(&i32, 2)));
562
563 td().RegisterVariableForTesting(coord_var.get());
564 gen().register_global(coord_var.get());
565 mod()->AddGlobalVariable(std::move(coord_var));
566
567 ASSERT_TRUE(td().Determine()) << td().error();
568 ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
569
570 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
571 EXPECT_EQ(result(), "asint(data.Load((4 * 2) + 0))");
572 }
573
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_ArrayAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx)574 TEST_F(HlslGeneratorImplTest_MemberAccessor,
575 EmitExpression_ArrayAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx) {
576 // struct Data {
577 // [[offset(0)]] a : [[stride(4)]] array<i32, 5>;
578 // };
579 // var<storage_buffer> data : Data;
580 // data.a[(2 + 4) - 3];
581 //
582 // -> asint(data.Load((4 * ((2 + 4) - 3)));
583 ast::type::F32Type f32;
584 ast::type::I32Type i32;
585 ast::type::ArrayType ary(&i32, 5);
586 ast::ArrayDecorationList decos;
587 decos.push_back(std::make_unique<ast::StrideDecoration>(4, Source{}));
588 ary.set_decorations(std::move(decos));
589
590 ast::StructMemberList members;
591 ast::StructMemberDecorationList a_deco;
592 a_deco.push_back(
593 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
594 members.push_back(
595 std::make_unique<ast::StructMember>("a", &ary, std::move(a_deco)));
596
597 auto str = std::make_unique<ast::Struct>();
598 str->set_members(std::move(members));
599
600 ast::type::StructType s("Data", std::move(str));
601
602 auto coord_var =
603 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
604 "data", ast::StorageClass::kStorageBuffer, &s));
605
606 ast::ArrayAccessorExpression expr(
607 std::make_unique<ast::MemberAccessorExpression>(
608 std::make_unique<ast::IdentifierExpression>("data"),
609 std::make_unique<ast::IdentifierExpression>("a")),
610 std::make_unique<ast::BinaryExpression>(
611 ast::BinaryOp::kSubtract,
612 std::make_unique<ast::BinaryExpression>(
613 ast::BinaryOp::kAdd,
614 std::make_unique<ast::ScalarConstructorExpression>(
615 std::make_unique<ast::SintLiteral>(&i32, 2)),
616 std::make_unique<ast::ScalarConstructorExpression>(
617 std::make_unique<ast::SintLiteral>(&i32, 4))),
618 std::make_unique<ast::ScalarConstructorExpression>(
619 std::make_unique<ast::SintLiteral>(&i32, 3))));
620
621 td().RegisterVariableForTesting(coord_var.get());
622 gen().register_global(coord_var.get());
623 mod()->AddGlobalVariable(std::move(coord_var));
624
625 ASSERT_TRUE(td().Determine()) << td().error();
626 ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
627
628 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
629 EXPECT_EQ(result(), "asint(data.Load((4 * ((2 + 4) - 3)) + 0))");
630 }
631
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Store)632 TEST_F(HlslGeneratorImplTest_MemberAccessor,
633 EmitExpression_MemberAccessor_StorageBuffer_Store) {
634 // struct Data {
635 // [[offset(0)]] a : i32;
636 // [[offset(4)]] b : f32;
637 // };
638 // var<storage_buffer> data : Data;
639 // data.b = 2.3f;
640 //
641 // -> data.Store(0, asuint(2.0f));
642
643 ast::type::F32Type f32;
644 ast::type::I32Type i32;
645
646 ast::StructMemberList members;
647 ast::StructMemberDecorationList a_deco;
648 a_deco.push_back(
649 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
650 members.push_back(
651 std::make_unique<ast::StructMember>("a", &i32, std::move(a_deco)));
652
653 ast::StructMemberDecorationList b_deco;
654 b_deco.push_back(
655 std::make_unique<ast::StructMemberOffsetDecoration>(4, Source{}));
656 members.push_back(
657 std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
658
659 auto str = std::make_unique<ast::Struct>();
660 str->set_members(std::move(members));
661
662 ast::type::StructType s("Data", std::move(str));
663
664 auto coord_var =
665 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
666 "data", ast::StorageClass::kStorageBuffer, &s));
667
668 td().RegisterVariableForTesting(coord_var.get());
669 gen().register_global(coord_var.get());
670 mod()->AddGlobalVariable(std::move(coord_var));
671
672 ASSERT_TRUE(td().Determine()) << td().error();
673
674 auto lhs = std::make_unique<ast::MemberAccessorExpression>(
675 std::make_unique<ast::IdentifierExpression>("data"),
676 std::make_unique<ast::IdentifierExpression>("b"));
677 auto rhs = std::make_unique<ast::ScalarConstructorExpression>(
678 std::make_unique<ast::FloatLiteral>(&f32, 2.0f));
679 ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
680
681 ASSERT_TRUE(td().DetermineResultType(&assign));
682 ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
683 EXPECT_EQ(result(), R"(data.Store(4, asuint(2.00000000f));
684 )");
685 }
686
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Store_ToArray)687 TEST_F(HlslGeneratorImplTest_MemberAccessor,
688 EmitExpression_MemberAccessor_StorageBuffer_Store_ToArray) {
689 // struct Data {
690 // [[offset(0)]] a : [[stride(4)]] array<i32, 5>;
691 // };
692 // var<storage_buffer> data : Data;
693 // data.a[2] = 2;
694 //
695 // -> data.Store((2 * 4), asuint(2.3f));
696
697 ast::type::F32Type f32;
698 ast::type::I32Type i32;
699 ast::type::ArrayType ary(&i32, 5);
700 ast::ArrayDecorationList decos;
701 decos.push_back(std::make_unique<ast::StrideDecoration>(4, Source{}));
702 ary.set_decorations(std::move(decos));
703
704 ast::StructMemberList members;
705 ast::StructMemberDecorationList a_deco;
706 a_deco.push_back(
707 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
708 members.push_back(
709 std::make_unique<ast::StructMember>("a", &ary, std::move(a_deco)));
710
711 auto str = std::make_unique<ast::Struct>();
712 str->set_members(std::move(members));
713
714 ast::type::StructType s("Data", std::move(str));
715
716 auto coord_var =
717 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
718 "data", ast::StorageClass::kStorageBuffer, &s));
719
720 td().RegisterVariableForTesting(coord_var.get());
721 gen().register_global(coord_var.get());
722 mod()->AddGlobalVariable(std::move(coord_var));
723
724 ASSERT_TRUE(td().Determine()) << td().error();
725
726 auto lhs = std::make_unique<ast::ArrayAccessorExpression>(
727 std::make_unique<ast::MemberAccessorExpression>(
728 std::make_unique<ast::IdentifierExpression>("data"),
729 std::make_unique<ast::IdentifierExpression>("a")),
730 std::make_unique<ast::ScalarConstructorExpression>(
731 std::make_unique<ast::SintLiteral>(&i32, 2)));
732 auto rhs = std::make_unique<ast::ScalarConstructorExpression>(
733 std::make_unique<ast::SintLiteral>(&i32, 2));
734 ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
735
736 ASSERT_TRUE(td().DetermineResultType(&assign)) << td().error();
737 ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
738 EXPECT_EQ(result(), R"(data.Store((4 * 2) + 0, asuint(2));
739 )");
740 }
741
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Store_Int)742 TEST_F(HlslGeneratorImplTest_MemberAccessor,
743 EmitExpression_MemberAccessor_StorageBuffer_Store_Int) {
744 // struct Data {
745 // [[offset(0)]] a : i32;
746 // [[offset(4)]] b : f32;
747 // };
748 // var<storage_buffer> data : Data;
749 // data.a = 2;
750 //
751 // -> data.Store(0, asuint(2));
752
753 ast::type::F32Type f32;
754 ast::type::I32Type i32;
755
756 ast::StructMemberList members;
757 ast::StructMemberDecorationList a_deco;
758 a_deco.push_back(
759 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
760 members.push_back(
761 std::make_unique<ast::StructMember>("a", &i32, std::move(a_deco)));
762
763 ast::StructMemberDecorationList b_deco;
764 b_deco.push_back(
765 std::make_unique<ast::StructMemberOffsetDecoration>(4, Source{}));
766 members.push_back(
767 std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
768
769 auto str = std::make_unique<ast::Struct>();
770 str->set_members(std::move(members));
771
772 ast::type::StructType s("Data", std::move(str));
773
774 auto coord_var =
775 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
776 "data", ast::StorageClass::kStorageBuffer, &s));
777
778 td().RegisterVariableForTesting(coord_var.get());
779 gen().register_global(coord_var.get());
780 mod()->AddGlobalVariable(std::move(coord_var));
781
782 ASSERT_TRUE(td().Determine()) << td().error();
783
784 auto lhs = std::make_unique<ast::MemberAccessorExpression>(
785 std::make_unique<ast::IdentifierExpression>("data"),
786 std::make_unique<ast::IdentifierExpression>("a"));
787 auto rhs = std::make_unique<ast::ScalarConstructorExpression>(
788 std::make_unique<ast::SintLiteral>(&i32, 2));
789 ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
790
791 ASSERT_TRUE(td().DetermineResultType(&assign));
792 ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
793 EXPECT_EQ(result(), R"(data.Store(0, asuint(2));
794 )");
795 }
796
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Load_Vec3)797 TEST_F(HlslGeneratorImplTest_MemberAccessor,
798 EmitExpression_MemberAccessor_StorageBuffer_Load_Vec3) {
799 // struct Data {
800 // [[offset(0)]] a : vec3<i32>;
801 // [[offset(16)]] b : vec3<f32>;
802 // };
803 // var<storage_buffer> data : Data;
804 // data.b;
805 //
806 // -> asfloat(data.Load(16));
807
808 ast::type::F32Type f32;
809 ast::type::I32Type i32;
810 ast::type::VectorType ivec3(&i32, 3);
811 ast::type::VectorType fvec3(&f32, 3);
812
813 ast::StructMemberList members;
814 ast::StructMemberDecorationList a_deco;
815 a_deco.push_back(
816 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
817 members.push_back(
818 std::make_unique<ast::StructMember>("a", &ivec3, std::move(a_deco)));
819
820 ast::StructMemberDecorationList b_deco;
821 b_deco.push_back(
822 std::make_unique<ast::StructMemberOffsetDecoration>(16, Source{}));
823 members.push_back(
824 std::make_unique<ast::StructMember>("b", &fvec3, std::move(b_deco)));
825
826 auto str = std::make_unique<ast::Struct>();
827 str->set_members(std::move(members));
828
829 ast::type::StructType s("Data", std::move(str));
830
831 auto coord_var =
832 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
833 "data", ast::StorageClass::kStorageBuffer, &s));
834
835 td().RegisterVariableForTesting(coord_var.get());
836 gen().register_global(coord_var.get());
837 mod()->AddGlobalVariable(std::move(coord_var));
838
839 ASSERT_TRUE(td().Determine()) << td().error();
840
841 ast::MemberAccessorExpression expr(
842 std::make_unique<ast::IdentifierExpression>("data"),
843 std::make_unique<ast::IdentifierExpression>("b"));
844
845 ASSERT_TRUE(td().DetermineResultType(&expr));
846 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
847 EXPECT_EQ(result(), "asfloat(data.Load3(16))");
848 }
849
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Store_Vec3)850 TEST_F(HlslGeneratorImplTest_MemberAccessor,
851 EmitExpression_MemberAccessor_StorageBuffer_Store_Vec3) {
852 // struct Data {
853 // [[offset(0)]] a : vec3<i32>;
854 // [[offset(16)]] b : vec3<f32>;
855 // };
856 // var<storage_buffer> data : Data;
857 // data.b = vec3<f32>(2.3f, 1.2f, 0.2f);
858 //
859 // -> data.Store(16, asuint(vector<float, 3>(2.3f, 1.2f, 0.2f)));
860
861 ast::type::F32Type f32;
862 ast::type::I32Type i32;
863 ast::type::VectorType ivec3(&i32, 3);
864 ast::type::VectorType fvec3(&f32, 3);
865
866 ast::StructMemberList members;
867 ast::StructMemberDecorationList a_deco;
868 a_deco.push_back(
869 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
870 members.push_back(
871 std::make_unique<ast::StructMember>("a", &ivec3, std::move(a_deco)));
872
873 ast::StructMemberDecorationList b_deco;
874 b_deco.push_back(
875 std::make_unique<ast::StructMemberOffsetDecoration>(16, Source{}));
876 members.push_back(
877 std::make_unique<ast::StructMember>("b", &fvec3, std::move(b_deco)));
878
879 auto str = std::make_unique<ast::Struct>();
880 str->set_members(std::move(members));
881
882 ast::type::StructType s("Data", std::move(str));
883
884 auto coord_var =
885 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
886 "data", ast::StorageClass::kStorageBuffer, &s));
887
888 td().RegisterVariableForTesting(coord_var.get());
889 gen().register_global(coord_var.get());
890 mod()->AddGlobalVariable(std::move(coord_var));
891
892 ASSERT_TRUE(td().Determine()) << td().error();
893
894 auto lit1 = std::make_unique<ast::FloatLiteral>(&f32, 1.f);
895 auto lit2 = std::make_unique<ast::FloatLiteral>(&f32, 2.f);
896 auto lit3 = std::make_unique<ast::FloatLiteral>(&f32, 3.f);
897 ast::ExpressionList values;
898 values.push_back(
899 std::make_unique<ast::ScalarConstructorExpression>(std::move(lit1)));
900 values.push_back(
901 std::make_unique<ast::ScalarConstructorExpression>(std::move(lit2)));
902 values.push_back(
903 std::make_unique<ast::ScalarConstructorExpression>(std::move(lit3)));
904
905 auto lhs = std::make_unique<ast::MemberAccessorExpression>(
906 std::make_unique<ast::IdentifierExpression>("data"),
907 std::make_unique<ast::IdentifierExpression>("b"));
908 auto rhs = std::make_unique<ast::TypeConstructorExpression>(
909 &fvec3, std::move(values));
910
911 ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
912
913 ASSERT_TRUE(td().DetermineResultType(&assign));
914 ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
915 EXPECT_EQ(
916 result(),
917 R"(data.Store3(16, asuint(vector<float, 3>(1.00000000f, 2.00000000f, 3.00000000f)));
918 )");
919 }
920
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel)921 TEST_F(HlslGeneratorImplTest_MemberAccessor,
922 EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel) {
923 // struct Data {
924 // [[offset(0)]] a : vec3<i32>;
925 // [[offset(16)]] b : vec3<f32>;
926 // };
927 // struct Pre {
928 // var c : [[stride(32)]] array<Data, 4>;
929 // };
930 //
931 // var<storage_buffer> data : Pre;
932 // data.c[2].b
933 //
934 // -> asfloat(data.Load3(16 + (2 * 32)))
935
936 ast::type::F32Type f32;
937 ast::type::I32Type i32;
938 ast::type::VectorType ivec3(&i32, 3);
939 ast::type::VectorType fvec3(&f32, 3);
940
941 ast::StructMemberList members;
942 ast::StructMemberDecorationList deco;
943 deco.push_back(
944 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
945 members.push_back(
946 std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
947
948 deco.push_back(
949 std::make_unique<ast::StructMemberOffsetDecoration>(16, Source{}));
950 members.push_back(
951 std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
952
953 auto data_str = std::make_unique<ast::Struct>();
954 data_str->set_members(std::move(members));
955
956 ast::type::StructType data("Data", std::move(data_str));
957
958 ast::type::ArrayType ary(&data, 4);
959 ast::ArrayDecorationList decos;
960 decos.push_back(std::make_unique<ast::StrideDecoration>(32, Source{}));
961 ary.set_decorations(std::move(decos));
962
963 deco.push_back(
964 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
965 members.push_back(
966 std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
967
968 auto pre_str = std::make_unique<ast::Struct>();
969 pre_str->set_members(std::move(members));
970
971 ast::type::StructType pre_struct("Pre", std::move(pre_str));
972
973 auto coord_var =
974 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
975 "data", ast::StorageClass::kStorageBuffer, &pre_struct));
976
977 td().RegisterVariableForTesting(coord_var.get());
978 gen().register_global(coord_var.get());
979 mod()->AddGlobalVariable(std::move(coord_var));
980
981 ASSERT_TRUE(td().Determine()) << td().error();
982
983 ast::MemberAccessorExpression expr(
984 std::make_unique<ast::ArrayAccessorExpression>(
985 std::make_unique<ast::MemberAccessorExpression>(
986 std::make_unique<ast::IdentifierExpression>("data"),
987 std::make_unique<ast::IdentifierExpression>("c")),
988 std::make_unique<ast::ScalarConstructorExpression>(
989 std::make_unique<ast::SintLiteral>(&i32, 2))),
990 std::make_unique<ast::IdentifierExpression>("b"));
991
992 ASSERT_TRUE(td().DetermineResultType(&expr));
993 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
994 EXPECT_EQ(result(), "asfloat(data.Load3(16 + (32 * 2) + 0))");
995 }
996
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Swizzle)997 TEST_F(HlslGeneratorImplTest_MemberAccessor,
998 EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Swizzle) {
999 // struct Data {
1000 // [[offset(0)]] a : vec3<i32>;
1001 // [[offset(16)]] b : vec3<f32>;
1002 // };
1003 // struct Pre {
1004 // var c : [[stride(32)]] array<Data, 4>;
1005 // };
1006 //
1007 // var<storage_buffer> data : Pre;
1008 // data.c[2].b.xy
1009 //
1010 // -> asfloat(data.Load3(16 + (2 * 32))).xy
1011
1012 ast::type::F32Type f32;
1013 ast::type::I32Type i32;
1014 ast::type::VectorType ivec3(&i32, 3);
1015 ast::type::VectorType fvec3(&f32, 3);
1016
1017 ast::StructMemberList members;
1018 ast::StructMemberDecorationList deco;
1019 deco.push_back(
1020 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
1021 members.push_back(
1022 std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
1023
1024 deco.push_back(
1025 std::make_unique<ast::StructMemberOffsetDecoration>(16, Source{}));
1026 members.push_back(
1027 std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
1028
1029 auto data_str = std::make_unique<ast::Struct>();
1030 data_str->set_members(std::move(members));
1031
1032 ast::type::StructType data("Data", std::move(data_str));
1033
1034 ast::type::ArrayType ary(&data, 4);
1035 ast::ArrayDecorationList decos;
1036 decos.push_back(std::make_unique<ast::StrideDecoration>(32, Source{}));
1037 ary.set_decorations(std::move(decos));
1038
1039 deco.push_back(
1040 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
1041 members.push_back(
1042 std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
1043
1044 auto pre_str = std::make_unique<ast::Struct>();
1045 pre_str->set_members(std::move(members));
1046
1047 ast::type::StructType pre_struct("Pre", std::move(pre_str));
1048
1049 auto coord_var =
1050 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
1051 "data", ast::StorageClass::kStorageBuffer, &pre_struct));
1052
1053 td().RegisterVariableForTesting(coord_var.get());
1054 gen().register_global(coord_var.get());
1055 mod()->AddGlobalVariable(std::move(coord_var));
1056
1057 ASSERT_TRUE(td().Determine()) << td().error();
1058
1059 ast::MemberAccessorExpression expr(
1060 std::make_unique<ast::MemberAccessorExpression>(
1061 std::make_unique<ast::ArrayAccessorExpression>(
1062 std::make_unique<ast::MemberAccessorExpression>(
1063 std::make_unique<ast::IdentifierExpression>("data"),
1064 std::make_unique<ast::IdentifierExpression>("c")),
1065 std::make_unique<ast::ScalarConstructorExpression>(
1066 std::make_unique<ast::SintLiteral>(&i32, 2))),
1067 std::make_unique<ast::IdentifierExpression>("b")),
1068 std::make_unique<ast::IdentifierExpression>("xy"));
1069
1070 ASSERT_TRUE(td().DetermineResultType(&expr));
1071 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
1072 EXPECT_EQ(result(), "asfloat(data.Load3(16 + (32 * 2) + 0)).xy");
1073 }
1074
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Swizzle_SingleLetter)1075 TEST_F(
1076 HlslGeneratorImplTest_MemberAccessor,
1077 EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Swizzle_SingleLetter) { // NOLINT
1078 // struct Data {
1079 // [[offset(0)]] a : vec3<i32>;
1080 // [[offset(16)]] b : vec3<f32>;
1081 // };
1082 // struct Pre {
1083 // var c : [[stride(32)]] array<Data, 4>;
1084 // };
1085 //
1086 // var<storage_buffer> data : Pre;
1087 // data.c[2].b.g
1088 //
1089 // -> asfloat(data.Load((4 * 1) + 16 + (2 * 32) + 0))
1090
1091 ast::type::F32Type f32;
1092 ast::type::I32Type i32;
1093 ast::type::VectorType ivec3(&i32, 3);
1094 ast::type::VectorType fvec3(&f32, 3);
1095
1096 ast::StructMemberList members;
1097 ast::StructMemberDecorationList deco;
1098 deco.push_back(
1099 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
1100 members.push_back(
1101 std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
1102
1103 deco.push_back(
1104 std::make_unique<ast::StructMemberOffsetDecoration>(16, Source{}));
1105 members.push_back(
1106 std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
1107
1108 auto data_str = std::make_unique<ast::Struct>();
1109 data_str->set_members(std::move(members));
1110
1111 ast::type::StructType data("Data", std::move(data_str));
1112
1113 ast::type::ArrayType ary(&data, 4);
1114 ast::ArrayDecorationList decos;
1115 decos.push_back(std::make_unique<ast::StrideDecoration>(32, Source{}));
1116 ary.set_decorations(std::move(decos));
1117
1118 deco.push_back(
1119 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
1120 members.push_back(
1121 std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
1122
1123 auto pre_str = std::make_unique<ast::Struct>();
1124 pre_str->set_members(std::move(members));
1125
1126 ast::type::StructType pre_struct("Pre", std::move(pre_str));
1127
1128 auto coord_var =
1129 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
1130 "data", ast::StorageClass::kStorageBuffer, &pre_struct));
1131
1132 td().RegisterVariableForTesting(coord_var.get());
1133 gen().register_global(coord_var.get());
1134 mod()->AddGlobalVariable(std::move(coord_var));
1135
1136 ASSERT_TRUE(td().Determine()) << td().error();
1137
1138 ast::MemberAccessorExpression expr(
1139 std::make_unique<ast::MemberAccessorExpression>(
1140 std::make_unique<ast::ArrayAccessorExpression>(
1141 std::make_unique<ast::MemberAccessorExpression>(
1142 std::make_unique<ast::IdentifierExpression>("data"),
1143 std::make_unique<ast::IdentifierExpression>("c")),
1144 std::make_unique<ast::ScalarConstructorExpression>(
1145 std::make_unique<ast::SintLiteral>(&i32, 2))),
1146 std::make_unique<ast::IdentifierExpression>("b")),
1147 std::make_unique<ast::IdentifierExpression>("g"));
1148
1149 ASSERT_TRUE(td().DetermineResultType(&expr));
1150 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
1151 EXPECT_EQ(result(), "asfloat(data.Load((4 * 1) + 16 + (32 * 2) + 0))");
1152 }
1153
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Index)1154 TEST_F(HlslGeneratorImplTest_MemberAccessor,
1155 EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Index) {
1156 // struct Data {
1157 // [[offset(0)]] a : vec3<i32>;
1158 // [[offset(16)]] b : vec3<f32>;
1159 // };
1160 // struct Pre {
1161 // var c : [[stride(32)]] array<Data, 4>;
1162 // };
1163 //
1164 // var<storage_buffer> data : Pre;
1165 // data.c[2].b[1]
1166 //
1167 // -> asfloat(data.Load(4 + 16 + (2 * 32)))
1168
1169 ast::type::F32Type f32;
1170 ast::type::I32Type i32;
1171 ast::type::VectorType ivec3(&i32, 3);
1172 ast::type::VectorType fvec3(&f32, 3);
1173
1174 ast::StructMemberList members;
1175 ast::StructMemberDecorationList deco;
1176 deco.push_back(
1177 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
1178 members.push_back(
1179 std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
1180
1181 deco.push_back(
1182 std::make_unique<ast::StructMemberOffsetDecoration>(16, Source{}));
1183 members.push_back(
1184 std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
1185
1186 auto data_str = std::make_unique<ast::Struct>();
1187 data_str->set_members(std::move(members));
1188
1189 ast::type::StructType data("Data", std::move(data_str));
1190
1191 ast::type::ArrayType ary(&data, 4);
1192 ast::ArrayDecorationList decos;
1193 decos.push_back(std::make_unique<ast::StrideDecoration>(32, Source{}));
1194 ary.set_decorations(std::move(decos));
1195
1196 deco.push_back(
1197 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
1198 members.push_back(
1199 std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
1200
1201 auto pre_str = std::make_unique<ast::Struct>();
1202 pre_str->set_members(std::move(members));
1203
1204 ast::type::StructType pre_struct("Pre", std::move(pre_str));
1205
1206 auto coord_var =
1207 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
1208 "data", ast::StorageClass::kStorageBuffer, &pre_struct));
1209
1210 td().RegisterVariableForTesting(coord_var.get());
1211 gen().register_global(coord_var.get());
1212 mod()->AddGlobalVariable(std::move(coord_var));
1213
1214 ASSERT_TRUE(td().Determine()) << td().error();
1215
1216 ast::ArrayAccessorExpression expr(
1217 std::make_unique<ast::MemberAccessorExpression>(
1218 std::make_unique<ast::ArrayAccessorExpression>(
1219 std::make_unique<ast::MemberAccessorExpression>(
1220 std::make_unique<ast::IdentifierExpression>("data"),
1221 std::make_unique<ast::IdentifierExpression>("c")),
1222 std::make_unique<ast::ScalarConstructorExpression>(
1223 std::make_unique<ast::SintLiteral>(&i32, 2))),
1224 std::make_unique<ast::IdentifierExpression>("b")),
1225 std::make_unique<ast::ScalarConstructorExpression>(
1226 std::make_unique<ast::SintLiteral>(&i32, 1)));
1227
1228 ASSERT_TRUE(td().DetermineResultType(&expr));
1229 ASSERT_TRUE(gen().EmitExpression(pre(), out(), &expr)) << gen().error();
1230 EXPECT_EQ(result(), "asfloat(data.Load((4 * 1) + 16 + (32 * 2) + 0))");
1231 }
1232
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Store_MultiLevel)1233 TEST_F(HlslGeneratorImplTest_MemberAccessor,
1234 EmitExpression_MemberAccessor_StorageBuffer_Store_MultiLevel) {
1235 // struct Data {
1236 // [[offset(0)]] a : vec3<i32>;
1237 // [[offset(16)]] b : vec3<f32>;
1238 // };
1239 // struct Pre {
1240 // var c : [[stride(32)]] array<Data, 4>;
1241 // };
1242 //
1243 // var<storage_buffer> data : Pre;
1244 // data.c[2].b = vec3<f32>(1.f, 2.f, 3.f);
1245 //
1246 // -> data.Store3(16 + (2 * 32), asuint(vector<float, 3>(1.0f, 2.0f, 3.0f)));
1247
1248 ast::type::F32Type f32;
1249 ast::type::I32Type i32;
1250 ast::type::VectorType ivec3(&i32, 3);
1251 ast::type::VectorType fvec3(&f32, 3);
1252
1253 ast::StructMemberList members;
1254 ast::StructMemberDecorationList deco;
1255 deco.push_back(
1256 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
1257 members.push_back(
1258 std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
1259
1260 deco.push_back(
1261 std::make_unique<ast::StructMemberOffsetDecoration>(16, Source{}));
1262 members.push_back(
1263 std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
1264
1265 auto data_str = std::make_unique<ast::Struct>();
1266 data_str->set_members(std::move(members));
1267
1268 ast::type::StructType data("Data", std::move(data_str));
1269
1270 ast::type::ArrayType ary(&data, 4);
1271 ast::ArrayDecorationList decos;
1272 decos.push_back(std::make_unique<ast::StrideDecoration>(32, Source{}));
1273 ary.set_decorations(std::move(decos));
1274
1275 deco.push_back(
1276 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
1277 members.push_back(
1278 std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
1279
1280 auto pre_str = std::make_unique<ast::Struct>();
1281 pre_str->set_members(std::move(members));
1282
1283 ast::type::StructType pre_struct("Pre", std::move(pre_str));
1284
1285 auto coord_var =
1286 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
1287 "data", ast::StorageClass::kStorageBuffer, &pre_struct));
1288
1289 td().RegisterVariableForTesting(coord_var.get());
1290 gen().register_global(coord_var.get());
1291 mod()->AddGlobalVariable(std::move(coord_var));
1292
1293 ASSERT_TRUE(td().Determine()) << td().error();
1294
1295 auto lhs = std::make_unique<ast::MemberAccessorExpression>(
1296 std::make_unique<ast::ArrayAccessorExpression>(
1297 std::make_unique<ast::MemberAccessorExpression>(
1298 std::make_unique<ast::IdentifierExpression>("data"),
1299 std::make_unique<ast::IdentifierExpression>("c")),
1300 std::make_unique<ast::ScalarConstructorExpression>(
1301 std::make_unique<ast::SintLiteral>(&i32, 2))),
1302 std::make_unique<ast::IdentifierExpression>("b"));
1303
1304 auto lit1 = std::make_unique<ast::FloatLiteral>(&f32, 1.f);
1305 auto lit2 = std::make_unique<ast::FloatLiteral>(&f32, 2.f);
1306 auto lit3 = std::make_unique<ast::FloatLiteral>(&f32, 3.f);
1307 ast::ExpressionList values;
1308 values.push_back(
1309 std::make_unique<ast::ScalarConstructorExpression>(std::move(lit1)));
1310 values.push_back(
1311 std::make_unique<ast::ScalarConstructorExpression>(std::move(lit2)));
1312 values.push_back(
1313 std::make_unique<ast::ScalarConstructorExpression>(std::move(lit3)));
1314
1315 auto rhs = std::make_unique<ast::TypeConstructorExpression>(
1316 &fvec3, std::move(values));
1317
1318 ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
1319
1320 ASSERT_TRUE(td().DetermineResultType(&assign));
1321 ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
1322 EXPECT_EQ(
1323 result(),
1324 R"(data.Store3(16 + (32 * 2) + 0, asuint(vector<float, 3>(1.00000000f, 2.00000000f, 3.00000000f)));
1325 )");
1326 }
1327
TEST_F(HlslGeneratorImplTest_MemberAccessor,EmitExpression_MemberAccessor_StorageBuffer_Store_Swizzle_SingleLetter)1328 TEST_F(HlslGeneratorImplTest_MemberAccessor,
1329 EmitExpression_MemberAccessor_StorageBuffer_Store_Swizzle_SingleLetter) {
1330 // struct Data {
1331 // [[offset(0)]] a : vec3<i32>;
1332 // [[offset(16)]] b : vec3<f32>;
1333 // };
1334 // struct Pre {
1335 // var c : [[stride(32)]] array<Data, 4>;
1336 // };
1337 //
1338 // var<storage_buffer> data : Pre;
1339 // data.c[2].b.y = 1.f;
1340 //
1341 // -> data.Store((4 * 1) + 16 + (2 * 32) + 0, asuint(1.0f));
1342
1343 ast::type::F32Type f32;
1344 ast::type::I32Type i32;
1345 ast::type::VectorType ivec3(&i32, 3);
1346 ast::type::VectorType fvec3(&f32, 3);
1347
1348 ast::StructMemberList members;
1349 ast::StructMemberDecorationList deco;
1350 deco.push_back(
1351 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
1352 members.push_back(
1353 std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
1354
1355 deco.push_back(
1356 std::make_unique<ast::StructMemberOffsetDecoration>(16, Source{}));
1357 members.push_back(
1358 std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
1359
1360 auto data_str = std::make_unique<ast::Struct>();
1361 data_str->set_members(std::move(members));
1362
1363 ast::type::StructType data("Data", std::move(data_str));
1364
1365 ast::type::ArrayType ary(&data, 4);
1366 ast::ArrayDecorationList decos;
1367 decos.push_back(std::make_unique<ast::StrideDecoration>(32, Source{}));
1368 ary.set_decorations(std::move(decos));
1369
1370 deco.push_back(
1371 std::make_unique<ast::StructMemberOffsetDecoration>(0, Source{}));
1372 members.push_back(
1373 std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
1374
1375 auto pre_str = std::make_unique<ast::Struct>();
1376 pre_str->set_members(std::move(members));
1377
1378 ast::type::StructType pre_struct("Pre", std::move(pre_str));
1379
1380 auto coord_var =
1381 std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
1382 "data", ast::StorageClass::kStorageBuffer, &pre_struct));
1383
1384 td().RegisterVariableForTesting(coord_var.get());
1385 gen().register_global(coord_var.get());
1386 mod()->AddGlobalVariable(std::move(coord_var));
1387
1388 ASSERT_TRUE(td().Determine()) << td().error();
1389
1390 auto lhs = std::make_unique<ast::MemberAccessorExpression>(
1391 std::make_unique<ast::MemberAccessorExpression>(
1392 std::make_unique<ast::ArrayAccessorExpression>(
1393 std::make_unique<ast::MemberAccessorExpression>(
1394 std::make_unique<ast::IdentifierExpression>("data"),
1395 std::make_unique<ast::IdentifierExpression>("c")),
1396 std::make_unique<ast::ScalarConstructorExpression>(
1397 std::make_unique<ast::SintLiteral>(&i32, 2))),
1398 std::make_unique<ast::IdentifierExpression>("b")),
1399 std::make_unique<ast::IdentifierExpression>("y"));
1400
1401 auto rhs = std::make_unique<ast::ScalarConstructorExpression>(
1402 std::make_unique<ast::FloatLiteral>(&i32, 1.f));
1403
1404 ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
1405
1406 ASSERT_TRUE(td().DetermineResultType(&assign));
1407 ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
1408 EXPECT_EQ(result(),
1409 R"(data.Store((4 * 1) + 16 + (32 * 2) + 0, asuint(1.00000000f));
1410 )");
1411 }
1412
1413 } // namespace
1414 } // namespace hlsl
1415 } // namespace writer
1416 } // namespace tint
1417