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