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