• 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/ast/struct_block_decoration.h"
16 #include "src/sem/depth_texture_type.h"
17 #include "src/sem/multisampled_texture_type.h"
18 #include "src/sem/sampled_texture_type.h"
19 #include "src/writer/spirv/spv_dump.h"
20 #include "src/writer/spirv/test_helper.h"
21 
22 namespace tint {
23 namespace writer {
24 namespace spirv {
25 namespace {
26 
27 using BuilderTest_Type = TestHelper;
28 
TEST_F(BuilderTest_Type,GenerateRuntimeArray)29 TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
30   auto* ary = ty.array(ty.i32());
31   auto* str = Structure("S", {Member("x", ary)},
32                         {create<ast::StructBlockDecoration>()});
33   Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
34          ast::DecorationList{
35              create<ast::BindingDecoration>(0),
36              create<ast::GroupDecoration>(0),
37          });
38 
39   spirv::Builder& b = Build();
40 
41   auto id = b.GenerateTypeIfNeeded(program->TypeOf(ary));
42   ASSERT_FALSE(b.has_error()) << b.error();
43   EXPECT_EQ(1u, id);
44 
45   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
46 %1 = OpTypeRuntimeArray %2
47 )");
48 }
49 
TEST_F(BuilderTest_Type,ReturnsGeneratedRuntimeArray)50 TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
51   auto* ary = ty.array(ty.i32());
52   auto* str = Structure("S", {Member("x", ary)},
53                         {create<ast::StructBlockDecoration>()});
54   Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
55          ast::DecorationList{
56              create<ast::BindingDecoration>(0),
57              create<ast::GroupDecoration>(0),
58          });
59 
60   spirv::Builder& b = Build();
61 
62   EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
63   EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
64   ASSERT_FALSE(b.has_error()) << b.error();
65 
66   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
67 %1 = OpTypeRuntimeArray %2
68 )");
69 }
70 
TEST_F(BuilderTest_Type,GenerateArray)71 TEST_F(BuilderTest_Type, GenerateArray) {
72   auto* ary = ty.array(ty.i32(), 4);
73   Global("a", ary, ast::StorageClass::kPrivate);
74 
75   spirv::Builder& b = Build();
76 
77   auto id = b.GenerateTypeIfNeeded(program->TypeOf(ary));
78   ASSERT_FALSE(b.has_error()) << b.error();
79   EXPECT_EQ(1u, id);
80 
81   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
82 %3 = OpTypeInt 32 0
83 %4 = OpConstant %3 4
84 %1 = OpTypeArray %2 %4
85 )");
86 }
87 
TEST_F(BuilderTest_Type,GenerateArray_WithStride)88 TEST_F(BuilderTest_Type, GenerateArray_WithStride) {
89   auto* ary = ty.array(ty.i32(), 4, 16u);
90   Global("a", ary, ast::StorageClass::kPrivate);
91 
92   spirv::Builder& b = Build();
93 
94   auto id = b.GenerateTypeIfNeeded(program->TypeOf(ary));
95   ASSERT_FALSE(b.has_error()) << b.error();
96   EXPECT_EQ(1u, id);
97 
98   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 ArrayStride 16
99 )");
100 
101   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
102 %3 = OpTypeInt 32 0
103 %4 = OpConstant %3 4
104 %1 = OpTypeArray %2 %4
105 )");
106 }
107 
TEST_F(BuilderTest_Type,ReturnsGeneratedArray)108 TEST_F(BuilderTest_Type, ReturnsGeneratedArray) {
109   auto* ary = ty.array(ty.i32(), 4);
110   Global("a", ary, ast::StorageClass::kPrivate);
111 
112   spirv::Builder& b = Build();
113 
114   EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
115   EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
116   ASSERT_FALSE(b.has_error()) << b.error();
117 
118   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
119 %3 = OpTypeInt 32 0
120 %4 = OpConstant %3 4
121 %1 = OpTypeArray %2 %4
122 )");
123 }
124 
TEST_F(BuilderTest_Type,GenerateBool)125 TEST_F(BuilderTest_Type, GenerateBool) {
126   auto* bool_ = create<sem::Bool>();
127 
128   spirv::Builder& b = Build();
129 
130   auto id = b.GenerateTypeIfNeeded(bool_);
131   ASSERT_FALSE(b.has_error()) << b.error();
132   EXPECT_EQ(id, 1u);
133 
134   ASSERT_EQ(b.types().size(), 1u);
135   EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeBool
136 )");
137 }
138 
TEST_F(BuilderTest_Type,ReturnsGeneratedBool)139 TEST_F(BuilderTest_Type, ReturnsGeneratedBool) {
140   auto* bool_ = create<sem::Bool>();
141   auto* i32 = create<sem::I32>();
142 
143   spirv::Builder& b = Build();
144 
145   EXPECT_EQ(b.GenerateTypeIfNeeded(bool_), 1u);
146   ASSERT_FALSE(b.has_error()) << b.error();
147   EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
148   ASSERT_FALSE(b.has_error()) << b.error();
149   EXPECT_EQ(b.GenerateTypeIfNeeded(bool_), 1u);
150   ASSERT_FALSE(b.has_error()) << b.error();
151 }
152 
TEST_F(BuilderTest_Type,GenerateF32)153 TEST_F(BuilderTest_Type, GenerateF32) {
154   auto* f32 = create<sem::F32>();
155 
156   spirv::Builder& b = Build();
157 
158   auto id = b.GenerateTypeIfNeeded(f32);
159   ASSERT_FALSE(b.has_error()) << b.error();
160   EXPECT_EQ(id, 1u);
161 
162   ASSERT_EQ(b.types().size(), 1u);
163   EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeFloat 32
164 )");
165 }
166 
TEST_F(BuilderTest_Type,ReturnsGeneratedF32)167 TEST_F(BuilderTest_Type, ReturnsGeneratedF32) {
168   auto* f32 = create<sem::F32>();
169   auto* i32 = create<sem::I32>();
170 
171   spirv::Builder& b = Build();
172 
173   EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 1u);
174   ASSERT_FALSE(b.has_error()) << b.error();
175   EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
176   ASSERT_FALSE(b.has_error()) << b.error();
177   EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 1u);
178   ASSERT_FALSE(b.has_error()) << b.error();
179 }
180 
TEST_F(BuilderTest_Type,GenerateI32)181 TEST_F(BuilderTest_Type, GenerateI32) {
182   auto* i32 = create<sem::I32>();
183 
184   spirv::Builder& b = Build();
185 
186   auto id = b.GenerateTypeIfNeeded(i32);
187   ASSERT_FALSE(b.has_error()) << b.error();
188   EXPECT_EQ(id, 1u);
189 
190   ASSERT_EQ(b.types().size(), 1u);
191   EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeInt 32 1
192 )");
193 }
194 
TEST_F(BuilderTest_Type,ReturnsGeneratedI32)195 TEST_F(BuilderTest_Type, ReturnsGeneratedI32) {
196   auto* f32 = create<sem::F32>();
197   auto* i32 = create<sem::I32>();
198 
199   spirv::Builder& b = Build();
200 
201   EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 1u);
202   ASSERT_FALSE(b.has_error()) << b.error();
203   EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 2u);
204   ASSERT_FALSE(b.has_error()) << b.error();
205   EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 1u);
206   ASSERT_FALSE(b.has_error()) << b.error();
207 }
208 
TEST_F(BuilderTest_Type,GenerateMatrix)209 TEST_F(BuilderTest_Type, GenerateMatrix) {
210   auto* f32 = create<sem::F32>();
211   auto* vec3 = create<sem::Vector>(f32, 3);
212   auto* mat2x3 = create<sem::Matrix>(vec3, 2);
213 
214   spirv::Builder& b = Build();
215 
216   auto id = b.GenerateTypeIfNeeded(mat2x3);
217   ASSERT_FALSE(b.has_error()) << b.error();
218   EXPECT_EQ(id, 1u);
219 
220   EXPECT_EQ(b.types().size(), 3u);
221   EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
222 %2 = OpTypeVector %3 3
223 %1 = OpTypeMatrix %2 2
224 )");
225 }
226 
TEST_F(BuilderTest_Type,ReturnsGeneratedMatrix)227 TEST_F(BuilderTest_Type, ReturnsGeneratedMatrix) {
228   auto* i32 = create<sem::I32>();
229   auto* col = create<sem::Vector>(i32, 4);
230   auto* mat = create<sem::Matrix>(col, 3);
231 
232   spirv::Builder& b = Build();
233 
234   EXPECT_EQ(b.GenerateTypeIfNeeded(mat), 1u);
235   ASSERT_FALSE(b.has_error()) << b.error();
236   EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 3u);
237   ASSERT_FALSE(b.has_error()) << b.error();
238   EXPECT_EQ(b.GenerateTypeIfNeeded(mat), 1u);
239   ASSERT_FALSE(b.has_error()) << b.error();
240 }
241 
TEST_F(BuilderTest_Type,GeneratePtr)242 TEST_F(BuilderTest_Type, GeneratePtr) {
243   auto* i32 = create<sem::I32>();
244   auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOutput,
245                                    ast::Access::kReadWrite);
246 
247   spirv::Builder& b = Build();
248 
249   auto id = b.GenerateTypeIfNeeded(ptr);
250   ASSERT_FALSE(b.has_error()) << b.error();
251   EXPECT_EQ(1u, id);
252 
253   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
254 %1 = OpTypePointer Output %2
255 )");
256 }
257 
TEST_F(BuilderTest_Type,ReturnsGeneratedPtr)258 TEST_F(BuilderTest_Type, ReturnsGeneratedPtr) {
259   auto* i32 = create<sem::I32>();
260   auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOutput,
261                                    ast::Access::kReadWrite);
262 
263   spirv::Builder& b = Build();
264 
265   EXPECT_EQ(b.GenerateTypeIfNeeded(ptr), 1u);
266   EXPECT_EQ(b.GenerateTypeIfNeeded(ptr), 1u);
267 }
268 
TEST_F(BuilderTest_Type,GenerateStruct)269 TEST_F(BuilderTest_Type, GenerateStruct) {
270   auto* s = Structure("my_struct", {Member("a", ty.f32())});
271 
272   spirv::Builder& b = Build();
273 
274   auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
275   ASSERT_FALSE(b.has_error()) << b.error();
276   EXPECT_EQ(id, 1u);
277 
278   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
279 %1 = OpTypeStruct %2
280 )");
281   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "my_struct"
282 OpMemberName %1 0 "a"
283 )");
284 }
285 
TEST_F(BuilderTest_Type,GenerateStruct_Decorated)286 TEST_F(BuilderTest_Type, GenerateStruct_Decorated) {
287   auto* s = Structure("my_struct", {Member("a", ty.f32())},
288                       {create<ast::StructBlockDecoration>()});
289 
290   spirv::Builder& b = Build();
291 
292   auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
293   ASSERT_FALSE(b.has_error()) << b.error();
294   EXPECT_EQ(id, 1u);
295 
296   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
297 %1 = OpTypeStruct %2
298 )");
299   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "my_struct"
300 OpMemberName %1 0 "a"
301 )");
302   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 Block
303 OpMemberDecorate %1 0 Offset 0
304 )");
305 }
306 
TEST_F(BuilderTest_Type,GenerateStruct_DecoratedMembers)307 TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) {
308   auto* s = Structure("S", {
309                                Member("a", ty.f32()),
310                                Member("b", ty.f32(), {MemberAlign(8)}),
311                            });
312 
313   spirv::Builder& b = Build();
314 
315   auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
316   ASSERT_FALSE(b.has_error()) << b.error();
317   EXPECT_EQ(id, 1u);
318 
319   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
320 %1 = OpTypeStruct %2 %2
321 )");
322   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
323 OpMemberName %1 0 "a"
324 OpMemberName %1 1 "b"
325 )");
326   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0
327 OpMemberDecorate %1 1 Offset 8
328 )");
329 }
330 
TEST_F(BuilderTest_Type,GenerateStruct_NonLayout_Matrix)331 TEST_F(BuilderTest_Type, GenerateStruct_NonLayout_Matrix) {
332   auto* s = Structure("S", {
333                                Member("a", ty.mat2x2<f32>()),
334                                Member("b", ty.mat2x3<f32>()),
335                                Member("c", ty.mat4x4<f32>()),
336                            });
337 
338   spirv::Builder& b = Build();
339 
340   auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
341   ASSERT_FALSE(b.has_error()) << b.error();
342   EXPECT_EQ(id, 1u);
343 
344   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
345 %3 = OpTypeVector %4 2
346 %2 = OpTypeMatrix %3 2
347 %6 = OpTypeVector %4 3
348 %5 = OpTypeMatrix %6 2
349 %8 = OpTypeVector %4 4
350 %7 = OpTypeMatrix %8 4
351 %1 = OpTypeStruct %2 %5 %7
352 )");
353   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
354 OpMemberName %1 0 "a"
355 OpMemberName %1 1 "b"
356 OpMemberName %1 2 "c"
357 )");
358   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0
359 OpMemberDecorate %1 0 ColMajor
360 OpMemberDecorate %1 0 MatrixStride 8
361 OpMemberDecorate %1 1 Offset 16
362 OpMemberDecorate %1 1 ColMajor
363 OpMemberDecorate %1 1 MatrixStride 16
364 OpMemberDecorate %1 2 Offset 48
365 OpMemberDecorate %1 2 ColMajor
366 OpMemberDecorate %1 2 MatrixStride 16
367 )");
368 }
369 
TEST_F(BuilderTest_Type,GenerateStruct_DecoratedMembers_LayoutMatrix)370 TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutMatrix) {
371   // We have to infer layout for matrix when it also has an offset.
372   auto* s = Structure("S", {
373                                Member("a", ty.mat2x2<f32>()),
374                                Member("b", ty.mat2x3<f32>()),
375                                Member("c", ty.mat4x4<f32>()),
376                            });
377 
378   spirv::Builder& b = Build();
379 
380   auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
381   ASSERT_FALSE(b.has_error()) << b.error();
382   EXPECT_EQ(id, 1u);
383 
384   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
385 %3 = OpTypeVector %4 2
386 %2 = OpTypeMatrix %3 2
387 %6 = OpTypeVector %4 3
388 %5 = OpTypeMatrix %6 2
389 %8 = OpTypeVector %4 4
390 %7 = OpTypeMatrix %8 4
391 %1 = OpTypeStruct %2 %5 %7
392 )");
393   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
394 OpMemberName %1 0 "a"
395 OpMemberName %1 1 "b"
396 OpMemberName %1 2 "c"
397 )");
398   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0
399 OpMemberDecorate %1 0 ColMajor
400 OpMemberDecorate %1 0 MatrixStride 8
401 OpMemberDecorate %1 1 Offset 16
402 OpMemberDecorate %1 1 ColMajor
403 OpMemberDecorate %1 1 MatrixStride 16
404 OpMemberDecorate %1 2 Offset 48
405 OpMemberDecorate %1 2 ColMajor
406 OpMemberDecorate %1 2 MatrixStride 16
407 )");
408 }
409 
TEST_F(BuilderTest_Type,GenerateStruct_DecoratedMembers_LayoutArraysOfMatrix)410 TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutArraysOfMatrix) {
411   // We have to infer layout for matrix when it also has an offset.
412   // The decoration goes on the struct member, even if the matrix is buried
413   // in levels of arrays.
414   auto* arr_mat2x2 = ty.array(ty.mat2x2<f32>(), 1);      // Singly nested array
415   auto* arr_arr_mat2x3 = ty.array(ty.mat2x3<f32>(), 1);  // Doubly nested array
416   auto* rtarr_mat4x4 = ty.array(ty.mat4x4<f32>());       // Runtime array
417 
418   auto* s =
419       Structure("S",
420                 {
421                     Member("a", arr_mat2x2),
422                     Member("b", arr_arr_mat2x3),
423                     Member("c", rtarr_mat4x4),
424                 },
425                 ast::DecorationList{create<ast::StructBlockDecoration>()});
426 
427   spirv::Builder& b = Build();
428 
429   auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
430   ASSERT_FALSE(b.has_error()) << b.error();
431   EXPECT_EQ(id, 1u);
432 
433   EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
434 %4 = OpTypeVector %5 2
435 %3 = OpTypeMatrix %4 2
436 %6 = OpTypeInt 32 0
437 %7 = OpConstant %6 1
438 %2 = OpTypeArray %3 %7
439 %10 = OpTypeVector %5 3
440 %9 = OpTypeMatrix %10 2
441 %8 = OpTypeArray %9 %7
442 %13 = OpTypeVector %5 4
443 %12 = OpTypeMatrix %13 4
444 %11 = OpTypeRuntimeArray %12
445 %1 = OpTypeStruct %2 %8 %11
446 )");
447   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
448 OpMemberName %1 0 "a"
449 OpMemberName %1 1 "b"
450 OpMemberName %1 2 "c"
451 )");
452   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 Block
453 OpMemberDecorate %1 0 Offset 0
454 OpMemberDecorate %1 0 ColMajor
455 OpMemberDecorate %1 0 MatrixStride 8
456 OpDecorate %2 ArrayStride 16
457 OpMemberDecorate %1 1 Offset 16
458 OpMemberDecorate %1 1 ColMajor
459 OpMemberDecorate %1 1 MatrixStride 16
460 OpDecorate %8 ArrayStride 32
461 OpMemberDecorate %1 2 Offset 48
462 OpMemberDecorate %1 2 ColMajor
463 OpMemberDecorate %1 2 MatrixStride 16
464 OpDecorate %11 ArrayStride 64
465 )");
466 }
467 
TEST_F(BuilderTest_Type,GenerateU32)468 TEST_F(BuilderTest_Type, GenerateU32) {
469   auto* u32 = create<sem::U32>();
470 
471   spirv::Builder& b = Build();
472 
473   auto id = b.GenerateTypeIfNeeded(u32);
474   ASSERT_FALSE(b.has_error()) << b.error();
475   EXPECT_EQ(id, 1u);
476 
477   ASSERT_EQ(b.types().size(), 1u);
478   EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeInt 32 0
479 )");
480 }
481 
TEST_F(BuilderTest_Type,ReturnsGeneratedU32)482 TEST_F(BuilderTest_Type, ReturnsGeneratedU32) {
483   auto* u32 = create<sem::U32>();
484   auto* f32 = create<sem::F32>();
485 
486   spirv::Builder& b = Build();
487 
488   EXPECT_EQ(b.GenerateTypeIfNeeded(u32), 1u);
489   ASSERT_FALSE(b.has_error()) << b.error();
490   EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 2u);
491   ASSERT_FALSE(b.has_error()) << b.error();
492   EXPECT_EQ(b.GenerateTypeIfNeeded(u32), 1u);
493   ASSERT_FALSE(b.has_error()) << b.error();
494 }
495 
TEST_F(BuilderTest_Type,GenerateVector)496 TEST_F(BuilderTest_Type, GenerateVector) {
497   auto* vec = create<sem::Vector>(create<sem::F32>(), 3);
498 
499   spirv::Builder& b = Build();
500 
501   auto id = b.GenerateTypeIfNeeded(vec);
502   ASSERT_FALSE(b.has_error()) << b.error();
503   EXPECT_EQ(id, 1u);
504 
505   EXPECT_EQ(b.types().size(), 2u);
506   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
507 %1 = OpTypeVector %2 3
508 )");
509 }
510 
TEST_F(BuilderTest_Type,ReturnsGeneratedVector)511 TEST_F(BuilderTest_Type, ReturnsGeneratedVector) {
512   auto* i32 = create<sem::I32>();
513   auto* vec = create<sem::Vector>(i32, 3);
514 
515   spirv::Builder& b = Build();
516 
517   EXPECT_EQ(b.GenerateTypeIfNeeded(vec), 1u);
518   ASSERT_FALSE(b.has_error()) << b.error();
519   EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
520   ASSERT_FALSE(b.has_error()) << b.error();
521   EXPECT_EQ(b.GenerateTypeIfNeeded(vec), 1u);
522   ASSERT_FALSE(b.has_error()) << b.error();
523 }
524 
TEST_F(BuilderTest_Type,GenerateVoid)525 TEST_F(BuilderTest_Type, GenerateVoid) {
526   auto* void_ = create<sem::Void>();
527 
528   spirv::Builder& b = Build();
529 
530   auto id = b.GenerateTypeIfNeeded(void_);
531   ASSERT_FALSE(b.has_error()) << b.error();
532   EXPECT_EQ(id, 1u);
533 
534   ASSERT_EQ(b.types().size(), 1u);
535   EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeVoid
536 )");
537 }
538 
TEST_F(BuilderTest_Type,ReturnsGeneratedVoid)539 TEST_F(BuilderTest_Type, ReturnsGeneratedVoid) {
540   auto* void_ = create<sem::Void>();
541   auto* i32 = create<sem::I32>();
542 
543   spirv::Builder& b = Build();
544 
545   EXPECT_EQ(b.GenerateTypeIfNeeded(void_), 1u);
546   ASSERT_FALSE(b.has_error()) << b.error();
547   EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
548   ASSERT_FALSE(b.has_error()) << b.error();
549   EXPECT_EQ(b.GenerateTypeIfNeeded(void_), 1u);
550   ASSERT_FALSE(b.has_error()) << b.error();
551 }
552 
553 struct PtrData {
554   ast::StorageClass ast_class;
555   SpvStorageClass result;
556 };
operator <<(std::ostream & out,PtrData data)557 inline std::ostream& operator<<(std::ostream& out, PtrData data) {
558   out << data.ast_class;
559   return out;
560 }
561 using PtrDataTest = TestParamHelper<PtrData>;
TEST_P(PtrDataTest,ConvertStorageClass)562 TEST_P(PtrDataTest, ConvertStorageClass) {
563   auto params = GetParam();
564 
565   spirv::Builder& b = Build();
566 
567   EXPECT_EQ(b.ConvertStorageClass(params.ast_class), params.result);
568 }
569 INSTANTIATE_TEST_SUITE_P(
570     BuilderTest_Type,
571     PtrDataTest,
572     testing::Values(
573         PtrData{ast::StorageClass::kNone, SpvStorageClassMax},
574         PtrData{ast::StorageClass::kInput, SpvStorageClassInput},
575         PtrData{ast::StorageClass::kOutput, SpvStorageClassOutput},
576         PtrData{ast::StorageClass::kUniform, SpvStorageClassUniform},
577         PtrData{ast::StorageClass::kWorkgroup, SpvStorageClassWorkgroup},
578         PtrData{ast::StorageClass::kUniformConstant,
579                 SpvStorageClassUniformConstant},
580         PtrData{ast::StorageClass::kStorage, SpvStorageClassStorageBuffer},
581         PtrData{ast::StorageClass::kImage, SpvStorageClassImage},
582         PtrData{ast::StorageClass::kPrivate, SpvStorageClassPrivate},
583         PtrData{ast::StorageClass::kFunction, SpvStorageClassFunction}));
584 
TEST_F(BuilderTest_Type,DepthTexture_Generate_2d)585 TEST_F(BuilderTest_Type, DepthTexture_Generate_2d) {
586   auto* two_d = create<sem::DepthTexture>(ast::TextureDimension::k2d);
587 
588   spirv::Builder& b = Build();
589 
590   auto id_two_d = b.GenerateTypeIfNeeded(two_d);
591   ASSERT_FALSE(b.has_error()) << b.error();
592   EXPECT_EQ(1u, id_two_d);
593 
594   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
595 %1 = OpTypeImage %2 2D 1 0 0 1 Unknown
596 )");
597 }
598 
TEST_F(BuilderTest_Type,DepthTexture_Generate_2dArray)599 TEST_F(BuilderTest_Type, DepthTexture_Generate_2dArray) {
600   auto* two_d_array =
601       create<sem::DepthTexture>(ast::TextureDimension::k2dArray);
602 
603   spirv::Builder& b = Build();
604 
605   auto id_two_d_array = b.GenerateTypeIfNeeded(two_d_array);
606   ASSERT_FALSE(b.has_error()) << b.error();
607   EXPECT_EQ(1u, id_two_d_array);
608 
609   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
610 %1 = OpTypeImage %2 2D 1 1 0 1 Unknown
611 )");
612 }
613 
TEST_F(BuilderTest_Type,DepthTexture_Generate_Cube)614 TEST_F(BuilderTest_Type, DepthTexture_Generate_Cube) {
615   auto* cube = create<sem::DepthTexture>(ast::TextureDimension::kCube);
616 
617   spirv::Builder& b = Build();
618 
619   auto id_cube = b.GenerateTypeIfNeeded(cube);
620   ASSERT_FALSE(b.has_error()) << b.error();
621   EXPECT_EQ(1u, id_cube);
622 
623   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
624 %1 = OpTypeImage %2 Cube 1 0 0 1 Unknown
625 )");
626   EXPECT_EQ(DumpInstructions(b.capabilities()), "");
627 }
628 
TEST_F(BuilderTest_Type,DepthTexture_Generate_CubeArray)629 TEST_F(BuilderTest_Type, DepthTexture_Generate_CubeArray) {
630   auto* cube_array =
631       create<sem::DepthTexture>(ast::TextureDimension::kCubeArray);
632 
633   spirv::Builder& b = Build();
634 
635   auto id_cube_array = b.GenerateTypeIfNeeded(cube_array);
636   ASSERT_FALSE(b.has_error()) << b.error();
637   EXPECT_EQ(1u, id_cube_array);
638 
639   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
640 %1 = OpTypeImage %2 Cube 1 1 0 1 Unknown
641 )");
642   EXPECT_EQ(DumpInstructions(b.capabilities()),
643             R"(OpCapability SampledCubeArray
644 )");
645 }
646 
TEST_F(BuilderTest_Type,MultisampledTexture_Generate_2d_i32)647 TEST_F(BuilderTest_Type, MultisampledTexture_Generate_2d_i32) {
648   auto* i32 = create<sem::I32>();
649   auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, i32);
650 
651   spirv::Builder& b = Build();
652 
653   EXPECT_EQ(1u, b.GenerateTypeIfNeeded(ms));
654   ASSERT_FALSE(b.has_error()) << b.error();
655   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
656 %1 = OpTypeImage %2 2D 0 0 1 1 Unknown
657 )");
658 }
659 
TEST_F(BuilderTest_Type,MultisampledTexture_Generate_2d_u32)660 TEST_F(BuilderTest_Type, MultisampledTexture_Generate_2d_u32) {
661   auto* u32 = create<sem::U32>();
662   auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, u32);
663 
664   spirv::Builder& b = Build();
665 
666   EXPECT_EQ(b.GenerateTypeIfNeeded(ms), 1u);
667   ASSERT_FALSE(b.has_error()) << b.error();
668   EXPECT_EQ(DumpInstructions(b.types()),
669             R"(%2 = OpTypeInt 32 0
670 %1 = OpTypeImage %2 2D 0 0 1 1 Unknown
671 )");
672 }
673 
TEST_F(BuilderTest_Type,MultisampledTexture_Generate_2d_f32)674 TEST_F(BuilderTest_Type, MultisampledTexture_Generate_2d_f32) {
675   auto* f32 = create<sem::F32>();
676   auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
677 
678   spirv::Builder& b = Build();
679 
680   EXPECT_EQ(b.GenerateTypeIfNeeded(ms), 1u);
681   ASSERT_FALSE(b.has_error()) << b.error();
682   EXPECT_EQ(DumpInstructions(b.types()),
683             R"(%2 = OpTypeFloat 32
684 %1 = OpTypeImage %2 2D 0 0 1 1 Unknown
685 )");
686 }
687 
TEST_F(BuilderTest_Type,SampledTexture_Generate_1d_i32)688 TEST_F(BuilderTest_Type, SampledTexture_Generate_1d_i32) {
689   auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d,
690                                         create<sem::I32>());
691 
692   spirv::Builder& b = Build();
693 
694   EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
695   ASSERT_FALSE(b.has_error()) << b.error();
696   EXPECT_EQ(DumpInstructions(b.types()),
697             R"(%2 = OpTypeInt 32 1
698 %1 = OpTypeImage %2 1D 0 0 0 1 Unknown
699 )");
700 
701   EXPECT_EQ(DumpInstructions(b.capabilities()),
702             R"(OpCapability Sampled1D
703 )");
704 }
705 
TEST_F(BuilderTest_Type,SampledTexture_Generate_1d_u32)706 TEST_F(BuilderTest_Type, SampledTexture_Generate_1d_u32) {
707   auto* u32 = create<sem::U32>();
708   auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d, u32);
709 
710   spirv::Builder& b = Build();
711 
712   EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
713   ASSERT_FALSE(b.has_error()) << b.error();
714   EXPECT_EQ(DumpInstructions(b.types()),
715             R"(%2 = OpTypeInt 32 0
716 %1 = OpTypeImage %2 1D 0 0 0 1 Unknown
717 )");
718 
719   EXPECT_EQ(DumpInstructions(b.capabilities()),
720             R"(OpCapability Sampled1D
721 )");
722 }
723 
TEST_F(BuilderTest_Type,SampledTexture_Generate_1d_f32)724 TEST_F(BuilderTest_Type, SampledTexture_Generate_1d_f32) {
725   auto* f32 = create<sem::F32>();
726   auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
727 
728   spirv::Builder& b = Build();
729 
730   EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
731   ASSERT_FALSE(b.has_error()) << b.error();
732   EXPECT_EQ(DumpInstructions(b.types()),
733             R"(%2 = OpTypeFloat 32
734 %1 = OpTypeImage %2 1D 0 0 0 1 Unknown
735 )");
736 
737   EXPECT_EQ(DumpInstructions(b.capabilities()),
738             R"(OpCapability Sampled1D
739 )");
740 }
741 
TEST_F(BuilderTest_Type,SampledTexture_Generate_2d)742 TEST_F(BuilderTest_Type, SampledTexture_Generate_2d) {
743   auto* f32 = create<sem::F32>();
744   auto* s = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
745 
746   spirv::Builder& b = Build();
747 
748   EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
749   ASSERT_FALSE(b.has_error()) << b.error();
750   EXPECT_EQ(DumpInstructions(b.types()),
751             R"(%2 = OpTypeFloat 32
752 %1 = OpTypeImage %2 2D 0 0 0 1 Unknown
753 )");
754 }
755 
TEST_F(BuilderTest_Type,SampledTexture_Generate_2d_array)756 TEST_F(BuilderTest_Type, SampledTexture_Generate_2d_array) {
757   auto* f32 = create<sem::F32>();
758   auto* s = create<sem::SampledTexture>(ast::TextureDimension::k2dArray, f32);
759 
760   spirv::Builder& b = Build();
761 
762   EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
763   ASSERT_FALSE(b.has_error()) << b.error();
764   EXPECT_EQ(DumpInstructions(b.types()),
765             R"(%2 = OpTypeFloat 32
766 %1 = OpTypeImage %2 2D 0 1 0 1 Unknown
767 )");
768 }
769 
TEST_F(BuilderTest_Type,SampledTexture_Generate_3d)770 TEST_F(BuilderTest_Type, SampledTexture_Generate_3d) {
771   auto* f32 = create<sem::F32>();
772   auto* s = create<sem::SampledTexture>(ast::TextureDimension::k3d, f32);
773 
774   spirv::Builder& b = Build();
775 
776   EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
777   ASSERT_FALSE(b.has_error()) << b.error();
778   EXPECT_EQ(DumpInstructions(b.types()),
779             R"(%2 = OpTypeFloat 32
780 %1 = OpTypeImage %2 3D 0 0 0 1 Unknown
781 )");
782 }
783 
TEST_F(BuilderTest_Type,SampledTexture_Generate_Cube)784 TEST_F(BuilderTest_Type, SampledTexture_Generate_Cube) {
785   auto* f32 = create<sem::F32>();
786   auto* s = create<sem::SampledTexture>(ast::TextureDimension::kCube, f32);
787 
788   spirv::Builder& b = Build();
789 
790   EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
791   ASSERT_FALSE(b.has_error()) << b.error();
792   EXPECT_EQ(DumpInstructions(b.types()),
793             R"(%2 = OpTypeFloat 32
794 %1 = OpTypeImage %2 Cube 0 0 0 1 Unknown
795 )");
796   EXPECT_EQ(DumpInstructions(b.capabilities()), "");
797 }
798 
TEST_F(BuilderTest_Type,SampledTexture_Generate_CubeArray)799 TEST_F(BuilderTest_Type, SampledTexture_Generate_CubeArray) {
800   auto* f32 = create<sem::F32>();
801   auto* s = create<sem::SampledTexture>(ast::TextureDimension::kCubeArray, f32);
802 
803   spirv::Builder& b = Build();
804 
805   EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
806   ASSERT_FALSE(b.has_error()) << b.error();
807   EXPECT_EQ(DumpInstructions(b.types()),
808             R"(%2 = OpTypeFloat 32
809 %1 = OpTypeImage %2 Cube 0 1 0 1 Unknown
810 )");
811   EXPECT_EQ(DumpInstructions(b.capabilities()),
812             R"(OpCapability SampledCubeArray
813 )");
814 }
815 
TEST_F(BuilderTest_Type,StorageTexture_Generate_1d)816 TEST_F(BuilderTest_Type, StorageTexture_Generate_1d) {
817   auto* s =
818       ty.storage_texture(ast::TextureDimension::k1d,
819                          ast::ImageFormat::kR32Float, ast::Access::kWrite);
820 
821   Global("test_var", s,
822          ast::DecorationList{
823              create<ast::BindingDecoration>(0),
824              create<ast::GroupDecoration>(0),
825          });
826 
827   spirv::Builder& b = Build();
828 
829   EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
830   ASSERT_FALSE(b.has_error()) << b.error();
831   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
832 %1 = OpTypeImage %2 1D 0 0 0 2 R32f
833 )");
834 }
835 
TEST_F(BuilderTest_Type,StorageTexture_Generate_2d)836 TEST_F(BuilderTest_Type, StorageTexture_Generate_2d) {
837   auto* s =
838       ty.storage_texture(ast::TextureDimension::k2d,
839                          ast::ImageFormat::kR32Float, ast::Access::kWrite);
840 
841   Global("test_var", s,
842          ast::DecorationList{
843              create<ast::BindingDecoration>(0),
844              create<ast::GroupDecoration>(0),
845          });
846 
847   spirv::Builder& b = Build();
848 
849   EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
850   ASSERT_FALSE(b.has_error()) << b.error();
851   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
852 %1 = OpTypeImage %2 2D 0 0 0 2 R32f
853 )");
854 }
855 
TEST_F(BuilderTest_Type,StorageTexture_Generate_2dArray)856 TEST_F(BuilderTest_Type, StorageTexture_Generate_2dArray) {
857   auto* s =
858       ty.storage_texture(ast::TextureDimension::k2dArray,
859                          ast::ImageFormat::kR32Float, ast::Access::kWrite);
860 
861   Global("test_var", s,
862          ast::DecorationList{
863              create<ast::BindingDecoration>(0),
864              create<ast::GroupDecoration>(0),
865          });
866 
867   spirv::Builder& b = Build();
868 
869   EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
870   ASSERT_FALSE(b.has_error()) << b.error();
871   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
872 %1 = OpTypeImage %2 2D 0 1 0 2 R32f
873 )");
874 }
875 
TEST_F(BuilderTest_Type,StorageTexture_Generate_3d)876 TEST_F(BuilderTest_Type, StorageTexture_Generate_3d) {
877   auto* s =
878       ty.storage_texture(ast::TextureDimension::k3d,
879                          ast::ImageFormat::kR32Float, ast::Access::kWrite);
880 
881   Global("test_var", s,
882          ast::DecorationList{
883              create<ast::BindingDecoration>(0),
884              create<ast::GroupDecoration>(0),
885          });
886 
887   spirv::Builder& b = Build();
888 
889   EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
890   ASSERT_FALSE(b.has_error()) << b.error();
891   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
892 %1 = OpTypeImage %2 3D 0 0 0 2 R32f
893 )");
894 }
895 
TEST_F(BuilderTest_Type,StorageTexture_Generate_SampledTypeFloat_Format_r32float)896 TEST_F(BuilderTest_Type,
897        StorageTexture_Generate_SampledTypeFloat_Format_r32float) {
898   auto* s =
899       ty.storage_texture(ast::TextureDimension::k2d,
900                          ast::ImageFormat::kR32Float, ast::Access::kWrite);
901 
902   Global("test_var", s,
903          ast::DecorationList{
904              create<ast::BindingDecoration>(0),
905              create<ast::GroupDecoration>(0),
906          });
907 
908   spirv::Builder& b = Build();
909 
910   EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
911   ASSERT_FALSE(b.has_error()) << b.error();
912   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
913 %1 = OpTypeImage %2 2D 0 0 0 2 R32f
914 )");
915 }
916 
TEST_F(BuilderTest_Type,StorageTexture_Generate_SampledTypeSint_Format_r32sint)917 TEST_F(BuilderTest_Type,
918        StorageTexture_Generate_SampledTypeSint_Format_r32sint) {
919   auto* s = ty.storage_texture(ast::TextureDimension::k2d,
920                                ast::ImageFormat::kR32Sint, ast::Access::kWrite);
921 
922   Global("test_var", s,
923          ast::DecorationList{
924              create<ast::BindingDecoration>(0),
925              create<ast::GroupDecoration>(0),
926          });
927 
928   spirv::Builder& b = Build();
929 
930   EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
931   ASSERT_FALSE(b.has_error()) << b.error();
932   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
933 %1 = OpTypeImage %2 2D 0 0 0 2 R32i
934 )");
935 }
936 
TEST_F(BuilderTest_Type,StorageTexture_Generate_SampledTypeUint_Format_r32uint)937 TEST_F(BuilderTest_Type,
938        StorageTexture_Generate_SampledTypeUint_Format_r32uint) {
939   auto* s = ty.storage_texture(ast::TextureDimension::k2d,
940                                ast::ImageFormat::kR32Uint, ast::Access::kWrite);
941 
942   Global("test_var", s,
943          ast::DecorationList{
944              create<ast::BindingDecoration>(0),
945              create<ast::GroupDecoration>(0),
946          });
947 
948   spirv::Builder& b = Build();
949 
950   EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
951   ASSERT_FALSE(b.has_error()) << b.error();
952   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
953 %1 = OpTypeImage %2 2D 0 0 0 2 R32ui
954 )");
955 }
956 
TEST_F(BuilderTest_Type,Sampler)957 TEST_F(BuilderTest_Type, Sampler) {
958   sem::Sampler sampler(ast::SamplerKind::kSampler);
959 
960   spirv::Builder& b = Build();
961 
962   EXPECT_EQ(b.GenerateTypeIfNeeded(&sampler), 1u);
963   ASSERT_FALSE(b.has_error()) << b.error();
964   EXPECT_EQ(DumpInstructions(b.types()), "%1 = OpTypeSampler\n");
965 }
966 
TEST_F(BuilderTest_Type,ComparisonSampler)967 TEST_F(BuilderTest_Type, ComparisonSampler) {
968   sem::Sampler sampler(ast::SamplerKind::kComparisonSampler);
969 
970   spirv::Builder& b = Build();
971 
972   EXPECT_EQ(b.GenerateTypeIfNeeded(&sampler), 1u);
973   ASSERT_FALSE(b.has_error()) << b.error();
974   EXPECT_EQ(DumpInstructions(b.types()), "%1 = OpTypeSampler\n");
975 }
976 
TEST_F(BuilderTest_Type,Dedup_Sampler_And_ComparisonSampler)977 TEST_F(BuilderTest_Type, Dedup_Sampler_And_ComparisonSampler) {
978   sem::Sampler comp_sampler(ast::SamplerKind::kComparisonSampler);
979   sem::Sampler sampler(ast::SamplerKind::kSampler);
980 
981   spirv::Builder& b = Build();
982 
983   EXPECT_EQ(b.GenerateTypeIfNeeded(&comp_sampler), 1u);
984 
985   EXPECT_EQ(b.GenerateTypeIfNeeded(&sampler), 1u);
986 
987   ASSERT_FALSE(b.has_error()) << b.error();
988   EXPECT_EQ(DumpInstructions(b.types()), "%1 = OpTypeSampler\n");
989 }
990 
991 }  // namespace
992 }  // namespace spirv
993 }  // namespace writer
994 }  // namespace tint
995