1 // Copyright 2021 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/transform/canonicalize_entry_point_io.h"
16
17 #include "src/transform/test_helper.h"
18 #include "src/transform/unshadow.h"
19
20 namespace tint {
21 namespace transform {
22 namespace {
23
24 using CanonicalizeEntryPointIOTest = TransformTest;
25
TEST_F(CanonicalizeEntryPointIOTest,Error_MissingUnshadow)26 TEST_F(CanonicalizeEntryPointIOTest, Error_MissingUnshadow) {
27 auto* src = "";
28
29 auto* expect =
30 "error: tint::transform::CanonicalizeEntryPointIO depends on "
31 "tint::transform::Unshadow but the dependency was not run";
32
33 auto got = Run<CanonicalizeEntryPointIO>(src);
34
35 EXPECT_EQ(expect, str(got));
36 }
37
TEST_F(CanonicalizeEntryPointIOTest,Error_MissingTransformData)38 TEST_F(CanonicalizeEntryPointIOTest, Error_MissingTransformData) {
39 auto* src = "";
40
41 auto* expect =
42 "error: missing transform data for "
43 "tint::transform::CanonicalizeEntryPointIO";
44
45 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src);
46
47 EXPECT_EQ(expect, str(got));
48 }
49
TEST_F(CanonicalizeEntryPointIOTest,NoShaderIO)50 TEST_F(CanonicalizeEntryPointIOTest, NoShaderIO) {
51 // Test that we do not introduce wrapper functions when there is no shader IO
52 // to process.
53 auto* src = R"(
54 [[stage(fragment)]]
55 fn frag_main() {
56 }
57
58 [[stage(compute), workgroup_size(1)]]
59 fn comp_main() {
60 }
61 )";
62
63 auto* expect = src;
64
65 DataMap data;
66 data.Add<CanonicalizeEntryPointIO::Config>(
67 CanonicalizeEntryPointIO::ShaderStyle::kMsl);
68 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
69
70 EXPECT_EQ(expect, str(got));
71 }
72
TEST_F(CanonicalizeEntryPointIOTest,Parameters_Spirv)73 TEST_F(CanonicalizeEntryPointIOTest, Parameters_Spirv) {
74 auto* src = R"(
75 [[stage(fragment)]]
76 fn frag_main([[location(1)]] loc1 : f32,
77 [[location(2)]] loc2 : vec4<u32>,
78 [[builtin(position)]] coord : vec4<f32>) {
79 var col : f32 = (coord.x * loc1);
80 }
81 )";
82
83 auto* expect = R"(
84 [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> loc1_1 : f32;
85
86 [[location(2), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<in> loc2_1 : vec4<u32>;
87
88 [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<in> coord_1 : vec4<f32>;
89
90 fn frag_main_inner(loc1 : f32, loc2 : vec4<u32>, coord : vec4<f32>) {
91 var col : f32 = (coord.x * loc1);
92 }
93
94 [[stage(fragment)]]
95 fn frag_main() {
96 frag_main_inner(loc1_1, loc2_1, coord_1);
97 }
98 )";
99
100 DataMap data;
101 data.Add<CanonicalizeEntryPointIO::Config>(
102 CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
103 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
104
105 EXPECT_EQ(expect, str(got));
106 }
107
TEST_F(CanonicalizeEntryPointIOTest,Parameters_Msl)108 TEST_F(CanonicalizeEntryPointIOTest, Parameters_Msl) {
109 auto* src = R"(
110 [[stage(fragment)]]
111 fn frag_main([[location(1)]] loc1 : f32,
112 [[location(2)]] loc2 : vec4<u32>,
113 [[builtin(position)]] coord : vec4<f32>) {
114 var col : f32 = (coord.x * loc1);
115 }
116 )";
117
118 auto* expect = R"(
119 struct tint_symbol_1 {
120 [[location(1)]]
121 loc1 : f32;
122 [[location(2)]]
123 loc2 : vec4<u32>;
124 };
125
126 fn frag_main_inner(loc1 : f32, loc2 : vec4<u32>, coord : vec4<f32>) {
127 var col : f32 = (coord.x * loc1);
128 }
129
130 [[stage(fragment)]]
131 fn frag_main([[builtin(position)]] coord : vec4<f32>, tint_symbol : tint_symbol_1) {
132 frag_main_inner(tint_symbol.loc1, tint_symbol.loc2, coord);
133 }
134 )";
135
136 DataMap data;
137 data.Add<CanonicalizeEntryPointIO::Config>(
138 CanonicalizeEntryPointIO::ShaderStyle::kMsl);
139 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
140
141 EXPECT_EQ(expect, str(got));
142 }
143
TEST_F(CanonicalizeEntryPointIOTest,Parameters_Hlsl)144 TEST_F(CanonicalizeEntryPointIOTest, Parameters_Hlsl) {
145 auto* src = R"(
146 [[stage(fragment)]]
147 fn frag_main([[location(1)]] loc1 : f32,
148 [[location(2)]] loc2 : vec4<u32>,
149 [[builtin(position)]] coord : vec4<f32>) {
150 var col : f32 = (coord.x * loc1);
151 }
152 )";
153
154 auto* expect = R"(
155 struct tint_symbol_1 {
156 [[location(1)]]
157 loc1 : f32;
158 [[location(2)]]
159 loc2 : vec4<u32>;
160 [[builtin(position)]]
161 coord : vec4<f32>;
162 };
163
164 fn frag_main_inner(loc1 : f32, loc2 : vec4<u32>, coord : vec4<f32>) {
165 var col : f32 = (coord.x * loc1);
166 }
167
168 [[stage(fragment)]]
169 fn frag_main(tint_symbol : tint_symbol_1) {
170 frag_main_inner(tint_symbol.loc1, tint_symbol.loc2, tint_symbol.coord);
171 }
172 )";
173
174 DataMap data;
175 data.Add<CanonicalizeEntryPointIO::Config>(
176 CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
177 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
178
179 EXPECT_EQ(expect, str(got));
180 }
181
TEST_F(CanonicalizeEntryPointIOTest,Parameter_TypeAlias)182 TEST_F(CanonicalizeEntryPointIOTest, Parameter_TypeAlias) {
183 auto* src = R"(
184 type myf32 = f32;
185
186 [[stage(fragment)]]
187 fn frag_main([[location(1)]] loc1 : myf32) {
188 var x : myf32 = loc1;
189 }
190 )";
191
192 auto* expect = R"(
193 type myf32 = f32;
194
195 struct tint_symbol_1 {
196 [[location(1)]]
197 loc1 : f32;
198 };
199
200 fn frag_main_inner(loc1 : myf32) {
201 var x : myf32 = loc1;
202 }
203
204 [[stage(fragment)]]
205 fn frag_main(tint_symbol : tint_symbol_1) {
206 frag_main_inner(tint_symbol.loc1);
207 }
208 )";
209
210 DataMap data;
211 data.Add<CanonicalizeEntryPointIO::Config>(
212 CanonicalizeEntryPointIO::ShaderStyle::kMsl);
213 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
214
215 EXPECT_EQ(expect, str(got));
216 }
217
TEST_F(CanonicalizeEntryPointIOTest,StructParameters_Spirv)218 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_Spirv) {
219 auto* src = R"(
220 struct FragBuiltins {
221 [[builtin(position)]] coord : vec4<f32>;
222 };
223 struct FragLocations {
224 [[location(1)]] loc1 : f32;
225 [[location(2)]] loc2 : vec4<u32>;
226 };
227
228 [[stage(fragment)]]
229 fn frag_main([[location(0)]] loc0 : f32,
230 locations : FragLocations,
231 builtins : FragBuiltins) {
232 var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
233 }
234 )";
235
236 auto* expect = R"(
237 [[location(0), internal(disable_validation__ignore_storage_class)]] var<in> loc0_1 : f32;
238
239 [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> loc1_1 : f32;
240
241 [[location(2), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<in> loc2_1 : vec4<u32>;
242
243 [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<in> coord_1 : vec4<f32>;
244
245 struct FragBuiltins {
246 coord : vec4<f32>;
247 };
248
249 struct FragLocations {
250 loc1 : f32;
251 loc2 : vec4<u32>;
252 };
253
254 fn frag_main_inner(loc0 : f32, locations : FragLocations, builtins : FragBuiltins) {
255 var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
256 }
257
258 [[stage(fragment)]]
259 fn frag_main() {
260 frag_main_inner(loc0_1, FragLocations(loc1_1, loc2_1), FragBuiltins(coord_1));
261 }
262 )";
263
264 DataMap data;
265 data.Add<CanonicalizeEntryPointIO::Config>(
266 CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
267 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
268
269 EXPECT_EQ(expect, str(got));
270 }
271
TEST_F(CanonicalizeEntryPointIOTest,StructParameters_kMsl)272 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_kMsl) {
273 auto* src = R"(
274 struct FragBuiltins {
275 [[builtin(position)]] coord : vec4<f32>;
276 };
277 struct FragLocations {
278 [[location(1)]] loc1 : f32;
279 [[location(2)]] loc2 : vec4<u32>;
280 };
281
282 [[stage(fragment)]]
283 fn frag_main([[location(0)]] loc0 : f32,
284 locations : FragLocations,
285 builtins : FragBuiltins) {
286 var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
287 }
288 )";
289
290 auto* expect = R"(
291 struct FragBuiltins {
292 coord : vec4<f32>;
293 };
294
295 struct FragLocations {
296 loc1 : f32;
297 loc2 : vec4<u32>;
298 };
299
300 struct tint_symbol_1 {
301 [[location(0)]]
302 loc0 : f32;
303 [[location(1)]]
304 loc1 : f32;
305 [[location(2)]]
306 loc2 : vec4<u32>;
307 };
308
309 fn frag_main_inner(loc0 : f32, locations : FragLocations, builtins : FragBuiltins) {
310 var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
311 }
312
313 [[stage(fragment)]]
314 fn frag_main([[builtin(position)]] coord : vec4<f32>, tint_symbol : tint_symbol_1) {
315 frag_main_inner(tint_symbol.loc0, FragLocations(tint_symbol.loc1, tint_symbol.loc2), FragBuiltins(coord));
316 }
317 )";
318
319 DataMap data;
320 data.Add<CanonicalizeEntryPointIO::Config>(
321 CanonicalizeEntryPointIO::ShaderStyle::kMsl);
322 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
323
324 EXPECT_EQ(expect, str(got));
325 }
326
TEST_F(CanonicalizeEntryPointIOTest,StructParameters_Hlsl)327 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_Hlsl) {
328 auto* src = R"(
329 struct FragBuiltins {
330 [[builtin(position)]] coord : vec4<f32>;
331 };
332 struct FragLocations {
333 [[location(1)]] loc1 : f32;
334 [[location(2)]] loc2 : vec4<u32>;
335 };
336
337 [[stage(fragment)]]
338 fn frag_main([[location(0)]] loc0 : f32,
339 locations : FragLocations,
340 builtins : FragBuiltins) {
341 var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
342 }
343 )";
344
345 auto* expect = R"(
346 struct FragBuiltins {
347 coord : vec4<f32>;
348 };
349
350 struct FragLocations {
351 loc1 : f32;
352 loc2 : vec4<u32>;
353 };
354
355 struct tint_symbol_1 {
356 [[location(0)]]
357 loc0 : f32;
358 [[location(1)]]
359 loc1 : f32;
360 [[location(2)]]
361 loc2 : vec4<u32>;
362 [[builtin(position)]]
363 coord : vec4<f32>;
364 };
365
366 fn frag_main_inner(loc0 : f32, locations : FragLocations, builtins : FragBuiltins) {
367 var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
368 }
369
370 [[stage(fragment)]]
371 fn frag_main(tint_symbol : tint_symbol_1) {
372 frag_main_inner(tint_symbol.loc0, FragLocations(tint_symbol.loc1, tint_symbol.loc2), FragBuiltins(tint_symbol.coord));
373 }
374 )";
375
376 DataMap data;
377 data.Add<CanonicalizeEntryPointIO::Config>(
378 CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
379 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
380
381 EXPECT_EQ(expect, str(got));
382 }
383
TEST_F(CanonicalizeEntryPointIOTest,Return_NonStruct_Spirv)384 TEST_F(CanonicalizeEntryPointIOTest, Return_NonStruct_Spirv) {
385 auto* src = R"(
386 [[stage(fragment)]]
387 fn frag_main() -> [[builtin(frag_depth)]] f32 {
388 return 1.0;
389 }
390 )";
391
392 auto* expect = R"(
393 [[builtin(frag_depth), internal(disable_validation__ignore_storage_class)]] var<out> value : f32;
394
395 fn frag_main_inner() -> f32 {
396 return 1.0;
397 }
398
399 [[stage(fragment)]]
400 fn frag_main() {
401 let inner_result = frag_main_inner();
402 value = inner_result;
403 }
404 )";
405
406 DataMap data;
407 data.Add<CanonicalizeEntryPointIO::Config>(
408 CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
409 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
410
411 EXPECT_EQ(expect, str(got));
412 }
413
TEST_F(CanonicalizeEntryPointIOTest,Return_NonStruct_Msl)414 TEST_F(CanonicalizeEntryPointIOTest, Return_NonStruct_Msl) {
415 auto* src = R"(
416 [[stage(fragment)]]
417 fn frag_main() -> [[builtin(frag_depth)]] f32 {
418 return 1.0;
419 }
420 )";
421
422 auto* expect = R"(
423 struct tint_symbol {
424 [[builtin(frag_depth)]]
425 value : f32;
426 };
427
428 fn frag_main_inner() -> f32 {
429 return 1.0;
430 }
431
432 [[stage(fragment)]]
433 fn frag_main() -> tint_symbol {
434 let inner_result = frag_main_inner();
435 var wrapper_result : tint_symbol;
436 wrapper_result.value = inner_result;
437 return wrapper_result;
438 }
439 )";
440
441 DataMap data;
442 data.Add<CanonicalizeEntryPointIO::Config>(
443 CanonicalizeEntryPointIO::ShaderStyle::kMsl);
444 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
445
446 EXPECT_EQ(expect, str(got));
447 }
448
TEST_F(CanonicalizeEntryPointIOTest,Return_NonStruct_Hlsl)449 TEST_F(CanonicalizeEntryPointIOTest, Return_NonStruct_Hlsl) {
450 auto* src = R"(
451 [[stage(fragment)]]
452 fn frag_main() -> [[builtin(frag_depth)]] f32 {
453 return 1.0;
454 }
455 )";
456
457 auto* expect = R"(
458 struct tint_symbol {
459 [[builtin(frag_depth)]]
460 value : f32;
461 };
462
463 fn frag_main_inner() -> f32 {
464 return 1.0;
465 }
466
467 [[stage(fragment)]]
468 fn frag_main() -> tint_symbol {
469 let inner_result = frag_main_inner();
470 var wrapper_result : tint_symbol;
471 wrapper_result.value = inner_result;
472 return wrapper_result;
473 }
474 )";
475
476 DataMap data;
477 data.Add<CanonicalizeEntryPointIO::Config>(
478 CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
479 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
480
481 EXPECT_EQ(expect, str(got));
482 }
483
TEST_F(CanonicalizeEntryPointIOTest,Return_Struct_Spirv)484 TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Spirv) {
485 auto* src = R"(
486 struct FragOutput {
487 [[location(0)]] color : vec4<f32>;
488 [[builtin(frag_depth)]] depth : f32;
489 [[builtin(sample_mask)]] mask : u32;
490 };
491
492 [[stage(fragment)]]
493 fn frag_main() -> FragOutput {
494 var output : FragOutput;
495 output.depth = 1.0;
496 output.mask = 7u;
497 output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
498 return output;
499 }
500 )";
501
502 auto* expect = R"(
503 [[location(0), internal(disable_validation__ignore_storage_class)]] var<out> color_1 : vec4<f32>;
504
505 [[builtin(frag_depth), internal(disable_validation__ignore_storage_class)]] var<out> depth_1 : f32;
506
507 [[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<out> mask_1 : array<u32, 1>;
508
509 struct FragOutput {
510 color : vec4<f32>;
511 depth : f32;
512 mask : u32;
513 };
514
515 fn frag_main_inner() -> FragOutput {
516 var output : FragOutput;
517 output.depth = 1.0;
518 output.mask = 7u;
519 output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
520 return output;
521 }
522
523 [[stage(fragment)]]
524 fn frag_main() {
525 let inner_result = frag_main_inner();
526 color_1 = inner_result.color;
527 depth_1 = inner_result.depth;
528 mask_1[0] = inner_result.mask;
529 }
530 )";
531
532 DataMap data;
533 data.Add<CanonicalizeEntryPointIO::Config>(
534 CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
535 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
536
537 EXPECT_EQ(expect, str(got));
538 }
539
TEST_F(CanonicalizeEntryPointIOTest,Return_Struct_Msl)540 TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Msl) {
541 auto* src = R"(
542 struct FragOutput {
543 [[location(0)]] color : vec4<f32>;
544 [[builtin(frag_depth)]] depth : f32;
545 [[builtin(sample_mask)]] mask : u32;
546 };
547
548 [[stage(fragment)]]
549 fn frag_main() -> FragOutput {
550 var output : FragOutput;
551 output.depth = 1.0;
552 output.mask = 7u;
553 output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
554 return output;
555 }
556 )";
557
558 auto* expect = R"(
559 struct FragOutput {
560 color : vec4<f32>;
561 depth : f32;
562 mask : u32;
563 };
564
565 struct tint_symbol {
566 [[location(0)]]
567 color : vec4<f32>;
568 [[builtin(frag_depth)]]
569 depth : f32;
570 [[builtin(sample_mask)]]
571 mask : u32;
572 };
573
574 fn frag_main_inner() -> FragOutput {
575 var output : FragOutput;
576 output.depth = 1.0;
577 output.mask = 7u;
578 output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
579 return output;
580 }
581
582 [[stage(fragment)]]
583 fn frag_main() -> tint_symbol {
584 let inner_result = frag_main_inner();
585 var wrapper_result : tint_symbol;
586 wrapper_result.color = inner_result.color;
587 wrapper_result.depth = inner_result.depth;
588 wrapper_result.mask = inner_result.mask;
589 return wrapper_result;
590 }
591 )";
592
593 DataMap data;
594 data.Add<CanonicalizeEntryPointIO::Config>(
595 CanonicalizeEntryPointIO::ShaderStyle::kMsl);
596 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
597
598 EXPECT_EQ(expect, str(got));
599 }
600
TEST_F(CanonicalizeEntryPointIOTest,Return_Struct_Hlsl)601 TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Hlsl) {
602 auto* src = R"(
603 struct FragOutput {
604 [[location(0)]] color : vec4<f32>;
605 [[builtin(frag_depth)]] depth : f32;
606 [[builtin(sample_mask)]] mask : u32;
607 };
608
609 [[stage(fragment)]]
610 fn frag_main() -> FragOutput {
611 var output : FragOutput;
612 output.depth = 1.0;
613 output.mask = 7u;
614 output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
615 return output;
616 }
617 )";
618
619 auto* expect = R"(
620 struct FragOutput {
621 color : vec4<f32>;
622 depth : f32;
623 mask : u32;
624 };
625
626 struct tint_symbol {
627 [[location(0)]]
628 color : vec4<f32>;
629 [[builtin(frag_depth)]]
630 depth : f32;
631 [[builtin(sample_mask)]]
632 mask : u32;
633 };
634
635 fn frag_main_inner() -> FragOutput {
636 var output : FragOutput;
637 output.depth = 1.0;
638 output.mask = 7u;
639 output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
640 return output;
641 }
642
643 [[stage(fragment)]]
644 fn frag_main() -> tint_symbol {
645 let inner_result = frag_main_inner();
646 var wrapper_result : tint_symbol;
647 wrapper_result.color = inner_result.color;
648 wrapper_result.depth = inner_result.depth;
649 wrapper_result.mask = inner_result.mask;
650 return wrapper_result;
651 }
652 )";
653
654 DataMap data;
655 data.Add<CanonicalizeEntryPointIO::Config>(
656 CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
657 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
658
659 EXPECT_EQ(expect, str(got));
660 }
661
TEST_F(CanonicalizeEntryPointIOTest,StructParameters_SharedDeviceFunction_Spirv)662 TEST_F(CanonicalizeEntryPointIOTest,
663 StructParameters_SharedDeviceFunction_Spirv) {
664 auto* src = R"(
665 struct FragmentInput {
666 [[location(0)]] value : f32;
667 [[location(1)]] mul : f32;
668 };
669
670 fn foo(x : FragmentInput) -> f32 {
671 return x.value * x.mul;
672 }
673
674 [[stage(fragment)]]
675 fn frag_main1(inputs : FragmentInput) {
676 var x : f32 = foo(inputs);
677 }
678
679 [[stage(fragment)]]
680 fn frag_main2(inputs : FragmentInput) {
681 var x : f32 = foo(inputs);
682 }
683 )";
684
685 auto* expect = R"(
686 [[location(0), internal(disable_validation__ignore_storage_class)]] var<in> value_1 : f32;
687
688 [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> mul_1 : f32;
689
690 [[location(0), internal(disable_validation__ignore_storage_class)]] var<in> value_2 : f32;
691
692 [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> mul_2 : f32;
693
694 struct FragmentInput {
695 value : f32;
696 mul : f32;
697 };
698
699 fn foo(x : FragmentInput) -> f32 {
700 return (x.value * x.mul);
701 }
702
703 fn frag_main1_inner(inputs : FragmentInput) {
704 var x : f32 = foo(inputs);
705 }
706
707 [[stage(fragment)]]
708 fn frag_main1() {
709 frag_main1_inner(FragmentInput(value_1, mul_1));
710 }
711
712 fn frag_main2_inner(inputs : FragmentInput) {
713 var x : f32 = foo(inputs);
714 }
715
716 [[stage(fragment)]]
717 fn frag_main2() {
718 frag_main2_inner(FragmentInput(value_2, mul_2));
719 }
720 )";
721
722 DataMap data;
723 data.Add<CanonicalizeEntryPointIO::Config>(
724 CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
725 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
726
727 EXPECT_EQ(expect, str(got));
728 }
729
TEST_F(CanonicalizeEntryPointIOTest,StructParameters_SharedDeviceFunction_Msl)730 TEST_F(CanonicalizeEntryPointIOTest,
731 StructParameters_SharedDeviceFunction_Msl) {
732 auto* src = R"(
733 struct FragmentInput {
734 [[location(0)]] value : f32;
735 [[location(1)]] mul : f32;
736 };
737
738 fn foo(x : FragmentInput) -> f32 {
739 return x.value * x.mul;
740 }
741
742 [[stage(fragment)]]
743 fn frag_main1(inputs : FragmentInput) {
744 var x : f32 = foo(inputs);
745 }
746
747 [[stage(fragment)]]
748 fn frag_main2(inputs : FragmentInput) {
749 var x : f32 = foo(inputs);
750 }
751 )";
752
753 auto* expect = R"(
754 struct FragmentInput {
755 value : f32;
756 mul : f32;
757 };
758
759 fn foo(x : FragmentInput) -> f32 {
760 return (x.value * x.mul);
761 }
762
763 struct tint_symbol_1 {
764 [[location(0)]]
765 value : f32;
766 [[location(1)]]
767 mul : f32;
768 };
769
770 fn frag_main1_inner(inputs : FragmentInput) {
771 var x : f32 = foo(inputs);
772 }
773
774 [[stage(fragment)]]
775 fn frag_main1(tint_symbol : tint_symbol_1) {
776 frag_main1_inner(FragmentInput(tint_symbol.value, tint_symbol.mul));
777 }
778
779 struct tint_symbol_3 {
780 [[location(0)]]
781 value : f32;
782 [[location(1)]]
783 mul : f32;
784 };
785
786 fn frag_main2_inner(inputs : FragmentInput) {
787 var x : f32 = foo(inputs);
788 }
789
790 [[stage(fragment)]]
791 fn frag_main2(tint_symbol_2 : tint_symbol_3) {
792 frag_main2_inner(FragmentInput(tint_symbol_2.value, tint_symbol_2.mul));
793 }
794 )";
795
796 DataMap data;
797 data.Add<CanonicalizeEntryPointIO::Config>(
798 CanonicalizeEntryPointIO::ShaderStyle::kMsl);
799 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
800
801 EXPECT_EQ(expect, str(got));
802 }
803
TEST_F(CanonicalizeEntryPointIOTest,StructParameters_SharedDeviceFunction_Hlsl)804 TEST_F(CanonicalizeEntryPointIOTest,
805 StructParameters_SharedDeviceFunction_Hlsl) {
806 auto* src = R"(
807 struct FragmentInput {
808 [[location(0)]] value : f32;
809 [[location(1)]] mul : f32;
810 };
811
812 fn foo(x : FragmentInput) -> f32 {
813 return x.value * x.mul;
814 }
815
816 [[stage(fragment)]]
817 fn frag_main1(inputs : FragmentInput) {
818 var x : f32 = foo(inputs);
819 }
820
821 [[stage(fragment)]]
822 fn frag_main2(inputs : FragmentInput) {
823 var x : f32 = foo(inputs);
824 }
825 )";
826
827 auto* expect = R"(
828 struct FragmentInput {
829 value : f32;
830 mul : f32;
831 };
832
833 fn foo(x : FragmentInput) -> f32 {
834 return (x.value * x.mul);
835 }
836
837 struct tint_symbol_1 {
838 [[location(0)]]
839 value : f32;
840 [[location(1)]]
841 mul : f32;
842 };
843
844 fn frag_main1_inner(inputs : FragmentInput) {
845 var x : f32 = foo(inputs);
846 }
847
848 [[stage(fragment)]]
849 fn frag_main1(tint_symbol : tint_symbol_1) {
850 frag_main1_inner(FragmentInput(tint_symbol.value, tint_symbol.mul));
851 }
852
853 struct tint_symbol_3 {
854 [[location(0)]]
855 value : f32;
856 [[location(1)]]
857 mul : f32;
858 };
859
860 fn frag_main2_inner(inputs : FragmentInput) {
861 var x : f32 = foo(inputs);
862 }
863
864 [[stage(fragment)]]
865 fn frag_main2(tint_symbol_2 : tint_symbol_3) {
866 frag_main2_inner(FragmentInput(tint_symbol_2.value, tint_symbol_2.mul));
867 }
868 )";
869
870 DataMap data;
871 data.Add<CanonicalizeEntryPointIO::Config>(
872 CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
873 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
874
875 EXPECT_EQ(expect, str(got));
876 }
877
TEST_F(CanonicalizeEntryPointIOTest,Struct_ModuleScopeVariable)878 TEST_F(CanonicalizeEntryPointIOTest, Struct_ModuleScopeVariable) {
879 auto* src = R"(
880 struct FragmentInput {
881 [[location(0)]] col1 : f32;
882 [[location(1)]] col2 : f32;
883 };
884
885 var<private> global_inputs : FragmentInput;
886
887 fn foo() -> f32 {
888 return global_inputs.col1 * 0.5;
889 }
890
891 fn bar() -> f32 {
892 return global_inputs.col2 * 2.0;
893 }
894
895 [[stage(fragment)]]
896 fn frag_main1(inputs : FragmentInput) {
897 global_inputs = inputs;
898 var r : f32 = foo();
899 var g : f32 = bar();
900 }
901 )";
902
903 auto* expect = R"(
904 struct FragmentInput {
905 col1 : f32;
906 col2 : f32;
907 };
908
909 var<private> global_inputs : FragmentInput;
910
911 fn foo() -> f32 {
912 return (global_inputs.col1 * 0.5);
913 }
914
915 fn bar() -> f32 {
916 return (global_inputs.col2 * 2.0);
917 }
918
919 struct tint_symbol_1 {
920 [[location(0)]]
921 col1 : f32;
922 [[location(1)]]
923 col2 : f32;
924 };
925
926 fn frag_main1_inner(inputs : FragmentInput) {
927 global_inputs = inputs;
928 var r : f32 = foo();
929 var g : f32 = bar();
930 }
931
932 [[stage(fragment)]]
933 fn frag_main1(tint_symbol : tint_symbol_1) {
934 frag_main1_inner(FragmentInput(tint_symbol.col1, tint_symbol.col2));
935 }
936 )";
937
938 DataMap data;
939 data.Add<CanonicalizeEntryPointIO::Config>(
940 CanonicalizeEntryPointIO::ShaderStyle::kMsl);
941 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
942
943 EXPECT_EQ(expect, str(got));
944 }
945
TEST_F(CanonicalizeEntryPointIOTest,Struct_TypeAliases)946 TEST_F(CanonicalizeEntryPointIOTest, Struct_TypeAliases) {
947 auto* src = R"(
948 type myf32 = f32;
949
950 struct FragmentInput {
951 [[location(0)]] col1 : myf32;
952 [[location(1)]] col2 : myf32;
953 };
954
955 struct FragmentOutput {
956 [[location(0)]] col1 : myf32;
957 [[location(1)]] col2 : myf32;
958 };
959
960 type MyFragmentInput = FragmentInput;
961
962 type MyFragmentOutput = FragmentOutput;
963
964 fn foo(x : MyFragmentInput) -> myf32 {
965 return x.col1;
966 }
967
968 [[stage(fragment)]]
969 fn frag_main(inputs : MyFragmentInput) -> MyFragmentOutput {
970 var x : myf32 = foo(inputs);
971 return MyFragmentOutput(x, inputs.col2);
972 }
973 )";
974
975 auto* expect = R"(
976 type myf32 = f32;
977
978 struct FragmentInput {
979 col1 : myf32;
980 col2 : myf32;
981 };
982
983 struct FragmentOutput {
984 col1 : myf32;
985 col2 : myf32;
986 };
987
988 type MyFragmentInput = FragmentInput;
989
990 type MyFragmentOutput = FragmentOutput;
991
992 fn foo(x : MyFragmentInput) -> myf32 {
993 return x.col1;
994 }
995
996 struct tint_symbol_1 {
997 [[location(0)]]
998 col1 : f32;
999 [[location(1)]]
1000 col2 : f32;
1001 };
1002
1003 struct tint_symbol_2 {
1004 [[location(0)]]
1005 col1 : f32;
1006 [[location(1)]]
1007 col2 : f32;
1008 };
1009
1010 fn frag_main_inner(inputs : MyFragmentInput) -> MyFragmentOutput {
1011 var x : myf32 = foo(inputs);
1012 return MyFragmentOutput(x, inputs.col2);
1013 }
1014
1015 [[stage(fragment)]]
1016 fn frag_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
1017 let inner_result = frag_main_inner(MyFragmentInput(tint_symbol.col1, tint_symbol.col2));
1018 var wrapper_result : tint_symbol_2;
1019 wrapper_result.col1 = inner_result.col1;
1020 wrapper_result.col2 = inner_result.col2;
1021 return wrapper_result;
1022 }
1023 )";
1024
1025 DataMap data;
1026 data.Add<CanonicalizeEntryPointIO::Config>(
1027 CanonicalizeEntryPointIO::ShaderStyle::kMsl);
1028 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1029
1030 EXPECT_EQ(expect, str(got));
1031 }
1032
TEST_F(CanonicalizeEntryPointIOTest,InterpolateAttributes)1033 TEST_F(CanonicalizeEntryPointIOTest, InterpolateAttributes) {
1034 auto* src = R"(
1035 struct VertexOut {
1036 [[builtin(position)]] pos : vec4<f32>;
1037 [[location(1), interpolate(flat)]] loc1: f32;
1038 [[location(2), interpolate(linear, sample)]] loc2 : f32;
1039 [[location(3), interpolate(perspective, centroid)]] loc3 : f32;
1040 };
1041
1042 struct FragmentIn {
1043 [[location(1), interpolate(flat)]] loc1: f32;
1044 [[location(2), interpolate(linear, sample)]] loc2 : f32;
1045 };
1046
1047 [[stage(vertex)]]
1048 fn vert_main() -> VertexOut {
1049 return VertexOut();
1050 }
1051
1052 [[stage(fragment)]]
1053 fn frag_main(inputs : FragmentIn,
1054 [[location(3), interpolate(perspective, centroid)]] loc3 : f32) {
1055 let x = inputs.loc1 + inputs.loc2 + loc3;
1056 }
1057 )";
1058
1059 auto* expect = R"(
1060 struct VertexOut {
1061 pos : vec4<f32>;
1062 loc1 : f32;
1063 loc2 : f32;
1064 loc3 : f32;
1065 };
1066
1067 struct FragmentIn {
1068 loc1 : f32;
1069 loc2 : f32;
1070 };
1071
1072 struct tint_symbol {
1073 [[location(1), interpolate(flat)]]
1074 loc1 : f32;
1075 [[location(2), interpolate(linear, sample)]]
1076 loc2 : f32;
1077 [[location(3), interpolate(perspective, centroid)]]
1078 loc3 : f32;
1079 [[builtin(position)]]
1080 pos : vec4<f32>;
1081 };
1082
1083 fn vert_main_inner() -> VertexOut {
1084 return VertexOut();
1085 }
1086
1087 [[stage(vertex)]]
1088 fn vert_main() -> tint_symbol {
1089 let inner_result = vert_main_inner();
1090 var wrapper_result : tint_symbol;
1091 wrapper_result.pos = inner_result.pos;
1092 wrapper_result.loc1 = inner_result.loc1;
1093 wrapper_result.loc2 = inner_result.loc2;
1094 wrapper_result.loc3 = inner_result.loc3;
1095 return wrapper_result;
1096 }
1097
1098 struct tint_symbol_2 {
1099 [[location(1), interpolate(flat)]]
1100 loc1 : f32;
1101 [[location(2), interpolate(linear, sample)]]
1102 loc2 : f32;
1103 [[location(3), interpolate(perspective, centroid)]]
1104 loc3 : f32;
1105 };
1106
1107 fn frag_main_inner(inputs : FragmentIn, loc3 : f32) {
1108 let x = ((inputs.loc1 + inputs.loc2) + loc3);
1109 }
1110
1111 [[stage(fragment)]]
1112 fn frag_main(tint_symbol_1 : tint_symbol_2) {
1113 frag_main_inner(FragmentIn(tint_symbol_1.loc1, tint_symbol_1.loc2), tint_symbol_1.loc3);
1114 }
1115 )";
1116
1117 DataMap data;
1118 data.Add<CanonicalizeEntryPointIO::Config>(
1119 CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
1120 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1121
1122 EXPECT_EQ(expect, str(got));
1123 }
1124
TEST_F(CanonicalizeEntryPointIOTest,InterpolateAttributes_Integers_Spirv)1125 TEST_F(CanonicalizeEntryPointIOTest, InterpolateAttributes_Integers_Spirv) {
1126 // Test that we add a Flat attribute to integers that are vertex outputs and
1127 // fragment inputs, but not vertex inputs or fragment outputs.
1128 auto* src = R"(
1129 struct VertexIn {
1130 [[location(0)]] i : i32;
1131 [[location(1)]] u : u32;
1132 [[location(2)]] vi : vec4<i32>;
1133 [[location(3)]] vu : vec4<u32>;
1134 };
1135
1136 struct VertexOut {
1137 [[location(0)]] i : i32;
1138 [[location(1)]] u : u32;
1139 [[location(2)]] vi : vec4<i32>;
1140 [[location(3)]] vu : vec4<u32>;
1141 [[builtin(position)]] pos : vec4<f32>;
1142 };
1143
1144 struct FragmentInterface {
1145 [[location(0)]] i : i32;
1146 [[location(1)]] u : u32;
1147 [[location(2)]] vi : vec4<i32>;
1148 [[location(3)]] vu : vec4<u32>;
1149 };
1150
1151 [[stage(vertex)]]
1152 fn vert_main(in : VertexIn) -> VertexOut {
1153 return VertexOut(in.i, in.u, in.vi, in.vu, vec4<f32>());
1154 }
1155
1156 [[stage(fragment)]]
1157 fn frag_main(inputs : FragmentInterface) -> FragmentInterface {
1158 return inputs;
1159 }
1160 )";
1161
1162 auto* expect =
1163 R"(
1164 [[location(0), internal(disable_validation__ignore_storage_class)]] var<in> i_1 : i32;
1165
1166 [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> u_1 : u32;
1167
1168 [[location(2), internal(disable_validation__ignore_storage_class)]] var<in> vi_1 : vec4<i32>;
1169
1170 [[location(3), internal(disable_validation__ignore_storage_class)]] var<in> vu_1 : vec4<u32>;
1171
1172 [[location(0), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<out> i_2 : i32;
1173
1174 [[location(1), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<out> u_2 : u32;
1175
1176 [[location(2), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<out> vi_2 : vec4<i32>;
1177
1178 [[location(3), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<out> vu_2 : vec4<u32>;
1179
1180 [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> pos_1 : vec4<f32>;
1181
1182 [[location(0), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<in> i_3 : i32;
1183
1184 [[location(1), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<in> u_3 : u32;
1185
1186 [[location(2), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<in> vi_3 : vec4<i32>;
1187
1188 [[location(3), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<in> vu_3 : vec4<u32>;
1189
1190 [[location(0), internal(disable_validation__ignore_storage_class)]] var<out> i_4 : i32;
1191
1192 [[location(1), internal(disable_validation__ignore_storage_class)]] var<out> u_4 : u32;
1193
1194 [[location(2), internal(disable_validation__ignore_storage_class)]] var<out> vi_4 : vec4<i32>;
1195
1196 [[location(3), internal(disable_validation__ignore_storage_class)]] var<out> vu_4 : vec4<u32>;
1197
1198 struct VertexIn {
1199 i : i32;
1200 u : u32;
1201 vi : vec4<i32>;
1202 vu : vec4<u32>;
1203 };
1204
1205 struct VertexOut {
1206 i : i32;
1207 u : u32;
1208 vi : vec4<i32>;
1209 vu : vec4<u32>;
1210 pos : vec4<f32>;
1211 };
1212
1213 struct FragmentInterface {
1214 i : i32;
1215 u : u32;
1216 vi : vec4<i32>;
1217 vu : vec4<u32>;
1218 };
1219
1220 fn vert_main_inner(in : VertexIn) -> VertexOut {
1221 return VertexOut(in.i, in.u, in.vi, in.vu, vec4<f32>());
1222 }
1223
1224 [[stage(vertex)]]
1225 fn vert_main() {
1226 let inner_result = vert_main_inner(VertexIn(i_1, u_1, vi_1, vu_1));
1227 i_2 = inner_result.i;
1228 u_2 = inner_result.u;
1229 vi_2 = inner_result.vi;
1230 vu_2 = inner_result.vu;
1231 pos_1 = inner_result.pos;
1232 }
1233
1234 fn frag_main_inner(inputs : FragmentInterface) -> FragmentInterface {
1235 return inputs;
1236 }
1237
1238 [[stage(fragment)]]
1239 fn frag_main() {
1240 let inner_result_1 = frag_main_inner(FragmentInterface(i_3, u_3, vi_3, vu_3));
1241 i_4 = inner_result_1.i;
1242 u_4 = inner_result_1.u;
1243 vi_4 = inner_result_1.vi;
1244 vu_4 = inner_result_1.vu;
1245 }
1246 )";
1247
1248 DataMap data;
1249 data.Add<CanonicalizeEntryPointIO::Config>(
1250 CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
1251 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1252
1253 EXPECT_EQ(expect, str(got));
1254 }
1255
TEST_F(CanonicalizeEntryPointIOTest,InvariantAttributes)1256 TEST_F(CanonicalizeEntryPointIOTest, InvariantAttributes) {
1257 auto* src = R"(
1258 struct VertexOut {
1259 [[builtin(position), invariant]] pos : vec4<f32>;
1260 };
1261
1262 [[stage(vertex)]]
1263 fn main1() -> VertexOut {
1264 return VertexOut();
1265 }
1266
1267 [[stage(vertex)]]
1268 fn main2() -> [[builtin(position), invariant]] vec4<f32> {
1269 return vec4<f32>();
1270 }
1271 )";
1272
1273 auto* expect = R"(
1274 struct VertexOut {
1275 pos : vec4<f32>;
1276 };
1277
1278 struct tint_symbol {
1279 [[builtin(position), invariant]]
1280 pos : vec4<f32>;
1281 };
1282
1283 fn main1_inner() -> VertexOut {
1284 return VertexOut();
1285 }
1286
1287 [[stage(vertex)]]
1288 fn main1() -> tint_symbol {
1289 let inner_result = main1_inner();
1290 var wrapper_result : tint_symbol;
1291 wrapper_result.pos = inner_result.pos;
1292 return wrapper_result;
1293 }
1294
1295 struct tint_symbol_1 {
1296 [[builtin(position), invariant]]
1297 value : vec4<f32>;
1298 };
1299
1300 fn main2_inner() -> vec4<f32> {
1301 return vec4<f32>();
1302 }
1303
1304 [[stage(vertex)]]
1305 fn main2() -> tint_symbol_1 {
1306 let inner_result_1 = main2_inner();
1307 var wrapper_result_1 : tint_symbol_1;
1308 wrapper_result_1.value = inner_result_1;
1309 return wrapper_result_1;
1310 }
1311 )";
1312
1313 DataMap data;
1314 data.Add<CanonicalizeEntryPointIO::Config>(
1315 CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
1316 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1317
1318 EXPECT_EQ(expect, str(got));
1319 }
1320
TEST_F(CanonicalizeEntryPointIOTest,Struct_LayoutDecorations)1321 TEST_F(CanonicalizeEntryPointIOTest, Struct_LayoutDecorations) {
1322 auto* src = R"(
1323 [[block]]
1324 struct FragmentInput {
1325 [[size(16), location(1)]] value : f32;
1326 [[builtin(position)]] [[align(32)]] coord : vec4<f32>;
1327 [[location(0), interpolate(linear, sample)]] [[align(128)]] loc0 : f32;
1328 };
1329
1330 struct FragmentOutput {
1331 [[size(16), location(1), interpolate(flat)]] value : f32;
1332 };
1333
1334 [[stage(fragment)]]
1335 fn frag_main(inputs : FragmentInput) -> FragmentOutput {
1336 return FragmentOutput(inputs.coord.x * inputs.value + inputs.loc0);
1337 }
1338 )";
1339
1340 auto* expect = R"(
1341 [[block]]
1342 struct FragmentInput {
1343 [[size(16)]]
1344 value : f32;
1345 [[align(32)]]
1346 coord : vec4<f32>;
1347 [[align(128)]]
1348 loc0 : f32;
1349 };
1350
1351 struct FragmentOutput {
1352 [[size(16)]]
1353 value : f32;
1354 };
1355
1356 struct tint_symbol_1 {
1357 [[location(0), interpolate(linear, sample)]]
1358 loc0 : f32;
1359 [[location(1)]]
1360 value : f32;
1361 [[builtin(position)]]
1362 coord : vec4<f32>;
1363 };
1364
1365 struct tint_symbol_2 {
1366 [[location(1), interpolate(flat)]]
1367 value : f32;
1368 };
1369
1370 fn frag_main_inner(inputs : FragmentInput) -> FragmentOutput {
1371 return FragmentOutput(((inputs.coord.x * inputs.value) + inputs.loc0));
1372 }
1373
1374 [[stage(fragment)]]
1375 fn frag_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
1376 let inner_result = frag_main_inner(FragmentInput(tint_symbol.value, tint_symbol.coord, tint_symbol.loc0));
1377 var wrapper_result : tint_symbol_2;
1378 wrapper_result.value = inner_result.value;
1379 return wrapper_result;
1380 }
1381 )";
1382
1383 DataMap data;
1384 data.Add<CanonicalizeEntryPointIO::Config>(
1385 CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
1386 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1387
1388 EXPECT_EQ(expect, str(got));
1389 }
1390
TEST_F(CanonicalizeEntryPointIOTest,SortedMembers)1391 TEST_F(CanonicalizeEntryPointIOTest, SortedMembers) {
1392 auto* src = R"(
1393 struct VertexOutput {
1394 [[location(1)]] b : u32;
1395 [[builtin(position)]] pos : vec4<f32>;
1396 [[location(3)]] d : u32;
1397 [[location(0)]] a : f32;
1398 [[location(2)]] c : i32;
1399 };
1400
1401 struct FragmentInputExtra {
1402 [[location(3)]] d : u32;
1403 [[builtin(position)]] pos : vec4<f32>;
1404 [[location(0)]] a : f32;
1405 };
1406
1407 [[stage(vertex)]]
1408 fn vert_main() -> VertexOutput {
1409 return VertexOutput();
1410 }
1411
1412 [[stage(fragment)]]
1413 fn frag_main([[builtin(front_facing)]] ff : bool,
1414 [[location(2)]] c : i32,
1415 inputs : FragmentInputExtra,
1416 [[location(1)]] b : u32) {
1417 }
1418 )";
1419
1420 auto* expect = R"(
1421 struct VertexOutput {
1422 b : u32;
1423 pos : vec4<f32>;
1424 d : u32;
1425 a : f32;
1426 c : i32;
1427 };
1428
1429 struct FragmentInputExtra {
1430 d : u32;
1431 pos : vec4<f32>;
1432 a : f32;
1433 };
1434
1435 struct tint_symbol {
1436 [[location(0)]]
1437 a : f32;
1438 [[location(1)]]
1439 b : u32;
1440 [[location(2)]]
1441 c : i32;
1442 [[location(3)]]
1443 d : u32;
1444 [[builtin(position)]]
1445 pos : vec4<f32>;
1446 };
1447
1448 fn vert_main_inner() -> VertexOutput {
1449 return VertexOutput();
1450 }
1451
1452 [[stage(vertex)]]
1453 fn vert_main() -> tint_symbol {
1454 let inner_result = vert_main_inner();
1455 var wrapper_result : tint_symbol;
1456 wrapper_result.b = inner_result.b;
1457 wrapper_result.pos = inner_result.pos;
1458 wrapper_result.d = inner_result.d;
1459 wrapper_result.a = inner_result.a;
1460 wrapper_result.c = inner_result.c;
1461 return wrapper_result;
1462 }
1463
1464 struct tint_symbol_2 {
1465 [[location(0)]]
1466 a : f32;
1467 [[location(1)]]
1468 b : u32;
1469 [[location(2)]]
1470 c : i32;
1471 [[location(3)]]
1472 d : u32;
1473 [[builtin(position)]]
1474 pos : vec4<f32>;
1475 [[builtin(front_facing)]]
1476 ff : bool;
1477 };
1478
1479 fn frag_main_inner(ff : bool, c : i32, inputs : FragmentInputExtra, b : u32) {
1480 }
1481
1482 [[stage(fragment)]]
1483 fn frag_main(tint_symbol_1 : tint_symbol_2) {
1484 frag_main_inner(tint_symbol_1.ff, tint_symbol_1.c, FragmentInputExtra(tint_symbol_1.d, tint_symbol_1.pos, tint_symbol_1.a), tint_symbol_1.b);
1485 }
1486 )";
1487
1488 DataMap data;
1489 data.Add<CanonicalizeEntryPointIO::Config>(
1490 CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
1491 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1492
1493 EXPECT_EQ(expect, str(got));
1494 }
1495
TEST_F(CanonicalizeEntryPointIOTest,DontRenameSymbols)1496 TEST_F(CanonicalizeEntryPointIOTest, DontRenameSymbols) {
1497 auto* src = R"(
1498 [[stage(fragment)]]
1499 fn tint_symbol_1([[location(0)]] col : f32) {
1500 }
1501 )";
1502
1503 auto* expect = R"(
1504 struct tint_symbol_2 {
1505 [[location(0)]]
1506 col : f32;
1507 };
1508
1509 fn tint_symbol_1_inner(col : f32) {
1510 }
1511
1512 [[stage(fragment)]]
1513 fn tint_symbol_1(tint_symbol : tint_symbol_2) {
1514 tint_symbol_1_inner(tint_symbol.col);
1515 }
1516 )";
1517
1518 DataMap data;
1519 data.Add<CanonicalizeEntryPointIO::Config>(
1520 CanonicalizeEntryPointIO::ShaderStyle::kMsl);
1521 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1522
1523 EXPECT_EQ(expect, str(got));
1524 }
1525
TEST_F(CanonicalizeEntryPointIOTest,FixedSampleMask_VoidNoReturn)1526 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_VoidNoReturn) {
1527 auto* src = R"(
1528 [[stage(fragment)]]
1529 fn frag_main() {
1530 }
1531 )";
1532
1533 auto* expect = R"(
1534 struct tint_symbol {
1535 [[builtin(sample_mask)]]
1536 fixed_sample_mask : u32;
1537 };
1538
1539 fn frag_main_inner() {
1540 }
1541
1542 [[stage(fragment)]]
1543 fn frag_main() -> tint_symbol {
1544 frag_main_inner();
1545 var wrapper_result : tint_symbol;
1546 wrapper_result.fixed_sample_mask = 3u;
1547 return wrapper_result;
1548 }
1549 )";
1550
1551 DataMap data;
1552 data.Add<CanonicalizeEntryPointIO::Config>(
1553 CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
1554 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1555
1556 EXPECT_EQ(expect, str(got));
1557 }
1558
TEST_F(CanonicalizeEntryPointIOTest,FixedSampleMask_VoidWithReturn)1559 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_VoidWithReturn) {
1560 auto* src = R"(
1561 [[stage(fragment)]]
1562 fn frag_main() {
1563 return;
1564 }
1565 )";
1566
1567 auto* expect = R"(
1568 struct tint_symbol {
1569 [[builtin(sample_mask)]]
1570 fixed_sample_mask : u32;
1571 };
1572
1573 fn frag_main_inner() {
1574 return;
1575 }
1576
1577 [[stage(fragment)]]
1578 fn frag_main() -> tint_symbol {
1579 frag_main_inner();
1580 var wrapper_result : tint_symbol;
1581 wrapper_result.fixed_sample_mask = 3u;
1582 return wrapper_result;
1583 }
1584 )";
1585
1586 DataMap data;
1587 data.Add<CanonicalizeEntryPointIO::Config>(
1588 CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
1589 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1590
1591 EXPECT_EQ(expect, str(got));
1592 }
1593
TEST_F(CanonicalizeEntryPointIOTest,FixedSampleMask_WithAuthoredMask)1594 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_WithAuthoredMask) {
1595 auto* src = R"(
1596 [[stage(fragment)]]
1597 fn frag_main() -> [[builtin(sample_mask)]] u32 {
1598 return 7u;
1599 }
1600 )";
1601
1602 auto* expect = R"(
1603 struct tint_symbol {
1604 [[builtin(sample_mask)]]
1605 value : u32;
1606 };
1607
1608 fn frag_main_inner() -> u32 {
1609 return 7u;
1610 }
1611
1612 [[stage(fragment)]]
1613 fn frag_main() -> tint_symbol {
1614 let inner_result = frag_main_inner();
1615 var wrapper_result : tint_symbol;
1616 wrapper_result.value = (inner_result & 3u);
1617 return wrapper_result;
1618 }
1619 )";
1620
1621 DataMap data;
1622 data.Add<CanonicalizeEntryPointIO::Config>(
1623 CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
1624 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1625
1626 EXPECT_EQ(expect, str(got));
1627 }
1628
TEST_F(CanonicalizeEntryPointIOTest,FixedSampleMask_WithoutAuthoredMask)1629 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_WithoutAuthoredMask) {
1630 auto* src = R"(
1631 [[stage(fragment)]]
1632 fn frag_main() -> [[location(0)]] f32 {
1633 return 1.0;
1634 }
1635 )";
1636
1637 auto* expect = R"(
1638 struct tint_symbol {
1639 [[location(0)]]
1640 value : f32;
1641 [[builtin(sample_mask)]]
1642 fixed_sample_mask : u32;
1643 };
1644
1645 fn frag_main_inner() -> f32 {
1646 return 1.0;
1647 }
1648
1649 [[stage(fragment)]]
1650 fn frag_main() -> tint_symbol {
1651 let inner_result = frag_main_inner();
1652 var wrapper_result : tint_symbol;
1653 wrapper_result.value = inner_result;
1654 wrapper_result.fixed_sample_mask = 3u;
1655 return wrapper_result;
1656 }
1657 )";
1658
1659 DataMap data;
1660 data.Add<CanonicalizeEntryPointIO::Config>(
1661 CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
1662 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1663
1664 EXPECT_EQ(expect, str(got));
1665 }
1666
TEST_F(CanonicalizeEntryPointIOTest,FixedSampleMask_StructWithAuthoredMask)1667 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_StructWithAuthoredMask) {
1668 auto* src = R"(
1669 struct Output {
1670 [[builtin(frag_depth)]] depth : f32;
1671 [[builtin(sample_mask)]] mask : u32;
1672 [[location(0)]] value : f32;
1673 };
1674
1675 [[stage(fragment)]]
1676 fn frag_main() -> Output {
1677 return Output(0.5, 7u, 1.0);
1678 }
1679 )";
1680
1681 auto* expect = R"(
1682 struct Output {
1683 depth : f32;
1684 mask : u32;
1685 value : f32;
1686 };
1687
1688 struct tint_symbol {
1689 [[location(0)]]
1690 value : f32;
1691 [[builtin(frag_depth)]]
1692 depth : f32;
1693 [[builtin(sample_mask)]]
1694 mask : u32;
1695 };
1696
1697 fn frag_main_inner() -> Output {
1698 return Output(0.5, 7u, 1.0);
1699 }
1700
1701 [[stage(fragment)]]
1702 fn frag_main() -> tint_symbol {
1703 let inner_result = frag_main_inner();
1704 var wrapper_result : tint_symbol;
1705 wrapper_result.depth = inner_result.depth;
1706 wrapper_result.mask = (inner_result.mask & 3u);
1707 wrapper_result.value = inner_result.value;
1708 return wrapper_result;
1709 }
1710 )";
1711
1712 DataMap data;
1713 data.Add<CanonicalizeEntryPointIO::Config>(
1714 CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
1715 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1716
1717 EXPECT_EQ(expect, str(got));
1718 }
1719
TEST_F(CanonicalizeEntryPointIOTest,FixedSampleMask_StructWithoutAuthoredMask)1720 TEST_F(CanonicalizeEntryPointIOTest,
1721 FixedSampleMask_StructWithoutAuthoredMask) {
1722 auto* src = R"(
1723 struct Output {
1724 [[builtin(frag_depth)]] depth : f32;
1725 [[location(0)]] value : f32;
1726 };
1727
1728 [[stage(fragment)]]
1729 fn frag_main() -> Output {
1730 return Output(0.5, 1.0);
1731 }
1732 )";
1733
1734 auto* expect = R"(
1735 struct Output {
1736 depth : f32;
1737 value : f32;
1738 };
1739
1740 struct tint_symbol {
1741 [[location(0)]]
1742 value : f32;
1743 [[builtin(frag_depth)]]
1744 depth : f32;
1745 [[builtin(sample_mask)]]
1746 fixed_sample_mask : u32;
1747 };
1748
1749 fn frag_main_inner() -> Output {
1750 return Output(0.5, 1.0);
1751 }
1752
1753 [[stage(fragment)]]
1754 fn frag_main() -> tint_symbol {
1755 let inner_result = frag_main_inner();
1756 var wrapper_result : tint_symbol;
1757 wrapper_result.depth = inner_result.depth;
1758 wrapper_result.value = inner_result.value;
1759 wrapper_result.fixed_sample_mask = 3u;
1760 return wrapper_result;
1761 }
1762 )";
1763
1764 DataMap data;
1765 data.Add<CanonicalizeEntryPointIO::Config>(
1766 CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
1767 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1768
1769 EXPECT_EQ(expect, str(got));
1770 }
1771
TEST_F(CanonicalizeEntryPointIOTest,FixedSampleMask_MultipleShaders)1772 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_MultipleShaders) {
1773 auto* src = R"(
1774 [[stage(fragment)]]
1775 fn frag_main1() -> [[builtin(sample_mask)]] u32 {
1776 return 7u;
1777 }
1778
1779 [[stage(fragment)]]
1780 fn frag_main2() -> [[location(0)]] f32 {
1781 return 1.0;
1782 }
1783
1784 [[stage(vertex)]]
1785 fn vert_main1() -> [[builtin(position)]] vec4<f32> {
1786 return vec4<f32>();
1787 }
1788
1789 [[stage(compute), workgroup_size(1)]]
1790 fn comp_main1() {
1791 }
1792 )";
1793
1794 auto* expect = R"(
1795 struct tint_symbol {
1796 [[builtin(sample_mask)]]
1797 value : u32;
1798 };
1799
1800 fn frag_main1_inner() -> u32 {
1801 return 7u;
1802 }
1803
1804 [[stage(fragment)]]
1805 fn frag_main1() -> tint_symbol {
1806 let inner_result = frag_main1_inner();
1807 var wrapper_result : tint_symbol;
1808 wrapper_result.value = (inner_result & 3u);
1809 return wrapper_result;
1810 }
1811
1812 struct tint_symbol_1 {
1813 [[location(0)]]
1814 value : f32;
1815 [[builtin(sample_mask)]]
1816 fixed_sample_mask : u32;
1817 };
1818
1819 fn frag_main2_inner() -> f32 {
1820 return 1.0;
1821 }
1822
1823 [[stage(fragment)]]
1824 fn frag_main2() -> tint_symbol_1 {
1825 let inner_result_1 = frag_main2_inner();
1826 var wrapper_result_1 : tint_symbol_1;
1827 wrapper_result_1.value = inner_result_1;
1828 wrapper_result_1.fixed_sample_mask = 3u;
1829 return wrapper_result_1;
1830 }
1831
1832 struct tint_symbol_2 {
1833 [[builtin(position)]]
1834 value : vec4<f32>;
1835 };
1836
1837 fn vert_main1_inner() -> vec4<f32> {
1838 return vec4<f32>();
1839 }
1840
1841 [[stage(vertex)]]
1842 fn vert_main1() -> tint_symbol_2 {
1843 let inner_result_2 = vert_main1_inner();
1844 var wrapper_result_2 : tint_symbol_2;
1845 wrapper_result_2.value = inner_result_2;
1846 return wrapper_result_2;
1847 }
1848
1849 [[stage(compute), workgroup_size(1)]]
1850 fn comp_main1() {
1851 }
1852 )";
1853
1854 DataMap data;
1855 data.Add<CanonicalizeEntryPointIO::Config>(
1856 CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
1857 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1858
1859 EXPECT_EQ(expect, str(got));
1860 }
1861
TEST_F(CanonicalizeEntryPointIOTest,FixedSampleMask_AvoidNameClash)1862 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_AvoidNameClash) {
1863 auto* src = R"(
1864 struct FragOut {
1865 [[location(0)]] fixed_sample_mask : vec4<f32>;
1866 [[location(1)]] fixed_sample_mask_1 : vec4<f32>;
1867 };
1868
1869 [[stage(fragment)]]
1870 fn frag_main() -> FragOut {
1871 return FragOut();
1872 }
1873 )";
1874
1875 auto* expect = R"(
1876 struct FragOut {
1877 fixed_sample_mask : vec4<f32>;
1878 fixed_sample_mask_1 : vec4<f32>;
1879 };
1880
1881 struct tint_symbol {
1882 [[location(0)]]
1883 fixed_sample_mask : vec4<f32>;
1884 [[location(1)]]
1885 fixed_sample_mask_1 : vec4<f32>;
1886 [[builtin(sample_mask)]]
1887 fixed_sample_mask_2 : u32;
1888 };
1889
1890 fn frag_main_inner() -> FragOut {
1891 return FragOut();
1892 }
1893
1894 [[stage(fragment)]]
1895 fn frag_main() -> tint_symbol {
1896 let inner_result = frag_main_inner();
1897 var wrapper_result : tint_symbol;
1898 wrapper_result.fixed_sample_mask = inner_result.fixed_sample_mask;
1899 wrapper_result.fixed_sample_mask_1 = inner_result.fixed_sample_mask_1;
1900 wrapper_result.fixed_sample_mask_2 = 3u;
1901 return wrapper_result;
1902 }
1903 )";
1904
1905 DataMap data;
1906 data.Add<CanonicalizeEntryPointIO::Config>(
1907 CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03);
1908 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1909
1910 EXPECT_EQ(expect, str(got));
1911 }
1912
TEST_F(CanonicalizeEntryPointIOTest,EmitVertexPointSize_ReturnNonStruct_Spirv)1913 TEST_F(CanonicalizeEntryPointIOTest,
1914 EmitVertexPointSize_ReturnNonStruct_Spirv) {
1915 auto* src = R"(
1916 [[stage(vertex)]]
1917 fn vert_main() -> [[builtin(position)]] vec4<f32> {
1918 return vec4<f32>();
1919 }
1920 )";
1921
1922 auto* expect = R"(
1923 [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> value : vec4<f32>;
1924
1925 [[builtin(pointsize), internal(disable_validation__ignore_storage_class)]] var<out> vertex_point_size : f32;
1926
1927 fn vert_main_inner() -> vec4<f32> {
1928 return vec4<f32>();
1929 }
1930
1931 [[stage(vertex)]]
1932 fn vert_main() {
1933 let inner_result = vert_main_inner();
1934 value = inner_result;
1935 vertex_point_size = 1.0;
1936 }
1937 )";
1938
1939 DataMap data;
1940 data.Add<CanonicalizeEntryPointIO::Config>(
1941 CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF, true);
1942 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1943
1944 EXPECT_EQ(expect, str(got));
1945 }
1946
TEST_F(CanonicalizeEntryPointIOTest,EmitVertexPointSize_ReturnNonStruct_Msl)1947 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_ReturnNonStruct_Msl) {
1948 auto* src = R"(
1949 [[stage(vertex)]]
1950 fn vert_main() -> [[builtin(position)]] vec4<f32> {
1951 return vec4<f32>();
1952 }
1953 )";
1954
1955 auto* expect = R"(
1956 struct tint_symbol {
1957 [[builtin(position)]]
1958 value : vec4<f32>;
1959 [[builtin(pointsize)]]
1960 vertex_point_size : f32;
1961 };
1962
1963 fn vert_main_inner() -> vec4<f32> {
1964 return vec4<f32>();
1965 }
1966
1967 [[stage(vertex)]]
1968 fn vert_main() -> tint_symbol {
1969 let inner_result = vert_main_inner();
1970 var wrapper_result : tint_symbol;
1971 wrapper_result.value = inner_result;
1972 wrapper_result.vertex_point_size = 1.0;
1973 return wrapper_result;
1974 }
1975 )";
1976
1977 DataMap data;
1978 data.Add<CanonicalizeEntryPointIO::Config>(
1979 CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0xFFFFFFFF, true);
1980 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
1981
1982 EXPECT_EQ(expect, str(got));
1983 }
1984
TEST_F(CanonicalizeEntryPointIOTest,EmitVertexPointSize_ReturnStruct_Spirv)1985 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_ReturnStruct_Spirv) {
1986 auto* src = R"(
1987 struct VertOut {
1988 [[builtin(position)]] pos : vec4<f32>;
1989 };
1990
1991 [[stage(vertex)]]
1992 fn vert_main() -> VertOut {
1993 return VertOut();
1994 }
1995 )";
1996
1997 auto* expect = R"(
1998 [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> pos_1 : vec4<f32>;
1999
2000 [[builtin(pointsize), internal(disable_validation__ignore_storage_class)]] var<out> vertex_point_size : f32;
2001
2002 struct VertOut {
2003 pos : vec4<f32>;
2004 };
2005
2006 fn vert_main_inner() -> VertOut {
2007 return VertOut();
2008 }
2009
2010 [[stage(vertex)]]
2011 fn vert_main() {
2012 let inner_result = vert_main_inner();
2013 pos_1 = inner_result.pos;
2014 vertex_point_size = 1.0;
2015 }
2016 )";
2017
2018 DataMap data;
2019 data.Add<CanonicalizeEntryPointIO::Config>(
2020 CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF, true);
2021 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
2022
2023 EXPECT_EQ(expect, str(got));
2024 }
2025
TEST_F(CanonicalizeEntryPointIOTest,EmitVertexPointSize_ReturnStruct_Msl)2026 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_ReturnStruct_Msl) {
2027 auto* src = R"(
2028 struct VertOut {
2029 [[builtin(position)]] pos : vec4<f32>;
2030 };
2031
2032 [[stage(vertex)]]
2033 fn vert_main() -> VertOut {
2034 return VertOut();
2035 }
2036 )";
2037
2038 auto* expect = R"(
2039 struct VertOut {
2040 pos : vec4<f32>;
2041 };
2042
2043 struct tint_symbol {
2044 [[builtin(position)]]
2045 pos : vec4<f32>;
2046 [[builtin(pointsize)]]
2047 vertex_point_size : f32;
2048 };
2049
2050 fn vert_main_inner() -> VertOut {
2051 return VertOut();
2052 }
2053
2054 [[stage(vertex)]]
2055 fn vert_main() -> tint_symbol {
2056 let inner_result = vert_main_inner();
2057 var wrapper_result : tint_symbol;
2058 wrapper_result.pos = inner_result.pos;
2059 wrapper_result.vertex_point_size = 1.0;
2060 return wrapper_result;
2061 }
2062 )";
2063
2064 DataMap data;
2065 data.Add<CanonicalizeEntryPointIO::Config>(
2066 CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0xFFFFFFFF, true);
2067 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
2068
2069 EXPECT_EQ(expect, str(got));
2070 }
2071
TEST_F(CanonicalizeEntryPointIOTest,EmitVertexPointSize_AvoidNameClash_Spirv)2072 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Spirv) {
2073 auto* src = R"(
2074 var<private> vertex_point_size : f32;
2075 var<private> vertex_point_size_1 : f32;
2076 var<private> vertex_point_size_2 : f32;
2077
2078 struct VertIn1 {
2079 [[location(0)]] collide : f32;
2080 };
2081
2082 struct VertIn2 {
2083 [[location(1)]] collide : f32;
2084 };
2085
2086 struct VertOut {
2087 [[location(0)]] vertex_point_size : f32;
2088 [[builtin(position)]] vertex_point_size_1 : vec4<f32>;
2089 };
2090
2091 [[stage(vertex)]]
2092 fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
2093 let x = collide.collide + collide_1.collide;
2094 return VertOut();
2095 }
2096 )";
2097
2098 auto* expect = R"(
2099 [[location(0), internal(disable_validation__ignore_storage_class)]] var<in> collide_2 : f32;
2100
2101 [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> collide_3 : f32;
2102
2103 [[location(0), internal(disable_validation__ignore_storage_class)]] var<out> vertex_point_size_3 : f32;
2104
2105 [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> vertex_point_size_1_1 : vec4<f32>;
2106
2107 [[builtin(pointsize), internal(disable_validation__ignore_storage_class)]] var<out> vertex_point_size_4 : f32;
2108
2109 var<private> vertex_point_size : f32;
2110
2111 var<private> vertex_point_size_1 : f32;
2112
2113 var<private> vertex_point_size_2 : f32;
2114
2115 struct VertIn1 {
2116 collide : f32;
2117 };
2118
2119 struct VertIn2 {
2120 collide : f32;
2121 };
2122
2123 struct VertOut {
2124 vertex_point_size : f32;
2125 vertex_point_size_1 : vec4<f32>;
2126 };
2127
2128 fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
2129 let x = (collide.collide + collide_1.collide);
2130 return VertOut();
2131 }
2132
2133 [[stage(vertex)]]
2134 fn vert_main() {
2135 let inner_result = vert_main_inner(VertIn1(collide_2), VertIn2(collide_3));
2136 vertex_point_size_3 = inner_result.vertex_point_size;
2137 vertex_point_size_1_1 = inner_result.vertex_point_size_1;
2138 vertex_point_size_4 = 1.0;
2139 }
2140 )";
2141
2142 DataMap data;
2143 data.Add<CanonicalizeEntryPointIO::Config>(
2144 CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF, true);
2145 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
2146
2147 EXPECT_EQ(expect, str(got));
2148 }
2149
TEST_F(CanonicalizeEntryPointIOTest,EmitVertexPointSize_AvoidNameClash_Msl)2150 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Msl) {
2151 auto* src = R"(
2152 struct VertIn1 {
2153 [[location(0)]] collide : f32;
2154 };
2155
2156 struct VertIn2 {
2157 [[location(1)]] collide : f32;
2158 };
2159
2160 struct VertOut {
2161 [[location(0)]] vertex_point_size : vec4<f32>;
2162 [[builtin(position)]] vertex_point_size_1 : vec4<f32>;
2163 };
2164
2165 [[stage(vertex)]]
2166 fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
2167 let x = collide.collide + collide_1.collide;
2168 return VertOut();
2169 }
2170 )";
2171
2172 auto* expect = R"(
2173 struct VertIn1 {
2174 collide : f32;
2175 };
2176
2177 struct VertIn2 {
2178 collide : f32;
2179 };
2180
2181 struct VertOut {
2182 vertex_point_size : vec4<f32>;
2183 vertex_point_size_1 : vec4<f32>;
2184 };
2185
2186 struct tint_symbol_1 {
2187 [[location(0)]]
2188 collide : f32;
2189 [[location(1)]]
2190 collide_2 : f32;
2191 };
2192
2193 struct tint_symbol_2 {
2194 [[location(0)]]
2195 vertex_point_size : vec4<f32>;
2196 [[builtin(position)]]
2197 vertex_point_size_1 : vec4<f32>;
2198 [[builtin(pointsize)]]
2199 vertex_point_size_2 : f32;
2200 };
2201
2202 fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
2203 let x = (collide.collide + collide_1.collide);
2204 return VertOut();
2205 }
2206
2207 [[stage(vertex)]]
2208 fn vert_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
2209 let inner_result = vert_main_inner(VertIn1(tint_symbol.collide), VertIn2(tint_symbol.collide_2));
2210 var wrapper_result : tint_symbol_2;
2211 wrapper_result.vertex_point_size = inner_result.vertex_point_size;
2212 wrapper_result.vertex_point_size_1 = inner_result.vertex_point_size_1;
2213 wrapper_result.vertex_point_size_2 = 1.0;
2214 return wrapper_result;
2215 }
2216 )";
2217
2218 DataMap data;
2219 data.Add<CanonicalizeEntryPointIO::Config>(
2220 CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0xFFFFFFFF, true);
2221 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
2222
2223 EXPECT_EQ(expect, str(got));
2224 }
2225
TEST_F(CanonicalizeEntryPointIOTest,EmitVertexPointSize_AvoidNameClash_Hlsl)2226 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Hlsl) {
2227 auto* src = R"(
2228 struct VertIn1 {
2229 [[location(0)]] collide : f32;
2230 };
2231
2232 struct VertIn2 {
2233 [[location(1)]] collide : f32;
2234 };
2235
2236 struct VertOut {
2237 [[location(0)]] vertex_point_size : vec4<f32>;
2238 [[builtin(position)]] vertex_point_size_1 : vec4<f32>;
2239 };
2240
2241 [[stage(vertex)]]
2242 fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
2243 let x = collide.collide + collide_1.collide;
2244 return VertOut();
2245 }
2246 )";
2247
2248 auto* expect = R"(
2249 struct VertIn1 {
2250 collide : f32;
2251 };
2252
2253 struct VertIn2 {
2254 collide : f32;
2255 };
2256
2257 struct VertOut {
2258 vertex_point_size : vec4<f32>;
2259 vertex_point_size_1 : vec4<f32>;
2260 };
2261
2262 struct tint_symbol_1 {
2263 [[location(0)]]
2264 collide : f32;
2265 [[location(1)]]
2266 collide_2 : f32;
2267 };
2268
2269 struct tint_symbol_2 {
2270 [[location(0)]]
2271 vertex_point_size : vec4<f32>;
2272 [[builtin(position)]]
2273 vertex_point_size_1 : vec4<f32>;
2274 [[builtin(pointsize)]]
2275 vertex_point_size_2 : f32;
2276 };
2277
2278 fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
2279 let x = (collide.collide + collide_1.collide);
2280 return VertOut();
2281 }
2282
2283 [[stage(vertex)]]
2284 fn vert_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
2285 let inner_result = vert_main_inner(VertIn1(tint_symbol.collide), VertIn2(tint_symbol.collide_2));
2286 var wrapper_result : tint_symbol_2;
2287 wrapper_result.vertex_point_size = inner_result.vertex_point_size;
2288 wrapper_result.vertex_point_size_1 = inner_result.vertex_point_size_1;
2289 wrapper_result.vertex_point_size_2 = 1.0;
2290 return wrapper_result;
2291 }
2292 )";
2293
2294 DataMap data;
2295 data.Add<CanonicalizeEntryPointIO::Config>(
2296 CanonicalizeEntryPointIO::ShaderStyle::kHlsl, 0xFFFFFFFF, true);
2297 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
2298
2299 EXPECT_EQ(expect, str(got));
2300 }
2301
TEST_F(CanonicalizeEntryPointIOTest,SpirvSampleMaskBuiltins)2302 TEST_F(CanonicalizeEntryPointIOTest, SpirvSampleMaskBuiltins) {
2303 auto* src = R"(
2304 [[stage(fragment)]]
2305 fn main([[builtin(sample_index)]] sample_index : u32,
2306 [[builtin(sample_mask)]] mask_in : u32
2307 ) -> [[builtin(sample_mask)]] u32 {
2308 return mask_in;
2309 }
2310 )";
2311
2312 auto* expect = R"(
2313 [[builtin(sample_index), internal(disable_validation__ignore_storage_class)]] var<in> sample_index_1 : u32;
2314
2315 [[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<in> mask_in_1 : array<u32, 1>;
2316
2317 [[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<out> value : array<u32, 1>;
2318
2319 fn main_inner(sample_index : u32, mask_in : u32) -> u32 {
2320 return mask_in;
2321 }
2322
2323 [[stage(fragment)]]
2324 fn main() {
2325 let inner_result = main_inner(sample_index_1, mask_in_1[0]);
2326 value[0] = inner_result;
2327 }
2328 )";
2329
2330 DataMap data;
2331 data.Add<CanonicalizeEntryPointIO::Config>(
2332 CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
2333 auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
2334
2335 EXPECT_EQ(expect, str(got));
2336 }
2337
2338 } // namespace
2339 } // namespace transform
2340 } // namespace tint
2341