• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/writer/spirv/spv_dump.h"
16 #include "src/writer/spirv/test_helper.h"
17 
18 namespace tint {
19 namespace writer {
20 namespace spirv {
21 namespace {
22 
23 using BuilderTest = TestHelper;
24 
TEST_F(BuilderTest,IndexAccessor_VectorRef_Literal)25 TEST_F(BuilderTest, IndexAccessor_VectorRef_Literal) {
26   // var ary : vec3<f32>;
27   // ary[1]  -> ref<f32>
28 
29   auto* var = Var("ary", ty.vec3<f32>());
30 
31   auto* ary = Expr("ary");
32   auto* idx_expr = Expr(1);
33 
34   auto* expr = IndexAccessor(ary, idx_expr);
35   WrapInFunction(var, expr);
36 
37   spirv::Builder& b = Build();
38 
39   b.push_function(Function{});
40   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
41 
42   EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
43 
44   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
45 %3 = OpTypeVector %4 3
46 %2 = OpTypePointer Function %3
47 %5 = OpConstantNull %3
48 %6 = OpTypeInt 32 1
49 %7 = OpConstant %6 1
50 %8 = OpTypePointer Function %4
51 )");
52   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
53             R"(%1 = OpVariable %2 Function %5
54 )");
55   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
56             R"(%9 = OpAccessChain %8 %1 %7
57 )");
58 }
59 
TEST_F(BuilderTest,IndexAccessor_VectorRef_Dynamic)60 TEST_F(BuilderTest, IndexAccessor_VectorRef_Dynamic) {
61   // var ary : vec3<f32>;
62   // var idx : i32;
63   // ary[idx]  -> ref<f32>
64 
65   auto* var = Var("ary", ty.vec3<f32>());
66   auto* idx = Var("idx", ty.i32());
67 
68   auto* ary = Expr("ary");
69   auto* idx_expr = Expr("idx");
70 
71   auto* expr = IndexAccessor(ary, idx_expr);
72   WrapInFunction(var, idx, expr);
73 
74   spirv::Builder& b = Build();
75 
76   b.push_function(Function{});
77   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
78   ASSERT_TRUE(b.GenerateFunctionVariable(idx)) << b.error();
79 
80   EXPECT_EQ(b.GenerateAccessorExpression(expr), 12u);
81 
82   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
83 %3 = OpTypeVector %4 3
84 %2 = OpTypePointer Function %3
85 %5 = OpConstantNull %3
86 %8 = OpTypeInt 32 1
87 %7 = OpTypePointer Function %8
88 %9 = OpConstantNull %8
89 %11 = OpTypePointer Function %4
90 )");
91   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
92             R"(%1 = OpVariable %2 Function %5
93 %6 = OpVariable %7 Function %9
94 )");
95   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
96             R"(%10 = OpLoad %8 %6
97 %12 = OpAccessChain %11 %1 %10
98 )");
99 }
100 
TEST_F(BuilderTest,IndexAccessor_VectorRef_Dynamic2)101 TEST_F(BuilderTest, IndexAccessor_VectorRef_Dynamic2) {
102   // var ary : vec3<f32>;
103   // ary[1 + 2]  -> ref<f32>
104 
105   auto* var = Var("ary", ty.vec3<f32>());
106 
107   auto* ary = Expr("ary");
108 
109   auto* expr = IndexAccessor(ary, Add(1, 2));
110   WrapInFunction(var, expr);
111 
112   spirv::Builder& b = Build();
113 
114   b.push_function(Function{});
115   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
116 
117   EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u);
118 
119   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
120 %3 = OpTypeVector %4 3
121 %2 = OpTypePointer Function %3
122 %5 = OpConstantNull %3
123 %6 = OpTypeInt 32 1
124 %7 = OpConstant %6 1
125 %8 = OpConstant %6 2
126 %10 = OpTypePointer Function %4
127 )");
128   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
129             R"(%1 = OpVariable %2 Function %5
130 )");
131   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
132             R"(%9 = OpIAdd %6 %7 %8
133 %11 = OpAccessChain %10 %1 %9
134 )");
135 }
136 
TEST_F(BuilderTest,IndexAccessor_ArrayRef_MultiLevel)137 TEST_F(BuilderTest, IndexAccessor_ArrayRef_MultiLevel) {
138   auto* ary4 = ty.array(ty.vec3<f32>(), 4);
139 
140   // var ary : array<vec3<f32>, 4>
141   // ary[3][2];
142 
143   auto* var = Var("ary", ary4);
144 
145   auto* expr = IndexAccessor(IndexAccessor("ary", 3), 2);
146   WrapInFunction(var, expr);
147 
148   spirv::Builder& b = Build();
149 
150   b.push_function(Function{});
151   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
152 
153   EXPECT_EQ(b.GenerateAccessorExpression(expr), 13u);
154 
155   EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
156 %4 = OpTypeVector %5 3
157 %6 = OpTypeInt 32 0
158 %7 = OpConstant %6 4
159 %3 = OpTypeArray %4 %7
160 %2 = OpTypePointer Function %3
161 %8 = OpConstantNull %3
162 %9 = OpTypeInt 32 1
163 %10 = OpConstant %9 3
164 %11 = OpConstant %9 2
165 %12 = OpTypePointer Function %5
166 )");
167   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
168             R"(%1 = OpVariable %2 Function %8
169 )");
170   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
171             R"(%13 = OpAccessChain %12 %1 %10 %11
172 )");
173 }
174 
TEST_F(BuilderTest,IndexAccessor_ArrayRef_ArrayWithSwizzle)175 TEST_F(BuilderTest, IndexAccessor_ArrayRef_ArrayWithSwizzle) {
176   auto* ary4 = ty.array(ty.vec3<f32>(), 4);
177 
178   // var a : array<vec3<f32>, 4>;
179   // a[2].xy;
180 
181   auto* var = Var("ary", ary4);
182 
183   auto* expr = MemberAccessor(IndexAccessor("ary", 2), "xy");
184   WrapInFunction(var, expr);
185 
186   spirv::Builder& b = Build();
187 
188   b.push_function(Function{});
189   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
190   EXPECT_EQ(b.GenerateAccessorExpression(expr), 15u);
191 
192   EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
193 %4 = OpTypeVector %5 3
194 %6 = OpTypeInt 32 0
195 %7 = OpConstant %6 4
196 %3 = OpTypeArray %4 %7
197 %2 = OpTypePointer Function %3
198 %8 = OpConstantNull %3
199 %9 = OpTypeInt 32 1
200 %10 = OpConstant %9 2
201 %11 = OpTypePointer Function %4
202 %13 = OpTypeVector %5 2
203 )");
204   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
205             R"(%1 = OpVariable %2 Function %8
206 )");
207   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
208             R"(%12 = OpAccessChain %11 %1 %10
209 %14 = OpLoad %4 %12
210 %15 = OpVectorShuffle %13 %14 %14 0 1
211 )");
212 }
213 
TEST_F(BuilderTest,MemberAccessor)214 TEST_F(BuilderTest, MemberAccessor) {
215   // my_struct {
216   //   a : f32
217   //   b : f32
218   // }
219   // var ident : my_struct
220   // ident.b
221 
222   auto* s = Structure("my_struct", {
223                                        Member("a", ty.f32()),
224                                        Member("b", ty.f32()),
225                                    });
226 
227   auto* var = Var("ident", ty.Of(s));
228 
229   auto* expr = MemberAccessor("ident", "b");
230   WrapInFunction(var, expr);
231 
232   spirv::Builder& b = Build();
233 
234   b.push_function(Function{});
235   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
236 
237   EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
238 
239   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
240 %3 = OpTypeStruct %4 %4
241 %2 = OpTypePointer Function %3
242 %5 = OpConstantNull %3
243 %6 = OpTypeInt 32 0
244 %7 = OpConstant %6 1
245 %8 = OpTypePointer Function %4
246 )");
247   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
248             R"(%1 = OpVariable %2 Function %5
249 )");
250   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
251             R"(%9 = OpAccessChain %8 %1 %7
252 )");
253 }
254 
TEST_F(BuilderTest,MemberAccessor_Nested)255 TEST_F(BuilderTest, MemberAccessor_Nested) {
256   // inner_struct {
257   //   a : f32
258   //   b : f32
259   // }
260   // my_struct {
261   //   inner : inner_struct
262   // }
263   //
264   // var ident : my_struct
265   // ident.inner.a
266   auto* inner_struct = Structure("Inner", {
267                                               Member("a", ty.f32()),
268                                               Member("b", ty.f32()),
269                                           });
270 
271   auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
272 
273   auto* var = Var("ident", ty.Of(s_type));
274   auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
275   WrapInFunction(var, expr);
276 
277   spirv::Builder& b = Build();
278 
279   b.push_function(Function{});
280   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
281 
282   EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u);
283 
284   EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
285 %4 = OpTypeStruct %5 %5
286 %3 = OpTypeStruct %4
287 %2 = OpTypePointer Function %3
288 %6 = OpConstantNull %3
289 %7 = OpTypeInt 32 0
290 %8 = OpConstant %7 0
291 %9 = OpConstant %7 1
292 %10 = OpTypePointer Function %5
293 )");
294   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
295             R"(%1 = OpVariable %2 Function %6
296 )");
297   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
298             R"(%11 = OpAccessChain %10 %1 %8 %9
299 )");
300 }
301 
TEST_F(BuilderTest,MemberAccessor_NonPointer)302 TEST_F(BuilderTest, MemberAccessor_NonPointer) {
303   // my_struct {
304   //   a : f32
305   //   b : f32
306   // }
307   // let ident : my_struct = my_struct();
308   // ident.b
309 
310   auto* s = Structure("my_struct", {
311                                        Member("a", ty.f32()),
312                                        Member("b", ty.f32()),
313                                    });
314 
315   auto* var = Const("ident", ty.Of(s), Construct(ty.Of(s), 0.f, 0.f));
316 
317   auto* expr = MemberAccessor("ident", "b");
318   WrapInFunction(var, expr);
319 
320   spirv::Builder& b = Build();
321 
322   b.push_function(Function{});
323   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
324 
325   EXPECT_EQ(b.GenerateAccessorExpression(expr), 5u);
326 
327   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
328 %1 = OpTypeStruct %2 %2
329 %3 = OpConstant %2 0
330 %4 = OpConstantComposite %1 %3 %3
331 )");
332   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
333             R"(%5 = OpCompositeExtract %2 %4 1
334 )");
335 }
336 
TEST_F(BuilderTest,MemberAccessor_Nested_NonPointer)337 TEST_F(BuilderTest, MemberAccessor_Nested_NonPointer) {
338   // inner_struct {
339   //   a : f32
340   //   b : f32
341   // }
342   // my_struct {
343   //   inner : inner_struct
344   // }
345   //
346   // let ident : my_struct = my_struct();
347   // ident.inner.a
348   auto* inner_struct = Structure("Inner", {
349                                               Member("a", ty.f32()),
350                                               Member("b", ty.f32()),
351                                           });
352 
353   auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
354 
355   auto* var =
356       Const("ident", ty.Of(s_type),
357             Construct(ty.Of(s_type), Construct(ty.Of(inner_struct), 0.f, 0.f)));
358   auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
359   WrapInFunction(var, expr);
360 
361   spirv::Builder& b = Build();
362 
363   b.push_function(Function{});
364   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
365 
366   EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
367 
368   EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
369 %2 = OpTypeStruct %3 %3
370 %1 = OpTypeStruct %2
371 %4 = OpConstant %3 0
372 %5 = OpConstantComposite %2 %4 %4
373 %6 = OpConstantComposite %1 %5
374 )");
375   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
376             R"(%7 = OpCompositeExtract %2 %6 0
377 %8 = OpCompositeExtract %3 %7 1
378 )");
379 }
380 
TEST_F(BuilderTest,MemberAccessor_Nested_WithAlias)381 TEST_F(BuilderTest, MemberAccessor_Nested_WithAlias) {
382   // struct Inner {
383   //   a : f32
384   //   b : f32
385   // };
386   // type Alias = Inner;
387   // my_struct {
388   //   inner : Inner
389   // }
390   //
391   // var ident : my_struct
392   // ident.inner.a
393   auto* inner_struct = Structure("Inner", {
394                                               Member("a", ty.f32()),
395                                               Member("b", ty.f32()),
396                                           });
397 
398   auto* alias = Alias("Alias", ty.Of(inner_struct));
399   auto* s_type = Structure("Outer", {Member("inner", ty.Of(alias))});
400 
401   auto* var = Var("ident", ty.Of(s_type));
402   auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a");
403   WrapInFunction(var, expr);
404 
405   spirv::Builder& b = Build();
406 
407   b.push_function(Function{});
408   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
409 
410   EXPECT_EQ(b.GenerateAccessorExpression(expr), 10u);
411 
412   EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
413 %4 = OpTypeStruct %5 %5
414 %3 = OpTypeStruct %4
415 %2 = OpTypePointer Function %3
416 %6 = OpConstantNull %3
417 %7 = OpTypeInt 32 0
418 %8 = OpConstant %7 0
419 %9 = OpTypePointer Function %5
420 )");
421   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
422             R"(%1 = OpVariable %2 Function %6
423 )");
424   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
425             R"(%10 = OpAccessChain %9 %1 %8 %8
426 )");
427 }
428 
TEST_F(BuilderTest,MemberAccessor_Nested_Assignment_LHS)429 TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_LHS) {
430   // inner_struct {
431   //   a : f32
432   // }
433   // my_struct {
434   //   inner : inner_struct
435   // }
436   //
437   // var ident : my_struct
438   // ident.inner.a = 2.0f;
439   auto* inner_struct = Structure("Inner", {
440                                               Member("a", ty.f32()),
441                                               Member("b", ty.f32()),
442                                           });
443 
444   auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
445 
446   auto* var = Var("ident", ty.Of(s_type));
447   auto* expr =
448       Assign(MemberAccessor(MemberAccessor("ident", "inner"), "a"), Expr(2.0f));
449   WrapInFunction(var, expr);
450 
451   spirv::Builder& b = Build();
452 
453   b.push_function(Function{});
454   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
455 
456   EXPECT_TRUE(b.GenerateAssignStatement(expr)) << b.error();
457 
458   EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
459 %4 = OpTypeStruct %5 %5
460 %3 = OpTypeStruct %4
461 %2 = OpTypePointer Function %3
462 %6 = OpConstantNull %3
463 %7 = OpTypeInt 32 0
464 %8 = OpConstant %7 0
465 %9 = OpTypePointer Function %5
466 %11 = OpConstant %5 2
467 )");
468   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
469             R"(%1 = OpVariable %2 Function %6
470 )");
471   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
472             R"(%10 = OpAccessChain %9 %1 %8 %8
473 OpStore %10 %11
474 )");
475 }
476 
TEST_F(BuilderTest,MemberAccessor_Nested_Assignment_RHS)477 TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_RHS) {
478   // inner_struct {
479   //   a : f32
480   // }
481   // my_struct {
482   //   inner : inner_struct
483   // }
484   //
485   // var ident : my_struct
486   // var store : f32 = ident.inner.a
487 
488   auto* inner_struct = Structure("Inner", {
489                                               Member("a", ty.f32()),
490                                               Member("b", ty.f32()),
491                                           });
492 
493   auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
494 
495   auto* var = Var("ident", ty.Of(s_type));
496   auto* store = Var("store", ty.f32());
497 
498   auto* rhs = MemberAccessor(MemberAccessor("ident", "inner"), "a");
499   auto* expr = Assign("store", rhs);
500   WrapInFunction(var, store, expr);
501 
502   spirv::Builder& b = Build();
503 
504   b.push_function(Function{});
505   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
506   ASSERT_TRUE(b.GenerateFunctionVariable(store)) << b.error();
507 
508   EXPECT_TRUE(b.GenerateAssignStatement(expr)) << b.error();
509 
510   EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
511 %4 = OpTypeStruct %5 %5
512 %3 = OpTypeStruct %4
513 %2 = OpTypePointer Function %3
514 %6 = OpConstantNull %3
515 %8 = OpTypePointer Function %5
516 %9 = OpConstantNull %5
517 %10 = OpTypeInt 32 0
518 %11 = OpConstant %10 0
519 )");
520   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
521             R"(%1 = OpVariable %2 Function %6
522 %7 = OpVariable %8 Function %9
523 )");
524   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
525             R"(%12 = OpAccessChain %8 %1 %11 %11
526 %13 = OpLoad %5 %12
527 OpStore %7 %13
528 )");
529 }
530 
TEST_F(BuilderTest,MemberAccessor_Swizzle_Single)531 TEST_F(BuilderTest, MemberAccessor_Swizzle_Single) {
532   // ident.y
533 
534   auto* var = Var("ident", ty.vec3<f32>());
535 
536   auto* expr = MemberAccessor("ident", "y");
537   WrapInFunction(var, expr);
538 
539   spirv::Builder& b = Build();
540 
541   b.push_function(Function{});
542   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
543 
544   EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
545 
546   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
547 %3 = OpTypeVector %4 3
548 %2 = OpTypePointer Function %3
549 %5 = OpConstantNull %3
550 %6 = OpTypeInt 32 0
551 %7 = OpConstant %6 1
552 %8 = OpTypePointer Function %4
553 )");
554   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
555             R"(%1 = OpVariable %2 Function %5
556 )");
557   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
558             R"(%9 = OpAccessChain %8 %1 %7
559 )");
560 }
561 
TEST_F(BuilderTest,MemberAccessor_Swizzle_MultipleNames)562 TEST_F(BuilderTest, MemberAccessor_Swizzle_MultipleNames) {
563   // ident.yx
564 
565   auto* var = Var("ident", ty.vec3<f32>());
566 
567   auto* expr = MemberAccessor("ident", "yx");
568   WrapInFunction(var, expr);
569 
570   spirv::Builder& b = Build();
571 
572   b.push_function(Function{});
573   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
574 
575   EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
576 
577   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
578 %3 = OpTypeVector %4 3
579 %2 = OpTypePointer Function %3
580 %5 = OpConstantNull %3
581 %6 = OpTypeVector %4 2
582 )");
583   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
584             R"(%1 = OpVariable %2 Function %5
585 )");
586   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
587             R"(%7 = OpLoad %3 %1
588 %8 = OpVectorShuffle %6 %7 %7 1 0
589 )");
590 }
591 
TEST_F(BuilderTest,MemberAccessor_Swizzle_of_Swizzle)592 TEST_F(BuilderTest, MemberAccessor_Swizzle_of_Swizzle) {
593   // ident.yxz.xz
594 
595   auto* var = Var("ident", ty.vec3<f32>());
596 
597   auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "xz");
598   WrapInFunction(var, expr);
599 
600   spirv::Builder& b = Build();
601 
602   b.push_function(Function{});
603   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
604 
605   EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
606 
607   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
608 %3 = OpTypeVector %4 3
609 %2 = OpTypePointer Function %3
610 %5 = OpConstantNull %3
611 %8 = OpTypeVector %4 2
612 )");
613   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
614             R"(%1 = OpVariable %2 Function %5
615 )");
616   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
617             R"(%6 = OpLoad %3 %1
618 %7 = OpVectorShuffle %3 %6 %6 1 0 2
619 %9 = OpVectorShuffle %8 %7 %7 0 2
620 )");
621 }
622 
TEST_F(BuilderTest,MemberAccessor_Member_of_Swizzle)623 TEST_F(BuilderTest, MemberAccessor_Member_of_Swizzle) {
624   // ident.yxz.x
625 
626   auto* var = Var("ident", ty.vec3<f32>());
627 
628   auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "x");
629   WrapInFunction(var, expr);
630 
631   spirv::Builder& b = Build();
632 
633   b.push_function(Function{});
634   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
635 
636   EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
637 
638   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
639 %3 = OpTypeVector %4 3
640 %2 = OpTypePointer Function %3
641 %5 = OpConstantNull %3
642 )");
643   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
644             R"(%1 = OpVariable %2 Function %5
645 )");
646   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
647             R"(%6 = OpLoad %3 %1
648 %7 = OpVectorShuffle %3 %6 %6 1 0 2
649 %8 = OpCompositeExtract %4 %7 0
650 )");
651 }
652 
TEST_F(BuilderTest,MemberAccessor_Array_of_Swizzle)653 TEST_F(BuilderTest, MemberAccessor_Array_of_Swizzle) {
654   // index.yxz[1]
655 
656   auto* var = Var("ident", ty.vec3<f32>());
657 
658   auto* expr = IndexAccessor(MemberAccessor("ident", "yxz"), 1);
659   WrapInFunction(var, expr);
660 
661   spirv::Builder& b = Build();
662 
663   b.push_function(Function{});
664   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
665 
666   EXPECT_EQ(b.GenerateAccessorExpression(expr), 10u);
667 
668   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
669 %3 = OpTypeVector %4 3
670 %2 = OpTypePointer Function %3
671 %5 = OpConstantNull %3
672 %8 = OpTypeInt 32 1
673 %9 = OpConstant %8 1
674 )");
675   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
676             R"(%1 = OpVariable %2 Function %5
677 )");
678   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
679             R"(%6 = OpLoad %3 %1
680 %7 = OpVectorShuffle %3 %6 %6 1 0 2
681 %10 = OpCompositeExtract %4 %7 1
682 )");
683 }
684 
TEST_F(BuilderTest,IndexAccessor_Mixed_ArrayAndMember)685 TEST_F(BuilderTest, IndexAccessor_Mixed_ArrayAndMember) {
686   // type C = struct {
687   //   baz : vec3<f32>
688   // }
689   // type B = struct {
690   //  bar : C;
691   // }
692   // type A = struct {
693   //   foo : array<B, 3>
694   // }
695   // var index : array<A, 2>
696   // index[0].foo[2].bar.baz.yx
697 
698   auto* c_type = Structure("C", {Member("baz", ty.vec3<f32>())});
699 
700   auto* b_type = Structure("B", {Member("bar", ty.Of(c_type))});
701   auto* b_ary_type = ty.array(ty.Of(b_type), 3);
702   auto* a_type = Structure("A", {Member("foo", b_ary_type)});
703 
704   auto* a_ary_type = ty.array(ty.Of(a_type), 2);
705   auto* var = Var("index", a_ary_type);
706   auto* expr = MemberAccessor(
707       MemberAccessor(
708           MemberAccessor(
709               IndexAccessor(MemberAccessor(IndexAccessor("index", 0), "foo"),
710                             2),
711               "bar"),
712           "baz"),
713       "yx");
714   WrapInFunction(var, expr);
715 
716   spirv::Builder& b = Build();
717 
718   b.push_function(Function{});
719   ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
720 
721   EXPECT_EQ(b.GenerateAccessorExpression(expr), 22u);
722 
723   EXPECT_EQ(DumpInstructions(b.types()), R"(%9 = OpTypeFloat 32
724 %8 = OpTypeVector %9 3
725 %7 = OpTypeStruct %8
726 %6 = OpTypeStruct %7
727 %10 = OpTypeInt 32 0
728 %11 = OpConstant %10 3
729 %5 = OpTypeArray %6 %11
730 %4 = OpTypeStruct %5
731 %12 = OpConstant %10 2
732 %3 = OpTypeArray %4 %12
733 %2 = OpTypePointer Function %3
734 %13 = OpConstantNull %3
735 %14 = OpTypeInt 32 1
736 %15 = OpConstant %14 0
737 %16 = OpConstant %10 0
738 %17 = OpConstant %14 2
739 %18 = OpTypePointer Function %8
740 %20 = OpTypeVector %9 2
741 )");
742   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
743             R"(%1 = OpVariable %2 Function %13
744 )");
745   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
746             R"(%19 = OpAccessChain %18 %1 %15 %16 %17 %16 %16
747 %21 = OpLoad %8 %19
748 %22 = OpVectorShuffle %20 %21 %21 1 0
749 )");
750 }
751 
TEST_F(BuilderTest,IndexAccessor_Of_Vec)752 TEST_F(BuilderTest, IndexAccessor_Of_Vec) {
753   // let pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
754   //   vec2<f32>(0.0, 0.5),
755   //   vec2<f32>(-0.5, -0.5),
756   //   vec2<f32>(0.5, -0.5));
757   // pos[1]
758 
759   auto* var =
760       Const("pos", ty.array(ty.vec2<f32>(), 3),
761             Construct(ty.array(ty.vec2<f32>(), 3), vec2<f32>(0.0f, 0.5f),
762                       vec2<f32>(-0.5f, -0.5f), vec2<f32>(0.5f, -0.5f)));
763 
764   auto* expr = IndexAccessor("pos", 1u);
765   WrapInFunction(var, expr);
766 
767   spirv::Builder& b = SanitizeAndBuild();
768 
769   ASSERT_TRUE(b.Build());
770 
771   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
772 %1 = OpTypeFunction %2
773 %7 = OpTypeFloat 32
774 %6 = OpTypeVector %7 2
775 %8 = OpTypeInt 32 0
776 %9 = OpConstant %8 3
777 %5 = OpTypeArray %6 %9
778 %10 = OpConstant %7 0
779 %11 = OpConstant %7 0.5
780 %12 = OpConstantComposite %6 %10 %11
781 %13 = OpConstant %7 -0.5
782 %14 = OpConstantComposite %6 %13 %13
783 %15 = OpConstantComposite %6 %11 %13
784 %16 = OpConstantComposite %5 %12 %14 %15
785 %17 = OpConstant %8 1
786 )");
787   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
788   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
789             R"(%18 = OpCompositeExtract %6 %16 1
790 OpReturn
791 )");
792 
793   Validate(b);
794 }
795 
TEST_F(BuilderTest,IndexAccessor_Of_Array_Of_f32)796 TEST_F(BuilderTest, IndexAccessor_Of_Array_Of_f32) {
797   // let pos : array<array<f32, 2>, 3> = array<vec2<f32, 2>, 3>(
798   //   array<f32, 2>(0.0, 0.5),
799   //   array<f32, 2>(-0.5, -0.5),
800   //   array<f32, 2>(0.5, -0.5));
801   // pos[2][1]
802 
803   auto* var =
804       Const("pos", ty.array(ty.vec2<f32>(), 3),
805             Construct(ty.array(ty.vec2<f32>(), 3), vec2<f32>(0.0f, 0.5f),
806                       vec2<f32>(-0.5f, -0.5f), vec2<f32>(0.5f, -0.5f)));
807 
808   auto* expr = IndexAccessor(IndexAccessor("pos", 2u), 1u);
809   WrapInFunction(var, expr);
810 
811   spirv::Builder& b = SanitizeAndBuild();
812 
813   ASSERT_TRUE(b.Build());
814 
815   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
816 %1 = OpTypeFunction %2
817 %7 = OpTypeFloat 32
818 %6 = OpTypeVector %7 2
819 %8 = OpTypeInt 32 0
820 %9 = OpConstant %8 3
821 %5 = OpTypeArray %6 %9
822 %10 = OpConstant %7 0
823 %11 = OpConstant %7 0.5
824 %12 = OpConstantComposite %6 %10 %11
825 %13 = OpConstant %7 -0.5
826 %14 = OpConstantComposite %6 %13 %13
827 %15 = OpConstantComposite %6 %11 %13
828 %16 = OpConstantComposite %5 %12 %14 %15
829 %17 = OpConstant %8 2
830 %19 = OpConstant %8 1
831 )");
832   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
833   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
834             R"(%18 = OpCompositeExtract %6 %16 2
835 %20 = OpCompositeExtract %7 %18 1
836 OpReturn
837 )");
838 
839   Validate(b);
840 }
841 
TEST_F(BuilderTest,IndexAccessor_Vec_Literal)842 TEST_F(BuilderTest, IndexAccessor_Vec_Literal) {
843   // let pos : vec2<f32> = vec2<f32>(0.0, 0.5);
844   // pos[1]
845 
846   auto* var = Const("pos", ty.vec2<f32>(), vec2<f32>(0.0f, 0.5f));
847 
848   auto* expr = IndexAccessor("pos", 1u);
849   WrapInFunction(var, expr);
850 
851   spirv::Builder& b = Build();
852 
853   b.push_function(Function{});
854   ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
855   EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u) << b.error();
856 
857   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
858 %1 = OpTypeVector %2 2
859 %3 = OpConstant %2 0
860 %4 = OpConstant %2 0.5
861 %5 = OpConstantComposite %1 %3 %4
862 %6 = OpTypeInt 32 0
863 %7 = OpConstant %6 1
864 )");
865   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), "");
866   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
867             R"(%8 = OpCompositeExtract %2 %5 1
868 )");
869 }
870 
TEST_F(BuilderTest,IndexAccessor_Vec_Dynamic)871 TEST_F(BuilderTest, IndexAccessor_Vec_Dynamic) {
872   // let pos : vec2<f32> = vec2<f32>(0.0, 0.5);
873   // idx : i32
874   // pos[idx]
875 
876   auto* var = Const("pos", ty.vec2<f32>(), vec2<f32>(0.0f, 0.5f));
877   auto* idx = Var("idx", ty.i32());
878   auto* expr = IndexAccessor("pos", idx);
879 
880   WrapInFunction(var, idx, expr);
881 
882   spirv::Builder& b = Build();
883 
884   b.push_function(Function{});
885   ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
886   ASSERT_TRUE(b.GenerateFunctionVariable(idx)) << b.error();
887   EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u) << b.error();
888 
889   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
890 %1 = OpTypeVector %2 2
891 %3 = OpConstant %2 0
892 %4 = OpConstant %2 0.5
893 %5 = OpConstantComposite %1 %3 %4
894 %8 = OpTypeInt 32 1
895 %7 = OpTypePointer Function %8
896 %9 = OpConstantNull %8
897 )");
898   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
899             R"(%6 = OpVariable %7 Function %9
900 )");
901   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
902             R"(%10 = OpLoad %8 %6
903 %11 = OpVectorExtractDynamic %2 %5 %10
904 )");
905 }
906 
TEST_F(BuilderTest,IndexAccessor_Array_Literal)907 TEST_F(BuilderTest, IndexAccessor_Array_Literal) {
908   // let a : array<f32, 3>;
909   // a[2]
910 
911   auto* var = Const("a", ty.array<f32, 3>(),
912                     Construct(ty.array<f32, 3>(), 0.0f, 0.5f, 1.0f));
913   auto* expr = IndexAccessor("a", 2);
914   WrapInFunction(var, expr);
915 
916   spirv::Builder& b = SanitizeAndBuild();
917 
918   ASSERT_TRUE(b.Build());
919 
920   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
921 %1 = OpTypeFunction %2
922 %6 = OpTypeFloat 32
923 %7 = OpTypeInt 32 0
924 %8 = OpConstant %7 3
925 %5 = OpTypeArray %6 %8
926 %9 = OpConstant %6 0
927 %10 = OpConstant %6 0.5
928 %11 = OpConstant %6 1
929 %12 = OpConstantComposite %5 %9 %10 %11
930 %13 = OpTypeInt 32 1
931 %14 = OpConstant %13 2
932 )");
933   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), "");
934   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
935             R"(%15 = OpCompositeExtract %6 %12 2
936 OpReturn
937 )");
938 
939   Validate(b);
940 }
941 
TEST_F(BuilderTest,IndexAccessor_Array_Dynamic)942 TEST_F(BuilderTest, IndexAccessor_Array_Dynamic) {
943   // var a : array<f32, 3>;
944   // idx : i32
945   // a[idx]
946 
947   auto* var = Var("a", ty.array<f32, 3>(),
948                   Construct(ty.array<f32, 3>(), 0.0f, 0.5f, 1.0f));
949 
950   auto* idx = Var("idx", ty.i32());
951   auto* expr = IndexAccessor("a", idx);
952 
953   WrapInFunction(var, idx, expr);
954 
955   spirv::Builder& b = SanitizeAndBuild();
956 
957   ASSERT_TRUE(b.Build());
958 
959   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
960 %1 = OpTypeFunction %2
961 %6 = OpTypeFloat 32
962 %7 = OpTypeInt 32 0
963 %8 = OpConstant %7 3
964 %5 = OpTypeArray %6 %8
965 %9 = OpConstant %6 0
966 %10 = OpConstant %6 0.5
967 %11 = OpConstant %6 1
968 %12 = OpConstantComposite %5 %9 %10 %11
969 %14 = OpTypePointer Function %5
970 %15 = OpConstantNull %5
971 %18 = OpTypeInt 32 1
972 %17 = OpTypePointer Function %18
973 %19 = OpConstantNull %18
974 %21 = OpTypePointer Function %6
975 )");
976   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
977             R"(%13 = OpVariable %14 Function %15
978 %16 = OpVariable %17 Function %19
979 )");
980   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
981             R"(OpStore %13 %12
982 %20 = OpLoad %18 %16
983 %22 = OpAccessChain %21 %13 %20
984 %23 = OpLoad %6 %22
985 OpReturn
986 )");
987 
988   Validate(b);
989 }
990 
TEST_F(BuilderTest,IndexAccessor_Matrix_Dynamic)991 TEST_F(BuilderTest, IndexAccessor_Matrix_Dynamic) {
992   // var a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
993   // idx : i32
994   // a[idx]
995 
996   auto* var =
997       Var("a", ty.mat2x2<f32>(),
998           Construct(ty.mat2x2<f32>(), Construct(ty.vec2<f32>(), 1.f, 2.f),
999                     Construct(ty.vec2<f32>(), 3.f, 4.f)));
1000 
1001   auto* idx = Var("idx", ty.i32());
1002   auto* expr = IndexAccessor("a", idx);
1003 
1004   WrapInFunction(var, idx, expr);
1005 
1006   spirv::Builder& b = SanitizeAndBuild();
1007 
1008   ASSERT_TRUE(b.Build());
1009 
1010   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
1011 %1 = OpTypeFunction %2
1012 %7 = OpTypeFloat 32
1013 %6 = OpTypeVector %7 2
1014 %5 = OpTypeMatrix %6 2
1015 %8 = OpConstant %7 1
1016 %9 = OpConstant %7 2
1017 %10 = OpConstantComposite %6 %8 %9
1018 %11 = OpConstant %7 3
1019 %12 = OpConstant %7 4
1020 %13 = OpConstantComposite %6 %11 %12
1021 %14 = OpConstantComposite %5 %10 %13
1022 %16 = OpTypePointer Function %5
1023 %17 = OpConstantNull %5
1024 %20 = OpTypeInt 32 1
1025 %19 = OpTypePointer Function %20
1026 %21 = OpConstantNull %20
1027 %23 = OpTypePointer Function %6
1028 )");
1029   EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
1030             R"(%15 = OpVariable %16 Function %17
1031 %18 = OpVariable %19 Function %21
1032 )");
1033   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
1034             R"(OpStore %15 %14
1035 %22 = OpLoad %20 %18
1036 %24 = OpAccessChain %23 %15 %22
1037 %25 = OpLoad %6 %24
1038 OpReturn
1039 )");
1040 
1041   Validate(b);
1042 }
1043 
1044 }  // namespace
1045 }  // namespace spirv
1046 }  // namespace writer
1047 }  // namespace tint
1048