• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/transform/robustness.h"
16 
17 #include "src/transform/test_helper.h"
18 
19 namespace tint {
20 namespace transform {
21 namespace {
22 
23 using RobustnessTest = TransformTest;
24 
TEST_F(RobustnessTest,Array_Idx_Clamp)25 TEST_F(RobustnessTest, Array_Idx_Clamp) {
26   auto* src = R"(
27 var<private> a : array<f32, 3>;
28 
29 let c : u32 = 1u;
30 
31 fn f() {
32   let b : f32 = a[c];
33 }
34 )";
35 
36   auto* expect = R"(
37 var<private> a : array<f32, 3>;
38 
39 let c : u32 = 1u;
40 
41 fn f() {
42   let b : f32 = a[1u];
43 }
44 )";
45 
46   auto got = Run<Robustness>(src);
47 
48   EXPECT_EQ(expect, str(got));
49 }
50 
TEST_F(RobustnessTest,Array_Idx_Nested_Scalar)51 TEST_F(RobustnessTest, Array_Idx_Nested_Scalar) {
52   auto* src = R"(
53 var<private> a : array<f32, 3>;
54 
55 var<private> b : array<i32, 5>;
56 
57 var<private> i : u32;
58 
59 fn f() {
60   var c : f32 = a[ b[i] ];
61 }
62 )";
63 
64   auto* expect = R"(
65 var<private> a : array<f32, 3>;
66 
67 var<private> b : array<i32, 5>;
68 
69 var<private> i : u32;
70 
71 fn f() {
72   var c : f32 = a[min(u32(b[min(i, 4u)]), 2u)];
73 }
74 )";
75 
76   auto got = Run<Robustness>(src);
77 
78   EXPECT_EQ(expect, str(got));
79 }
80 
TEST_F(RobustnessTest,Array_Idx_Scalar)81 TEST_F(RobustnessTest, Array_Idx_Scalar) {
82   auto* src = R"(
83 var<private> a : array<f32, 3>;
84 
85 fn f() {
86   var b : f32 = a[1];
87 }
88 )";
89 
90   auto* expect = R"(
91 var<private> a : array<f32, 3>;
92 
93 fn f() {
94   var b : f32 = a[1];
95 }
96 )";
97 
98   auto got = Run<Robustness>(src);
99 
100   EXPECT_EQ(expect, str(got));
101 }
102 
TEST_F(RobustnessTest,Array_Idx_Expr)103 TEST_F(RobustnessTest, Array_Idx_Expr) {
104   auto* src = R"(
105 var<private> a : array<f32, 3>;
106 
107 var<private> c : i32;
108 
109 fn f() {
110   var b : f32 = a[c + 2 - 3];
111 }
112 )";
113 
114   auto* expect = R"(
115 var<private> a : array<f32, 3>;
116 
117 var<private> c : i32;
118 
119 fn f() {
120   var b : f32 = a[min(u32(((c + 2) - 3)), 2u)];
121 }
122 )";
123 
124   auto got = Run<Robustness>(src);
125 
126   EXPECT_EQ(expect, str(got));
127 }
128 
TEST_F(RobustnessTest,Array_Idx_Negative)129 TEST_F(RobustnessTest, Array_Idx_Negative) {
130   auto* src = R"(
131 var<private> a : array<f32, 3>;
132 
133 fn f() {
134   var b : f32 = a[-1];
135 }
136 )";
137 
138   auto* expect = R"(
139 var<private> a : array<f32, 3>;
140 
141 fn f() {
142   var b : f32 = a[0];
143 }
144 )";
145 
146   auto got = Run<Robustness>(src);
147 
148   EXPECT_EQ(expect, str(got));
149 }
150 
TEST_F(RobustnessTest,Array_Idx_OutOfBounds)151 TEST_F(RobustnessTest, Array_Idx_OutOfBounds) {
152   auto* src = R"(
153 var<private> a : array<f32, 3>;
154 
155 fn f() {
156   var b : f32 = a[3];
157 }
158 )";
159 
160   auto* expect = R"(
161 var<private> a : array<f32, 3>;
162 
163 fn f() {
164   var b : f32 = a[2];
165 }
166 )";
167 
168   auto got = Run<Robustness>(src);
169 
170   EXPECT_EQ(expect, str(got));
171 }
172 
173 // TODO(crbug.com/tint/1177) - Validation currently forbids arrays larger than
174 // 0xffffffff. If WGSL supports 64-bit indexing, re-enable this test.
TEST_F(RobustnessTest,DISABLED_LargeArrays_Idx)175 TEST_F(RobustnessTest, DISABLED_LargeArrays_Idx) {
176   auto* src = R"(
177 [[block]]
178 struct S {
179   a : array<f32, 0x7fffffff>;
180   b : array<f32>;
181 };
182 [[group(0), binding(0)]] var<storage, read> s : S;
183 
184 fn f() {
185   // Signed
186   var i32_a1 : f32 = s.a[ 0x7ffffffe];
187   var i32_a2 : f32 = s.a[ 1];
188   var i32_a3 : f32 = s.a[ 0];
189   var i32_a4 : f32 = s.a[-1];
190   var i32_a5 : f32 = s.a[-0x7fffffff];
191 
192   var i32_b1 : f32 = s.b[ 0x7ffffffe];
193   var i32_b2 : f32 = s.b[ 1];
194   var i32_b3 : f32 = s.b[ 0];
195   var i32_b4 : f32 = s.b[-1];
196   var i32_b5 : f32 = s.b[-0x7fffffff];
197 
198   // Unsigned
199   var u32_a1 : f32 = s.a[0u];
200   var u32_a2 : f32 = s.a[1u];
201   var u32_a3 : f32 = s.a[0x7ffffffeu];
202   var u32_a4 : f32 = s.a[0x7fffffffu];
203   var u32_a5 : f32 = s.a[0x80000000u];
204   var u32_a6 : f32 = s.a[0xffffffffu];
205 
206   var u32_b1 : f32 = s.b[0u];
207   var u32_b2 : f32 = s.b[1u];
208   var u32_b3 : f32 = s.b[0x7ffffffeu];
209   var u32_b4 : f32 = s.b[0x7fffffffu];
210   var u32_b5 : f32 = s.b[0x80000000u];
211   var u32_b6 : f32 = s.b[0xffffffffu];
212 }
213 )";
214 
215   auto* expect = R"(
216 [[block]]
217 struct S {
218   a : array<f32, 2147483647>;
219   b : array<f32>;
220 };
221 
222 [[group(0), binding(0)]] var<storage, read> s : S;
223 
224 fn f() {
225   var i32_a1 : f32 = s.a[2147483646];
226   var i32_a2 : f32 = s.a[1];
227   var i32_a3 : f32 = s.a[0];
228   var i32_a4 : f32 = s.a[0];
229   var i32_a5 : f32 = s.a[0];
230   var i32_b1 : f32 = s.b[min(2147483646u, (arrayLength(&(s.b)) - 1u))];
231   var i32_b2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
232   var i32_b3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
233   var i32_b4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
234   var i32_b5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
235   var u32_a1 : f32 = s.a[0u];
236   var u32_a2 : f32 = s.a[1u];
237   var u32_a3 : f32 = s.a[2147483646u];
238   var u32_a4 : f32 = s.a[2147483646u];
239   var u32_a5 : f32 = s.a[2147483646u];
240   var u32_a6 : f32 = s.a[2147483646u];
241   var u32_b1 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
242   var u32_b2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
243   var u32_b3 : f32 = s.b[min(2147483646u, (arrayLength(&(s.b)) - 1u))];
244   var u32_b4 : f32 = s.b[min(2147483647u, (arrayLength(&(s.b)) - 1u))];
245   var u32_b5 : f32 = s.b[min(2147483648u, (arrayLength(&(s.b)) - 1u))];
246   var u32_b6 : f32 = s.b[min(4294967295u, (arrayLength(&(s.b)) - 1u))];
247 }
248 )";
249 
250   auto got = Run<Robustness>(src);
251 
252   EXPECT_EQ(expect, str(got));
253 }
254 
TEST_F(RobustnessTest,Vector_Idx_Scalar)255 TEST_F(RobustnessTest, Vector_Idx_Scalar) {
256   auto* src = R"(
257 var<private> a : vec3<f32>;
258 
259 fn f() {
260   var b : f32 = a[1];
261 }
262 )";
263 
264   auto* expect = R"(
265 var<private> a : vec3<f32>;
266 
267 fn f() {
268   var b : f32 = a[1];
269 }
270 )";
271 
272   auto got = Run<Robustness>(src);
273 
274   EXPECT_EQ(expect, str(got));
275 }
276 
TEST_F(RobustnessTest,Vector_Idx_Expr)277 TEST_F(RobustnessTest, Vector_Idx_Expr) {
278   auto* src = R"(
279 var<private> a : vec3<f32>;
280 
281 var<private> c : i32;
282 
283 fn f() {
284   var b : f32 = a[c + 2 - 3];
285 }
286 )";
287 
288   auto* expect = R"(
289 var<private> a : vec3<f32>;
290 
291 var<private> c : i32;
292 
293 fn f() {
294   var b : f32 = a[min(u32(((c + 2) - 3)), 2u)];
295 }
296 )";
297 
298   auto got = Run<Robustness>(src);
299 
300   EXPECT_EQ(expect, str(got));
301 }
302 
TEST_F(RobustnessTest,Vector_Swizzle_Idx_Scalar)303 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Scalar) {
304   auto* src = R"(
305 var<private> a : vec3<f32>;
306 
307 fn f() {
308   var b : f32 = a.xy[2];
309 }
310 )";
311 
312   auto* expect = R"(
313 var<private> a : vec3<f32>;
314 
315 fn f() {
316   var b : f32 = a.xy[1];
317 }
318 )";
319 
320   auto got = Run<Robustness>(src);
321 
322   EXPECT_EQ(expect, str(got));
323 }
324 
TEST_F(RobustnessTest,Vector_Swizzle_Idx_Var)325 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Var) {
326   auto* src = R"(
327 var<private> a : vec3<f32>;
328 
329 var<private> c : i32;
330 
331 fn f() {
332   var b : f32 = a.xy[c];
333 }
334 )";
335 
336   auto* expect = R"(
337 var<private> a : vec3<f32>;
338 
339 var<private> c : i32;
340 
341 fn f() {
342   var b : f32 = a.xy[min(u32(c), 1u)];
343 }
344 )";
345 
346   auto got = Run<Robustness>(src);
347 
348   EXPECT_EQ(expect, str(got));
349 }
TEST_F(RobustnessTest,Vector_Swizzle_Idx_Expr)350 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Expr) {
351   auto* src = R"(
352 var<private> a : vec3<f32>;
353 
354 var<private> c : i32;
355 
356 fn f() {
357   var b : f32 = a.xy[c + 2 - 3];
358 }
359 )";
360 
361   auto* expect = R"(
362 var<private> a : vec3<f32>;
363 
364 var<private> c : i32;
365 
366 fn f() {
367   var b : f32 = a.xy[min(u32(((c + 2) - 3)), 1u)];
368 }
369 )";
370 
371   auto got = Run<Robustness>(src);
372 
373   EXPECT_EQ(expect, str(got));
374 }
375 
TEST_F(RobustnessTest,Vector_Idx_Negative)376 TEST_F(RobustnessTest, Vector_Idx_Negative) {
377   auto* src = R"(
378 var<private> a : vec3<f32>;
379 
380 fn f() {
381   var b : f32 = a[-1];
382 }
383 )";
384 
385   auto* expect = R"(
386 var<private> a : vec3<f32>;
387 
388 fn f() {
389   var b : f32 = a[0];
390 }
391 )";
392 
393   auto got = Run<Robustness>(src);
394 
395   EXPECT_EQ(expect, str(got));
396 }
397 
TEST_F(RobustnessTest,Vector_Idx_OutOfBounds)398 TEST_F(RobustnessTest, Vector_Idx_OutOfBounds) {
399   auto* src = R"(
400 var<private> a : vec3<f32>;
401 
402 fn f() {
403   var b : f32 = a[3];
404 }
405 )";
406 
407   auto* expect = R"(
408 var<private> a : vec3<f32>;
409 
410 fn f() {
411   var b : f32 = a[2];
412 }
413 )";
414 
415   auto got = Run<Robustness>(src);
416 
417   EXPECT_EQ(expect, str(got));
418 }
419 
TEST_F(RobustnessTest,Matrix_Idx_Scalar)420 TEST_F(RobustnessTest, Matrix_Idx_Scalar) {
421   auto* src = R"(
422 var<private> a : mat3x2<f32>;
423 
424 fn f() {
425   var b : f32 = a[2][1];
426 }
427 )";
428 
429   auto* expect = R"(
430 var<private> a : mat3x2<f32>;
431 
432 fn f() {
433   var b : f32 = a[2][1];
434 }
435 )";
436 
437   auto got = Run<Robustness>(src);
438 
439   EXPECT_EQ(expect, str(got));
440 }
441 
TEST_F(RobustnessTest,Matrix_Idx_Expr_Column)442 TEST_F(RobustnessTest, Matrix_Idx_Expr_Column) {
443   auto* src = R"(
444 var<private> a : mat3x2<f32>;
445 
446 var<private> c : i32;
447 
448 fn f() {
449   var b : f32 = a[c + 2 - 3][1];
450 }
451 )";
452 
453   auto* expect = R"(
454 var<private> a : mat3x2<f32>;
455 
456 var<private> c : i32;
457 
458 fn f() {
459   var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1];
460 }
461 )";
462 
463   auto got = Run<Robustness>(src);
464 
465   EXPECT_EQ(expect, str(got));
466 }
467 
TEST_F(RobustnessTest,Matrix_Idx_Expr_Row)468 TEST_F(RobustnessTest, Matrix_Idx_Expr_Row) {
469   auto* src = R"(
470 var<private> a : mat3x2<f32>;
471 
472 var<private> c : i32;
473 
474 fn f() {
475   var b : f32 = a[1][c + 2 - 3];
476 }
477 )";
478 
479   auto* expect = R"(
480 var<private> a : mat3x2<f32>;
481 
482 var<private> c : i32;
483 
484 fn f() {
485   var b : f32 = a[1][min(u32(((c + 2) - 3)), 1u)];
486 }
487 )";
488 
489   auto got = Run<Robustness>(src);
490 
491   EXPECT_EQ(expect, str(got));
492 }
493 
TEST_F(RobustnessTest,Matrix_Idx_Negative_Column)494 TEST_F(RobustnessTest, Matrix_Idx_Negative_Column) {
495   auto* src = R"(
496 var<private> a : mat3x2<f32>;
497 
498 fn f() {
499   var b : f32 = a[-1][1];
500 }
501 )";
502 
503   auto* expect = R"(
504 var<private> a : mat3x2<f32>;
505 
506 fn f() {
507   var b : f32 = a[0][1];
508 }
509 )";
510 
511   auto got = Run<Robustness>(src);
512 
513   EXPECT_EQ(expect, str(got));
514 }
515 
TEST_F(RobustnessTest,Matrix_Idx_Negative_Row)516 TEST_F(RobustnessTest, Matrix_Idx_Negative_Row) {
517   auto* src = R"(
518 var<private> a : mat3x2<f32>;
519 
520 fn f() {
521   var b : f32 = a[2][-1];
522 }
523 )";
524 
525   auto* expect = R"(
526 var<private> a : mat3x2<f32>;
527 
528 fn f() {
529   var b : f32 = a[2][0];
530 }
531 )";
532 
533   auto got = Run<Robustness>(src);
534 
535   EXPECT_EQ(expect, str(got));
536 }
537 
TEST_F(RobustnessTest,Matrix_Idx_OutOfBounds_Column)538 TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Column) {
539   auto* src = R"(
540 var<private> a : mat3x2<f32>;
541 
542 fn f() {
543   var b : f32 = a[5][1];
544 }
545 )";
546 
547   auto* expect = R"(
548 var<private> a : mat3x2<f32>;
549 
550 fn f() {
551   var b : f32 = a[2][1];
552 }
553 )";
554 
555   auto got = Run<Robustness>(src);
556 
557   EXPECT_EQ(expect, str(got));
558 }
559 
TEST_F(RobustnessTest,Matrix_Idx_OutOfBounds_Row)560 TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Row) {
561   auto* src = R"(
562 var<private> a : mat3x2<f32>;
563 
564 fn f() {
565   var b : f32 = a[2][5];
566 }
567 )";
568 
569   auto* expect = R"(
570 var<private> a : mat3x2<f32>;
571 
572 fn f() {
573   var b : f32 = a[2][1];
574 }
575 )";
576 
577   auto got = Run<Robustness>(src);
578 
579   EXPECT_EQ(expect, str(got));
580 }
581 
582 // TODO(dsinclair): Implement when constant_id exists
TEST_F(RobustnessTest,DISABLED_Vector_Constant_Id_Clamps)583 TEST_F(RobustnessTest, DISABLED_Vector_Constant_Id_Clamps) {
584   // [[override(1300)]] let idx : i32;
585   // var a : vec3<f32>
586   // var b : f32 = a[idx]
587   //
588   // ->var b : f32 = a[min(u32(idx), 2)]
589 }
590 
591 // TODO(dsinclair): Implement when constant_id exists
TEST_F(RobustnessTest,DISABLED_Array_Constant_Id_Clamps)592 TEST_F(RobustnessTest, DISABLED_Array_Constant_Id_Clamps) {
593   // [[override(1300)]] let idx : i32;
594   // var a : array<f32, 4>
595   // var b : f32 = a[idx]
596   //
597   // -> var b : f32 = a[min(u32(idx), 3)]
598 }
599 
600 // TODO(dsinclair): Implement when constant_id exists
TEST_F(RobustnessTest,DISABLED_Matrix_Column_Constant_Id_Clamps)601 TEST_F(RobustnessTest, DISABLED_Matrix_Column_Constant_Id_Clamps) {
602   // [[override(1300)]] let idx : i32;
603   // var a : mat3x2<f32>
604   // var b : f32 = a[idx][1]
605   //
606   // -> var b : f32 = a[min(u32(idx), 2)][1]
607 }
608 
609 // TODO(dsinclair): Implement when constant_id exists
TEST_F(RobustnessTest,DISABLED_Matrix_Row_Constant_Id_Clamps)610 TEST_F(RobustnessTest, DISABLED_Matrix_Row_Constant_Id_Clamps) {
611   // [[override(1300)]] let idx : i32;
612   // var a : mat3x2<f32>
613   // var b : f32 = a[1][idx]
614   //
615   // -> var b : f32 = a[1][min(u32(idx), 0, 1)]
616 }
617 
TEST_F(RobustnessTest,RuntimeArray_Clamps)618 TEST_F(RobustnessTest, RuntimeArray_Clamps) {
619   auto* src = R"(
620 [[block]]
621 struct S {
622   a : f32;
623   b : array<f32>;
624 };
625 [[group(0), binding(0)]] var<storage, read> s : S;
626 
627 fn f() {
628   var d : f32 = s.b[25];
629 }
630 )";
631 
632   auto* expect = R"(
633 [[block]]
634 struct S {
635   a : f32;
636   b : array<f32>;
637 };
638 
639 [[group(0), binding(0)]] var<storage, read> s : S;
640 
641 fn f() {
642   var d : f32 = s.b[min(25u, (arrayLength(&(s.b)) - 1u))];
643 }
644 )";
645 
646   auto got = Run<Robustness>(src);
647 
648   EXPECT_EQ(expect, str(got));
649 }
650 
651 // TODO(dsinclair): Clamp atomics when available.
TEST_F(RobustnessTest,DISABLED_Atomics_Clamp)652 TEST_F(RobustnessTest, DISABLED_Atomics_Clamp) {
653   FAIL();
654 }
655 
656 // Clamp textureLoad() coord, array_index and level values
TEST_F(RobustnessTest,TextureLoad_Clamp)657 TEST_F(RobustnessTest, TextureLoad_Clamp) {
658   auto* src = R"(
659 [[group(0), binding(0)]] var tex_1d : texture_1d<f32>;
660 [[group(0), binding(0)]] var tex_2d : texture_2d<f32>;
661 [[group(0), binding(0)]] var tex_2d_arr : texture_2d_array<f32>;
662 [[group(0), binding(0)]] var tex_3d : texture_3d<f32>;
663 [[group(0), binding(0)]] var tex_ms_2d : texture_multisampled_2d<f32>;
664 [[group(0), binding(0)]] var tex_depth_2d : texture_depth_2d;
665 [[group(0), binding(0)]] var tex_depth_2d_arr : texture_depth_2d_array;
666 [[group(0), binding(0)]] var tex_external : texture_external;
667 
668 fn f() {
669   var array_idx : i32;
670   var level_idx : i32;
671   var sample_idx : i32;
672 
673   textureLoad(tex_1d, 1, level_idx);
674   textureLoad(tex_2d, vec2<i32>(1, 2), level_idx);
675   textureLoad(tex_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
676   textureLoad(tex_3d, vec3<i32>(1, 2, 3), level_idx);
677   textureLoad(tex_ms_2d, vec2<i32>(1, 2), sample_idx);
678   textureLoad(tex_depth_2d, vec2<i32>(1, 2), level_idx);
679   textureLoad(tex_depth_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
680   textureLoad(tex_external, vec2<i32>(1, 2));
681 }
682 )";
683 
684   auto* expect =
685       R"(
686 [[group(0), binding(0)]] var tex_1d : texture_1d<f32>;
687 
688 [[group(0), binding(0)]] var tex_2d : texture_2d<f32>;
689 
690 [[group(0), binding(0)]] var tex_2d_arr : texture_2d_array<f32>;
691 
692 [[group(0), binding(0)]] var tex_3d : texture_3d<f32>;
693 
694 [[group(0), binding(0)]] var tex_ms_2d : texture_multisampled_2d<f32>;
695 
696 [[group(0), binding(0)]] var tex_depth_2d : texture_depth_2d;
697 
698 [[group(0), binding(0)]] var tex_depth_2d_arr : texture_depth_2d_array;
699 
700 [[group(0), binding(0)]] var tex_external : texture_external;
701 
702 fn f() {
703   var array_idx : i32;
704   var level_idx : i32;
705   var sample_idx : i32;
706   textureLoad(tex_1d, clamp(1, i32(), (textureDimensions(tex_1d, clamp(level_idx, 0, (textureNumLevels(tex_1d) - 1))) - i32(1))), clamp(level_idx, 0, (textureNumLevels(tex_1d) - 1)));
707   textureLoad(tex_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d, clamp(level_idx, 0, (textureNumLevels(tex_2d) - 1))) - vec2<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_2d) - 1)));
708   textureLoad(tex_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d_arr, clamp(level_idx, 0, (textureNumLevels(tex_2d_arr) - 1))) - vec2<i32>(1))), clamp(array_idx, 0, (textureNumLayers(tex_2d_arr) - 1)), clamp(level_idx, 0, (textureNumLevels(tex_2d_arr) - 1)));
709   textureLoad(tex_3d, clamp(vec3<i32>(1, 2, 3), vec3<i32>(), (textureDimensions(tex_3d, clamp(level_idx, 0, (textureNumLevels(tex_3d) - 1))) - vec3<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_3d) - 1)));
710   textureLoad(tex_ms_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_ms_2d) - vec2<i32>(1))), sample_idx);
711   textureLoad(tex_depth_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d, clamp(level_idx, 0, (textureNumLevels(tex_depth_2d) - 1))) - vec2<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_depth_2d) - 1)));
712   textureLoad(tex_depth_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d_arr, clamp(level_idx, 0, (textureNumLevels(tex_depth_2d_arr) - 1))) - vec2<i32>(1))), clamp(array_idx, 0, (textureNumLayers(tex_depth_2d_arr) - 1)), clamp(level_idx, 0, (textureNumLevels(tex_depth_2d_arr) - 1)));
713   textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_external) - vec2<i32>(1))));
714 }
715 )";
716 
717   auto got = Run<Robustness>(src);
718 
719   EXPECT_EQ(expect, str(got));
720 }
721 
722 // Clamp textureStore() coord, array_index and level values
TEST_F(RobustnessTest,TextureStore_Clamp)723 TEST_F(RobustnessTest, TextureStore_Clamp) {
724   auto* src = R"(
725 [[group(0), binding(0)]] var tex1d : texture_storage_1d<rgba8sint, write>;
726 
727 [[group(0), binding(1)]] var tex2d : texture_storage_2d<rgba8sint, write>;
728 
729 [[group(0), binding(2)]] var tex2d_arr : texture_storage_2d_array<rgba8sint, write>;
730 
731 [[group(0), binding(3)]] var tex3d : texture_storage_3d<rgba8sint, write>;
732 
733 fn f() {
734   textureStore(tex1d, 10, vec4<i32>());
735   textureStore(tex2d, vec2<i32>(10, 20), vec4<i32>());
736   textureStore(tex2d_arr, vec2<i32>(10, 20), 50, vec4<i32>());
737   textureStore(tex3d, vec3<i32>(10, 20, 30), vec4<i32>());
738 }
739 )";
740 
741   auto* expect = R"(
742 [[group(0), binding(0)]] var tex1d : texture_storage_1d<rgba8sint, write>;
743 
744 [[group(0), binding(1)]] var tex2d : texture_storage_2d<rgba8sint, write>;
745 
746 [[group(0), binding(2)]] var tex2d_arr : texture_storage_2d_array<rgba8sint, write>;
747 
748 [[group(0), binding(3)]] var tex3d : texture_storage_3d<rgba8sint, write>;
749 
750 fn f() {
751   textureStore(tex1d, clamp(10, i32(), (textureDimensions(tex1d) - i32(1))), vec4<i32>());
752   textureStore(tex2d, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d) - vec2<i32>(1))), vec4<i32>());
753   textureStore(tex2d_arr, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d_arr) - vec2<i32>(1))), clamp(50, 0, (textureNumLayers(tex2d_arr) - 1)), vec4<i32>());
754   textureStore(tex3d, clamp(vec3<i32>(10, 20, 30), vec3<i32>(), (textureDimensions(tex3d) - vec3<i32>(1))), vec4<i32>());
755 }
756 )";
757 
758   auto got = Run<Robustness>(src);
759 
760   EXPECT_EQ(expect, str(got));
761 }
762 
763 // TODO(dsinclair): Test for scoped variables when shadowing is implemented
TEST_F(RobustnessTest,DISABLED_Shadowed_Variable)764 TEST_F(RobustnessTest, DISABLED_Shadowed_Variable) {
765   // var a : array<f32, 3>;
766   // var i : u32;
767   // {
768   //    var a : array<f32, 5>;
769   //    var b : f32 = a[i];
770   // }
771   // var c : f32 = a[i];
772   //
773   // -> var b : f32 = a[min(u32(i), 4)];
774   //    var c : f32 = a[min(u32(i), 2)];
775   FAIL();
776 }
777 
778 // Check that existing use of min() and arrayLength() do not get renamed.
TEST_F(RobustnessTest,DontRenameSymbols)779 TEST_F(RobustnessTest, DontRenameSymbols) {
780   auto* src = R"(
781 [[block]]
782 struct S {
783   a : f32;
784   b : array<f32>;
785 };
786 
787 [[group(0), binding(0)]] var<storage, read> s : S;
788 
789 let c : u32 = 1u;
790 
791 fn f() {
792   let b : f32 = s.b[c];
793   let x : i32 = min(1, 2);
794   let y : u32 = arrayLength(&s.b);
795 }
796 )";
797 
798   auto* expect = R"(
799 [[block]]
800 struct S {
801   a : f32;
802   b : array<f32>;
803 };
804 
805 [[group(0), binding(0)]] var<storage, read> s : S;
806 
807 let c : u32 = 1u;
808 
809 fn f() {
810   let b : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
811   let x : i32 = min(1, 2);
812   let y : u32 = arrayLength(&(s.b));
813 }
814 )";
815 
816   auto got = Run<Robustness>(src);
817 
818   EXPECT_EQ(expect, str(got));
819 }
820 
821 const char* kOmitSourceShader = R"(
822 [[block]]
823 struct S {
824   a : array<f32, 4>;
825   b : array<f32>;
826 };
827 [[group(0), binding(0)]] var<storage, read> s : S;
828 
829 type UArr = [[stride(16)]] array<f32, 4>;
830 [[block]] struct U {
831   a : UArr;
832 };
833 [[group(1), binding(0)]] var<uniform> u : U;
834 
835 fn f() {
836   // Signed
837   var i32_sa1 : f32 = s.a[4];
838   var i32_sa2 : f32 = s.a[1];
839   var i32_sa3 : f32 = s.a[0];
840   var i32_sa4 : f32 = s.a[-1];
841   var i32_sa5 : f32 = s.a[-4];
842 
843   var i32_sb1 : f32 = s.b[4];
844   var i32_sb2 : f32 = s.b[1];
845   var i32_sb3 : f32 = s.b[0];
846   var i32_sb4 : f32 = s.b[-1];
847   var i32_sb5 : f32 = s.b[-4];
848 
849   var i32_ua1 : f32 = u.a[4];
850   var i32_ua2 : f32 = u.a[1];
851   var i32_ua3 : f32 = u.a[0];
852   var i32_ua4 : f32 = u.a[-1];
853   var i32_ua5 : f32 = u.a[-4];
854 
855   // Unsigned
856   var u32_sa1 : f32 = s.a[0u];
857   var u32_sa2 : f32 = s.a[1u];
858   var u32_sa3 : f32 = s.a[3u];
859   var u32_sa4 : f32 = s.a[4u];
860   var u32_sa5 : f32 = s.a[10u];
861   var u32_sa6 : f32 = s.a[100u];
862 
863   var u32_sb1 : f32 = s.b[0u];
864   var u32_sb2 : f32 = s.b[1u];
865   var u32_sb3 : f32 = s.b[3u];
866   var u32_sb4 : f32 = s.b[4u];
867   var u32_sb5 : f32 = s.b[10u];
868   var u32_sb6 : f32 = s.b[100u];
869 
870   var u32_ua1 : f32 = u.a[0u];
871   var u32_ua2 : f32 = u.a[1u];
872   var u32_ua3 : f32 = u.a[3u];
873   var u32_ua4 : f32 = u.a[4u];
874   var u32_ua5 : f32 = u.a[10u];
875   var u32_ua6 : f32 = u.a[100u];
876 }
877 )";
878 
TEST_F(RobustnessTest,OmitNone)879 TEST_F(RobustnessTest, OmitNone) {
880   auto* expect = R"(
881 [[block]]
882 struct S {
883   a : array<f32, 4>;
884   b : array<f32>;
885 };
886 
887 [[group(0), binding(0)]] var<storage, read> s : S;
888 
889 type UArr = [[stride(16)]] array<f32, 4>;
890 
891 [[block]]
892 struct U {
893   a : UArr;
894 };
895 
896 [[group(1), binding(0)]] var<uniform> u : U;
897 
898 fn f() {
899   var i32_sa1 : f32 = s.a[3];
900   var i32_sa2 : f32 = s.a[1];
901   var i32_sa3 : f32 = s.a[0];
902   var i32_sa4 : f32 = s.a[0];
903   var i32_sa5 : f32 = s.a[0];
904   var i32_sb1 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
905   var i32_sb2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
906   var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
907   var i32_sb4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
908   var i32_sb5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
909   var i32_ua1 : f32 = u.a[3];
910   var i32_ua2 : f32 = u.a[1];
911   var i32_ua3 : f32 = u.a[0];
912   var i32_ua4 : f32 = u.a[0];
913   var i32_ua5 : f32 = u.a[0];
914   var u32_sa1 : f32 = s.a[0u];
915   var u32_sa2 : f32 = s.a[1u];
916   var u32_sa3 : f32 = s.a[3u];
917   var u32_sa4 : f32 = s.a[3u];
918   var u32_sa5 : f32 = s.a[3u];
919   var u32_sa6 : f32 = s.a[3u];
920   var u32_sb1 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
921   var u32_sb2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
922   var u32_sb3 : f32 = s.b[min(3u, (arrayLength(&(s.b)) - 1u))];
923   var u32_sb4 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
924   var u32_sb5 : f32 = s.b[min(10u, (arrayLength(&(s.b)) - 1u))];
925   var u32_sb6 : f32 = s.b[min(100u, (arrayLength(&(s.b)) - 1u))];
926   var u32_ua1 : f32 = u.a[0u];
927   var u32_ua2 : f32 = u.a[1u];
928   var u32_ua3 : f32 = u.a[3u];
929   var u32_ua4 : f32 = u.a[3u];
930   var u32_ua5 : f32 = u.a[3u];
931   var u32_ua6 : f32 = u.a[3u];
932 }
933 )";
934 
935   Robustness::Config cfg;
936   DataMap data;
937   data.Add<Robustness::Config>(cfg);
938 
939   auto got = Run<Robustness>(kOmitSourceShader, data);
940 
941   EXPECT_EQ(expect, str(got));
942 }
943 
TEST_F(RobustnessTest,OmitStorage)944 TEST_F(RobustnessTest, OmitStorage) {
945   auto* expect = R"(
946 [[block]]
947 struct S {
948   a : array<f32, 4>;
949   b : array<f32>;
950 };
951 
952 [[group(0), binding(0)]] var<storage, read> s : S;
953 
954 type UArr = [[stride(16)]] array<f32, 4>;
955 
956 [[block]]
957 struct U {
958   a : UArr;
959 };
960 
961 [[group(1), binding(0)]] var<uniform> u : U;
962 
963 fn f() {
964   var i32_sa1 : f32 = s.a[4];
965   var i32_sa2 : f32 = s.a[1];
966   var i32_sa3 : f32 = s.a[0];
967   var i32_sa4 : f32 = s.a[-1];
968   var i32_sa5 : f32 = s.a[-4];
969   var i32_sb1 : f32 = s.b[4];
970   var i32_sb2 : f32 = s.b[1];
971   var i32_sb3 : f32 = s.b[0];
972   var i32_sb4 : f32 = s.b[-1];
973   var i32_sb5 : f32 = s.b[-4];
974   var i32_ua1 : f32 = u.a[3];
975   var i32_ua2 : f32 = u.a[1];
976   var i32_ua3 : f32 = u.a[0];
977   var i32_ua4 : f32 = u.a[0];
978   var i32_ua5 : f32 = u.a[0];
979   var u32_sa1 : f32 = s.a[0u];
980   var u32_sa2 : f32 = s.a[1u];
981   var u32_sa3 : f32 = s.a[3u];
982   var u32_sa4 : f32 = s.a[4u];
983   var u32_sa5 : f32 = s.a[10u];
984   var u32_sa6 : f32 = s.a[100u];
985   var u32_sb1 : f32 = s.b[0u];
986   var u32_sb2 : f32 = s.b[1u];
987   var u32_sb3 : f32 = s.b[3u];
988   var u32_sb4 : f32 = s.b[4u];
989   var u32_sb5 : f32 = s.b[10u];
990   var u32_sb6 : f32 = s.b[100u];
991   var u32_ua1 : f32 = u.a[0u];
992   var u32_ua2 : f32 = u.a[1u];
993   var u32_ua3 : f32 = u.a[3u];
994   var u32_ua4 : f32 = u.a[3u];
995   var u32_ua5 : f32 = u.a[3u];
996   var u32_ua6 : f32 = u.a[3u];
997 }
998 )";
999 
1000   Robustness::Config cfg;
1001   cfg.omitted_classes.insert(Robustness::StorageClass::kStorage);
1002 
1003   DataMap data;
1004   data.Add<Robustness::Config>(cfg);
1005 
1006   auto got = Run<Robustness>(kOmitSourceShader, data);
1007 
1008   EXPECT_EQ(expect, str(got));
1009 }
1010 
TEST_F(RobustnessTest,OmitUniform)1011 TEST_F(RobustnessTest, OmitUniform) {
1012   auto* expect = R"(
1013 [[block]]
1014 struct S {
1015   a : array<f32, 4>;
1016   b : array<f32>;
1017 };
1018 
1019 [[group(0), binding(0)]] var<storage, read> s : S;
1020 
1021 type UArr = [[stride(16)]] array<f32, 4>;
1022 
1023 [[block]]
1024 struct U {
1025   a : UArr;
1026 };
1027 
1028 [[group(1), binding(0)]] var<uniform> u : U;
1029 
1030 fn f() {
1031   var i32_sa1 : f32 = s.a[3];
1032   var i32_sa2 : f32 = s.a[1];
1033   var i32_sa3 : f32 = s.a[0];
1034   var i32_sa4 : f32 = s.a[0];
1035   var i32_sa5 : f32 = s.a[0];
1036   var i32_sb1 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
1037   var i32_sb2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
1038   var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
1039   var i32_sb4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
1040   var i32_sb5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
1041   var i32_ua1 : f32 = u.a[4];
1042   var i32_ua2 : f32 = u.a[1];
1043   var i32_ua3 : f32 = u.a[0];
1044   var i32_ua4 : f32 = u.a[-1];
1045   var i32_ua5 : f32 = u.a[-4];
1046   var u32_sa1 : f32 = s.a[0u];
1047   var u32_sa2 : f32 = s.a[1u];
1048   var u32_sa3 : f32 = s.a[3u];
1049   var u32_sa4 : f32 = s.a[3u];
1050   var u32_sa5 : f32 = s.a[3u];
1051   var u32_sa6 : f32 = s.a[3u];
1052   var u32_sb1 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
1053   var u32_sb2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
1054   var u32_sb3 : f32 = s.b[min(3u, (arrayLength(&(s.b)) - 1u))];
1055   var u32_sb4 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
1056   var u32_sb5 : f32 = s.b[min(10u, (arrayLength(&(s.b)) - 1u))];
1057   var u32_sb6 : f32 = s.b[min(100u, (arrayLength(&(s.b)) - 1u))];
1058   var u32_ua1 : f32 = u.a[0u];
1059   var u32_ua2 : f32 = u.a[1u];
1060   var u32_ua3 : f32 = u.a[3u];
1061   var u32_ua4 : f32 = u.a[4u];
1062   var u32_ua5 : f32 = u.a[10u];
1063   var u32_ua6 : f32 = u.a[100u];
1064 }
1065 )";
1066 
1067   Robustness::Config cfg;
1068   cfg.omitted_classes.insert(Robustness::StorageClass::kUniform);
1069 
1070   DataMap data;
1071   data.Add<Robustness::Config>(cfg);
1072 
1073   auto got = Run<Robustness>(kOmitSourceShader, data);
1074 
1075   EXPECT_EQ(expect, str(got));
1076 }
1077 
TEST_F(RobustnessTest,OmitBoth)1078 TEST_F(RobustnessTest, OmitBoth) {
1079   auto* expect = R"(
1080 [[block]]
1081 struct S {
1082   a : array<f32, 4>;
1083   b : array<f32>;
1084 };
1085 
1086 [[group(0), binding(0)]] var<storage, read> s : S;
1087 
1088 type UArr = [[stride(16)]] array<f32, 4>;
1089 
1090 [[block]]
1091 struct U {
1092   a : UArr;
1093 };
1094 
1095 [[group(1), binding(0)]] var<uniform> u : U;
1096 
1097 fn f() {
1098   var i32_sa1 : f32 = s.a[4];
1099   var i32_sa2 : f32 = s.a[1];
1100   var i32_sa3 : f32 = s.a[0];
1101   var i32_sa4 : f32 = s.a[-1];
1102   var i32_sa5 : f32 = s.a[-4];
1103   var i32_sb1 : f32 = s.b[4];
1104   var i32_sb2 : f32 = s.b[1];
1105   var i32_sb3 : f32 = s.b[0];
1106   var i32_sb4 : f32 = s.b[-1];
1107   var i32_sb5 : f32 = s.b[-4];
1108   var i32_ua1 : f32 = u.a[4];
1109   var i32_ua2 : f32 = u.a[1];
1110   var i32_ua3 : f32 = u.a[0];
1111   var i32_ua4 : f32 = u.a[-1];
1112   var i32_ua5 : f32 = u.a[-4];
1113   var u32_sa1 : f32 = s.a[0u];
1114   var u32_sa2 : f32 = s.a[1u];
1115   var u32_sa3 : f32 = s.a[3u];
1116   var u32_sa4 : f32 = s.a[4u];
1117   var u32_sa5 : f32 = s.a[10u];
1118   var u32_sa6 : f32 = s.a[100u];
1119   var u32_sb1 : f32 = s.b[0u];
1120   var u32_sb2 : f32 = s.b[1u];
1121   var u32_sb3 : f32 = s.b[3u];
1122   var u32_sb4 : f32 = s.b[4u];
1123   var u32_sb5 : f32 = s.b[10u];
1124   var u32_sb6 : f32 = s.b[100u];
1125   var u32_ua1 : f32 = u.a[0u];
1126   var u32_ua2 : f32 = u.a[1u];
1127   var u32_ua3 : f32 = u.a[3u];
1128   var u32_ua4 : f32 = u.a[4u];
1129   var u32_ua5 : f32 = u.a[10u];
1130   var u32_ua6 : f32 = u.a[100u];
1131 }
1132 )";
1133 
1134   Robustness::Config cfg;
1135   cfg.omitted_classes.insert(Robustness::StorageClass::kStorage);
1136   cfg.omitted_classes.insert(Robustness::StorageClass::kUniform);
1137 
1138   DataMap data;
1139   data.Add<Robustness::Config>(cfg);
1140 
1141   auto got = Run<Robustness>(kOmitSourceShader, data);
1142 
1143   EXPECT_EQ(expect, str(got));
1144 }
1145 
1146 }  // namespace
1147 }  // namespace transform
1148 }  // namespace tint
1149