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