| // Copyright 2020 The Dawn & Tint Authors |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // 1. Redistributions of source code must retain the above copyright notice, this |
| // list of conditions and the following disclaimer. |
| // |
| // 2. Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // 3. Neither the name of the copyright holder nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include "src/tint/lang/wgsl/ast/transform/robustness.h" |
| |
| #include "src/tint/lang/wgsl/ast/transform/helper_test.h" |
| |
| namespace tint::ast::transform { |
| |
| static std::ostream& operator<<(std::ostream& out, Robustness::Action action) { |
| switch (action) { |
| case Robustness::Action::kIgnore: |
| return out << "ignore"; |
| case Robustness::Action::kClamp: |
| return out << "clamp"; |
| case Robustness::Action::kPredicate: |
| return out << "predicate"; |
| } |
| return out << "unknown"; |
| } |
| |
| namespace { |
| |
| DataMap Config(Robustness::Action action, bool disable_runtime_sized_array_index_clamping = false) { |
| Robustness::Config cfg; |
| cfg.value_action = action; |
| cfg.texture_action = action; |
| cfg.function_action = action; |
| cfg.private_action = action; |
| cfg.push_constant_action = action; |
| cfg.storage_action = action; |
| cfg.uniform_action = action; |
| cfg.workgroup_action = action; |
| cfg.disable_runtime_sized_array_index_clamping = disable_runtime_sized_array_index_clamping; |
| DataMap data; |
| data.Add<Robustness::Config>(cfg); |
| return data; |
| } |
| |
| const char* Expect(Robustness::Action action, |
| const char* expect_ignore, |
| const char* expect_clamp, |
| const char* expect_predicate) { |
| switch (action) { |
| case Robustness::Action::kIgnore: |
| return expect_ignore; |
| case Robustness::Action::kClamp: |
| return expect_clamp; |
| case Robustness::Action::kPredicate: |
| return expect_predicate; |
| } |
| return "<invalid action>"; |
| } |
| |
| using RobustnessTest = TransformTestWithParam<Robustness::Action>; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Constant sized array |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayVal_IndexWithLiteral) { |
| auto* src = R"( |
| fn f() { |
| var b : f32 = array<f32, 3>()[1i]; |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayVal_IndexWithConst) { |
| auto* src = R"( |
| const c : u32 = 1u; |
| |
| fn f() { |
| let b : f32 = array<f32, 3>()[c]; |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayVal_IndexWithLet) { |
| auto* src = R"( |
| fn f() { |
| let l : u32 = 1u; |
| let b : f32 = array<f32, 3>()[l]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| fn f() { |
| let l : u32 = 1u; |
| let b : f32 = array<f32, 3>()[min(l, 2u)]; |
| } |
| )", |
| /* predicate */ R"( |
| fn f() { |
| let l : u32 = 1u; |
| let index = l; |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = array<f32, 3>()[index]; |
| } |
| let b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayVal_IndexWithRuntimeArrayIndex) { |
| auto* src = R"( |
| var<private> i : u32; |
| |
| fn f() { |
| let a = array<f32, 3>(); |
| let b = array<i32, 5>(); |
| var c : f32 = a[b[i]]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> i : u32; |
| |
| fn f() { |
| let a = array<f32, 3>(); |
| let b = array<i32, 5>(); |
| var c : f32 = a[min(u32(b[min(i, 4u)]), 2u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> i : u32; |
| |
| fn f() { |
| let a = array<f32, 3>(); |
| let b = array<i32, 5>(); |
| let index = i; |
| let predicate = (u32(index) <= 4u); |
| var predicated_expr : i32; |
| if (predicate) { |
| predicated_expr = b[index]; |
| } |
| let index_1 = predicated_expr; |
| let predicate_1 = (u32(index_1) <= 2u); |
| var predicated_expr_1 : f32; |
| if (predicate_1) { |
| predicated_expr_1 = a[index_1]; |
| } |
| var c : f32 = predicated_expr_1; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayVal_IndexWithRuntimeExpression) { |
| auto* src = R"( |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = array<f32, 3>()[((c + 2) - 3)]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = array<f32, 3>()[min(u32(((c + 2) - 3)), 2u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> c : i32; |
| |
| fn f() { |
| let index = ((c + 2) - 3); |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = array<f32, 3>()[index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_NestedConstantSizedArraysVal_IndexWithRuntimeExpressions) { |
| auto* src = R"( |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| let a = array<array<array<f32, 1>, 2>, 3>(); |
| var r = a[x][y][z]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| let a = array<array<array<f32, 1>, 2>, 3>(); |
| var r = a[min(u32(x), 2u)][min(u32(y), 1u)][min(u32(z), 0u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| let a = array<array<array<f32, 1>, 2>, 3>(); |
| let index = x; |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : array<array<f32, 1u>, 2u>; |
| if (predicate) { |
| predicated_expr = a[index]; |
| } |
| let index_1 = y; |
| let predicate_1 = (u32(index_1) <= 1u); |
| var predicated_expr_1 : array<f32, 1u>; |
| if (predicate_1) { |
| predicated_expr_1 = predicated_expr[index_1]; |
| } |
| let index_2 = z; |
| let predicate_2 = (u32(index_2) <= 0u); |
| var predicated_expr_2 : f32; |
| if (predicate_2) { |
| predicated_expr_2 = predicated_expr_1[index_2]; |
| } |
| var r = predicated_expr_2; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayVal_IndexWithOverride) { |
| auto* src = R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| let a = array<f32, 4>(); |
| var b : f32 = a[idx]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| let a = array<f32, 4>(); |
| var b : f32 = a[min(u32(idx), 3u)]; |
| } |
| )", |
| /* predicate */ R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| let a = array<f32, 4>(); |
| let index = idx; |
| let predicate = (u32(index) <= 3u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a[index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayRef_IndexWithLiteral) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| var b : f32 = a[1i]; |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayRef_IndexWithConst) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| const c : u32 = 1u; |
| |
| fn f() { |
| let b : f32 = a[c]; |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayRef_IndexWithLet) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let b : f32 = a[l]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let b : f32 = a[min(l, 2u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let index = l; |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a[index]; |
| } |
| let b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayRef_IndexWithRuntimeArrayIndex) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| var c : f32 = a[b[i]]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| var c : f32 = a[min(u32(b[min(i, 4u)]), 2u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| let index = i; |
| let predicate = (u32(index) <= 4u); |
| var predicated_expr : i32; |
| if (predicate) { |
| predicated_expr = b[index]; |
| } |
| let index_1 = predicated_expr; |
| let predicate_1 = (u32(index_1) <= 2u); |
| var predicated_expr_1 : f32; |
| if (predicate_1) { |
| predicated_expr_1 = a[index_1]; |
| } |
| var c : f32 = predicated_expr_1; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayRef_IndexWithRuntimeArrayIndexViaPointerIndex) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| let p1 = &(a); |
| let p2 = &(b); |
| var c : f32 = p1[p2[i]]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| let p1 = &(a); |
| let p2 = &(b); |
| var c : f32 = p1[min(u32(p2[min(i, 4u)]), 2u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| let p1 = &(a); |
| let p2 = &(b); |
| let index = i; |
| let predicate = (u32(index) <= 4u); |
| var predicated_expr : i32; |
| if (predicate) { |
| predicated_expr = p2[index]; |
| } |
| let index_1 = predicated_expr; |
| let predicate_1 = (u32(index_1) <= 2u); |
| var predicated_expr_1 : f32; |
| if (predicate_1) { |
| predicated_expr_1 = p1[index_1]; |
| } |
| var c : f32 = predicated_expr_1; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayRef_IndexWithRuntimeExpression) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a[((c + 2) - 3)]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a[min(u32(((c + 2) - 3)), 2u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let index = ((c + 2) - 3); |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a[index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_NestedConstantSizedArraysRef_IndexWithRuntimeExpressions) { |
| auto* src = R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| var r = a[x][y][z]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| var r = a[min(u32(x), 2u)][min(u32(y), 1u)][min(u32(z), 0u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| let index = x; |
| let predicate = (u32(index) <= 2u); |
| let index_1 = y; |
| let predicate_1 = (predicate & (u32(index_1) <= 1u)); |
| let index_2 = z; |
| let predicate_2 = (predicate_1 & (u32(index_2) <= 0u)); |
| var predicated_expr : f32; |
| if (predicate_2) { |
| predicated_expr = a[index][index_1][index_2]; |
| } |
| var r = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayRef_IndexWithOverride) { |
| auto* src = R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : array<f32, 4>; |
| var b : f32 = a[idx]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : array<f32, 4>; |
| var b : f32 = a[min(u32(idx), 3u)]; |
| } |
| )", |
| /* predicate */ R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : array<f32, 4>; |
| let index = idx; |
| let predicate = (u32(index) <= 3u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a[index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayPtr_IndexWithLet) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let p = &(a[l]); |
| let f : f32 = *(p); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let p = &(a[min(l, 2u)]); |
| let f : f32 = *(p); |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let index = l; |
| let predicate = (u32(index) <= 2u); |
| let p = &(a[index]); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = *(p); |
| } |
| let f : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_ConstantSizedArrayPtr_IndexWithRuntimeArrayIndex) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| let pa = &(a); |
| let pb = &(b); |
| let p0 = &((*(pb))[i]); |
| let p1 = &(a[*(p0)]); |
| var x : f32 = *(p1); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| let pa = &(a); |
| let pb = &(b); |
| let p0 = &((*(pb))[min(i, 4u)]); |
| let p1 = &(a[min(u32(*(p0)), 2u)]); |
| var x : f32 = *(p1); |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| let pa = &(a); |
| let pb = &(b); |
| let index = i; |
| let predicate = (u32(index) <= 4u); |
| let p0 = &((*(pb))[index]); |
| var predicated_expr : i32; |
| if (predicate) { |
| predicated_expr = *(p0); |
| } |
| let index_1 = predicated_expr; |
| let predicate_1 = (u32(index_1) <= 2u); |
| let p1 = &(a[index_1]); |
| var predicated_expr_1 : f32; |
| if (predicate_1) { |
| predicated_expr_1 = *(p1); |
| } |
| var x : f32 = predicated_expr_1; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_NestedConstantSizedArraysPtr_IndexWithRuntimeExpressions) { |
| auto* src = R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let p1 = &((*(p0))[x]); |
| let p2 = &((*(p1))[y]); |
| let p3 = &((*(p2))[z]); |
| var r = *(p3); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let p1 = &((*(p0))[min(u32(x), 2u)]); |
| let p2 = &((*(p1))[min(u32(y), 1u)]); |
| let p3 = &((*(p2))[min(u32(z), 0u)]); |
| var r = *(p3); |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let index = x; |
| let predicate = (u32(index) <= 2u); |
| let p1 = &((*(p0))[index]); |
| let index_1 = y; |
| let predicate_1 = (predicate & (u32(index_1) <= 1u)); |
| let p2 = &((*(p1))[index_1]); |
| let index_2 = z; |
| let predicate_2 = (predicate_1 & (u32(index_2) <= 0u)); |
| let p3 = &((*(p2))[index_2]); |
| var predicated_expr : f32; |
| if (predicate_2) { |
| predicated_expr = *(p3); |
| } |
| var r = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_NestedConstantSizedArrays_MixedAccess) { |
| auto* src = R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| const y = 1; |
| |
| override z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let p1 = &((*(p0))[x]); |
| let p2 = &((*(p1))[y]); |
| let p3 = &((*(p2))[z]); |
| var r = *(p3); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| const y = 1; |
| |
| override z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let p1 = &((*(p0))[min(u32(x), 2u)]); |
| let p2 = &((*(p1))[y]); |
| let p3 = &((*(p2))[min(u32(z), 0u)]); |
| var r = *(p3); |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| const y = 1; |
| |
| override z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let index = x; |
| let predicate = (u32(index) <= 2u); |
| let p1 = &((*(p0))[index]); |
| let p2 = &((*(p1))[y]); |
| let index_1 = z; |
| let predicate_1 = (predicate & (u32(index_1) <= 0u)); |
| let p3 = &((*(p2))[index_1]); |
| var predicated_expr : f32; |
| if (predicate_1) { |
| predicated_expr = *(p3); |
| } |
| var r = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Assign_ConstantSizedArray_IndexWithLet) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| a[l] = 42.0f; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| a[min(l, 2u)] = 42.0f; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let index = l; |
| let predicate = (u32(index) <= 2u); |
| if (predicate) { |
| a[index] = 42.0f; |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Assign_ConstantSizedArrayPtr_IndexWithLet) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let p = &(a[l]); |
| *(p) = 42.0f; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let p = &(a[min(l, 2u)]); |
| *(p) = 42.0f; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let index = l; |
| let predicate = (u32(index) <= 2u); |
| let p = &(a[index]); |
| if (predicate) { |
| *(p) = 42.0f; |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Assign_ConstantSizedArrayPtr_IndexWithRuntimeArrayIndex) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| let pa = &(a); |
| let pb = &(b); |
| let p0 = &((*(pb))[i]); |
| let p1 = &(a[*(p0)]); |
| *(p1) = 42.0f; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| let pa = &(a); |
| let pb = &(b); |
| let p0 = &((*(pb))[min(i, 4u)]); |
| let p1 = &(a[min(u32(*(p0)), 2u)]); |
| *(p1) = 42.0f; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<f32, 3>; |
| |
| var<private> b : array<i32, 5>; |
| |
| var<private> i : u32; |
| |
| fn f() { |
| let pa = &(a); |
| let pb = &(b); |
| let index = i; |
| let predicate = (u32(index) <= 4u); |
| let p0 = &((*(pb))[index]); |
| var predicated_expr : i32; |
| if (predicate) { |
| predicated_expr = *(p0); |
| } |
| let index_1 = predicated_expr; |
| let predicate_1 = (u32(index_1) <= 2u); |
| let p1 = &(a[index_1]); |
| if (predicate_1) { |
| *(p1) = 42.0f; |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Assign_NestedConstantSizedArraysPtr_IndexWithRuntimeExpressions) { |
| auto* src = R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let p1 = &((*(p0))[x]); |
| let p2 = &((*(p1))[y]); |
| let p3 = &((*(p2))[z]); |
| *(p3) = 42.0f; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let p1 = &((*(p0))[min(u32(x), 2u)]); |
| let p2 = &((*(p1))[min(u32(y), 1u)]); |
| let p3 = &((*(p2))[min(u32(z), 0u)]); |
| *(p3) = 42.0f; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| var<private> y : i32; |
| |
| var<private> z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let index = x; |
| let predicate = (u32(index) <= 2u); |
| let p1 = &((*(p0))[index]); |
| let index_1 = y; |
| let predicate_1 = (predicate & (u32(index_1) <= 1u)); |
| let p2 = &((*(p1))[index_1]); |
| let index_2 = z; |
| let predicate_2 = (predicate_1 & (u32(index_2) <= 0u)); |
| let p3 = &((*(p2))[index_2]); |
| if (predicate_2) { |
| *(p3) = 42.0f; |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Assign_NestedConstantSizedArrays_MixedAccess) { |
| auto* src = R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| const y = 1; |
| |
| override z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let p1 = &((*(p0))[x]); |
| let p2 = &((*(p1))[y]); |
| let p3 = &((*(p2))[z]); |
| *(p3) = 42.0f; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| const y = 1; |
| |
| override z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let p1 = &((*(p0))[min(u32(x), 2u)]); |
| let p2 = &((*(p1))[y]); |
| let p3 = &((*(p2))[min(u32(z), 0u)]); |
| *(p3) = 42.0f; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<array<array<f32, 1>, 2>, 3>; |
| |
| var<private> x : i32; |
| |
| const y = 1; |
| |
| override z : i32; |
| |
| fn f() { |
| let p0 = &(a); |
| let index = x; |
| let predicate = (u32(index) <= 2u); |
| let p1 = &((*(p0))[index]); |
| let p2 = &((*(p1))[y]); |
| let index_1 = z; |
| let predicate_1 = (predicate & (u32(index_1) <= 0u)); |
| let p3 = &((*(p2))[index_1]); |
| if (predicate_1) { |
| *(p3) = 42.0f; |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, CompoundAssign_ConstantSizedArray_IndexWithLet) { |
| auto* src = R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| a[l] += 42.0f; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| a[min(l, 2u)] += 42.0f; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<f32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let index = l; |
| let predicate = (u32(index) <= 2u); |
| if (predicate) { |
| a[index] += 42.0f; |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Increment_ConstantSizedArray_IndexWithLet) { |
| auto* src = R"( |
| var<private> a : array<i32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| a[l]++; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<i32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| a[min(l, 2u)]++; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<i32, 3>; |
| |
| fn f() { |
| let l : u32 = 1u; |
| let index = l; |
| let predicate = (u32(index) <= 2u); |
| if (predicate) { |
| a[index]++; |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Runtime sized array |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| TEST_P(RobustnessTest, Read_RuntimeArray_IndexWithLiteral) { |
| auto* src = R"( |
| struct S { |
| a : f32, |
| b : array<f32>, |
| } |
| |
| @group(0) @binding(0) var<storage, read> s : S; |
| |
| fn f() { |
| var d : f32 = s.b[25]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| struct S { |
| a : f32, |
| b : array<f32>, |
| } |
| |
| @group(0) @binding(0) var<storage, read> s : S; |
| |
| fn f() { |
| var d : f32 = s.b[min(u32(25), (arrayLength(&(s.b)) - 1u))]; |
| } |
| )", |
| /* predicate */ R"( |
| struct S { |
| a : f32, |
| b : array<f32>, |
| } |
| |
| @group(0) @binding(0) var<storage, read> s : S; |
| |
| fn f() { |
| let index = 25; |
| let predicate = (u32(index) <= (arrayLength(&(s.b)) - 1u)); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = s.b[index]; |
| } |
| var d : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Vector |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| TEST_P(RobustnessTest, Read_Vector_IndexWithLiteral) { |
| auto* src = R"( |
| var<private> a : vec3<f32>; |
| |
| fn f() { |
| var b : f32 = a[1i]; |
| } |
| )"; |
| |
| auto* expect = src; |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_Vector_IndexWithConst) { |
| auto* src = R"( |
| var<private> a : vec3<f32>; |
| |
| fn f() { |
| const i = 1; |
| var b : f32 = a[i]; |
| } |
| )"; |
| |
| auto* expect = src; |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_Vector_IndexWithLet) { |
| auto* src = R"( |
| fn f() { |
| let i = 99; |
| let v = vec4<f32>()[i]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| fn f() { |
| let i = 99; |
| let v = vec4<f32>()[min(u32(i), 3u)]; |
| } |
| )", |
| /* predicate */ R"( |
| fn f() { |
| let i = 99; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = vec4<f32>()[index]; |
| } |
| let v = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_Vector_IndexWithRuntimeExpression) { |
| auto* src = R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a[((c + 2) - 3)]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a[min(u32(((c + 2) - 3)), 2u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let index = ((c + 2) - 3); |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a[index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_Vector_IndexWithRuntimeExpression_ViaPointerIndex) { |
| auto* src = R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let p = &(a); |
| var b : f32 = p[((c + 2) - 3)]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let p = &(a); |
| var b : f32 = p[min(u32(((c + 2) - 3)), 2u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let p = &(a); |
| let index = ((c + 2) - 3); |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = p[index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_Vector_SwizzleIndexWithGlobalVar) { |
| auto* src = R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a.xy[c]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a.xy[min(u32(c), 1u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let index = c; |
| let predicate = (u32(index) <= 1u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a.xy[index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_Vector_SwizzleIndexWithRuntimeExpression) { |
| auto* src = R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a.xy[((c + 2) - 3)]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a.xy[min(u32(((c + 2) - 3)), 1u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let index = ((c + 2) - 3); |
| let predicate = (u32(index) <= 1u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a.xy[index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_Vector_SwizzleIndexWithRuntimeExpression_ViaPointerDot) { |
| auto* src = R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let p = &(a); |
| var b : f32 = p.xy[((c + 2) - 3)]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let p = &(a); |
| var b : f32 = p.xy[min(u32(((c + 2) - 3)), 1u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : vec3<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let p = &(a); |
| let index = ((c + 2) - 3); |
| let predicate = (u32(index) <= 1u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = p.xy[index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_Vector_IndexWithOverride) { |
| auto* src = R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : vec3<f32>; |
| var b : f32 = a[idx]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : vec3<f32>; |
| var b : f32 = a[min(u32(idx), 2u)]; |
| } |
| )", |
| /* predicate */ R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : vec3<f32>; |
| let index = idx; |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a[index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Matrix |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| TEST_P(RobustnessTest, Read_MatrixRef_IndexingWithLiterals) { |
| auto* src = R"( |
| var<private> a : mat3x2<f32>; |
| |
| fn f() { |
| var b : f32 = a[2i][1i]; |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_MatrixRef_IndexWithRuntimeExpressionThenLiteral) { |
| auto* src = R"( |
| var<private> a : mat3x2<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a[((c + 2) - 3)][1]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : mat3x2<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : mat3x2<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let index = ((c + 2) - 3); |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a[index][1]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_MatrixRef_IndexWithLiteralThenRuntimeExpression) { |
| auto* src = R"( |
| var<private> a : mat3x2<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a[1][((c + 2) - 3)]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : mat3x2<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| var b : f32 = a[1][min(u32(((c + 2) - 3)), 1u)]; |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : mat3x2<f32>; |
| |
| var<private> c : i32; |
| |
| fn f() { |
| let index = ((c + 2) - 3); |
| let predicate = (u32(index) <= 1u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a[1][index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_MatrixRef_IndexWithOverrideThenLiteral) { |
| auto* src = R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : mat3x2<f32>; |
| var b : f32 = a[idx][1]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : mat3x2<f32>; |
| var b : f32 = a[min(u32(idx), 2u)][1]; |
| } |
| )", |
| /* predicate */ R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : mat3x2<f32>; |
| let index = idx; |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a[index][1]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_MatrixRef_IndexWithLetThenSwizzle) { |
| auto* src = R"( |
| fn f() { |
| let i = 1; |
| var m = mat3x2<f32>(); |
| var v = m[i].yx; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| fn f() { |
| let i = 1; |
| var m = mat3x2<f32>(); |
| var v = m[min(u32(i), 2u)].yx; |
| } |
| )", |
| /* predicate */ R"( |
| fn f() { |
| let i = 1; |
| var m = mat3x2<f32>(); |
| let index = i; |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : vec2<f32>; |
| if (predicate) { |
| predicated_expr = m[index]; |
| } |
| var v = predicated_expr.yx; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_MatrixRef_IndexWithLiteralThenOverride) { |
| auto* src = R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : mat3x2<f32>; |
| var b : f32 = a[1][idx]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : mat3x2<f32>; |
| var b : f32 = a[1][min(u32(idx), 1u)]; |
| } |
| )", |
| /* predicate */ R"( |
| @id(1300) override idx : i32; |
| |
| fn f() { |
| var a : mat3x2<f32>; |
| let index = idx; |
| let predicate = (u32(index) <= 1u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a[1][index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Assign_Matrix_IndexWithLet) { |
| auto* src = R"( |
| var<private> m : mat3x4f; |
| |
| fn f() { |
| let c = 1; |
| m[c] = vec4f(1); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> m : mat3x4f; |
| |
| fn f() { |
| let c = 1; |
| m[min(u32(c), 2u)] = vec4f(1); |
| } |
| )", |
| /* predicate */ R"( |
| var<private> m : mat3x4f; |
| |
| fn f() { |
| let c = 1; |
| let index = c; |
| let predicate = (u32(index) <= 2u); |
| if (predicate) { |
| m[index] = vec4f(1); |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, CompoundAssign_Matrix_IndexWithLet) { |
| auto* src = R"( |
| var<private> m : mat3x4f; |
| |
| fn f() { |
| let c = 1; |
| m[c] += vec4f(1); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> m : mat3x4f; |
| |
| fn f() { |
| let c = 1; |
| m[min(u32(c), 2u)] += vec4f(1); |
| } |
| )", |
| /* predicate */ R"( |
| var<private> m : mat3x4f; |
| |
| fn f() { |
| let c = 1; |
| let index = c; |
| let predicate = (u32(index) <= 2u); |
| if (predicate) { |
| m[index] += vec4f(1); |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Texture builtin calls. |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| TEST_P(RobustnessTest, TextureDimensions) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| fn dimensions() { |
| let l = textureDimensions(t); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureDimensions_Level) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| fn dimensions_signed(level : i32) { |
| let l = textureDimensions(t, level); |
| } |
| |
| fn dimensions_unsigned(level : u32) { |
| let l = textureDimensions(t, level); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| dimensions_signed(i32(non_uniform.x)); |
| dimensions_unsigned(u32(non_uniform.x)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| fn dimensions_signed(level : i32) { |
| let level_idx = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureDimensions(t, level_idx); |
| } |
| |
| fn dimensions_unsigned(level : u32) { |
| let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureDimensions(t, level_idx_1); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| dimensions_signed(i32(non_uniform.x)); |
| dimensions_unsigned(u32(non_uniform.x)); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| fn dimensions_signed(level : i32) { |
| let level_idx = u32(level); |
| let num_levels = textureNumLevels(t); |
| var predicated_value : vec2<u32>; |
| if ((level_idx < num_levels)) { |
| predicated_value = textureDimensions(t, level_idx); |
| } |
| let l = predicated_value; |
| } |
| |
| fn dimensions_unsigned(level : u32) { |
| let level_idx_1 = u32(level); |
| let num_levels_1 = textureNumLevels(t); |
| var predicated_value_1 : vec2<u32>; |
| if ((level_idx_1 < num_levels_1)) { |
| predicated_value_1 = textureDimensions(t, level_idx_1); |
| } |
| let l = predicated_value_1; |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| dimensions_signed(i32(non_uniform.x)); |
| dimensions_unsigned(u32(non_uniform.x)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureGather) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn gather(coords : vec2f) { |
| let l = textureGather(0, t, s, coords); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureGather_Array) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d_array<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn gather_signed(coords : vec2f, array : i32) { |
| let l = textureGather(1, t, s, coords, array); |
| } |
| |
| fn gather_unsigned(coords : vec2f, array : u32) { |
| let l = textureGather(1, t, s, coords, array); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| gather_signed(non_uniform.xy, i32(non_uniform.x)); |
| gather_unsigned(non_uniform.xy, u32(non_uniform.x)); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureGatherCompare) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d; |
| |
| @group(0) @binding(1) var s : sampler_comparison; |
| |
| fn gather(coords : vec2f, depth_ref : f32) { |
| let l = textureGatherCompare(t, s, coords, depth_ref); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureGatherCompare_Array) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d_array; |
| |
| @group(0) @binding(1) var s : sampler_comparison; |
| |
| fn gather_signed(coords : vec2f, array : i32, depth_ref : f32) { |
| let l = textureGatherCompare(t, s, coords, array, depth_ref); |
| } |
| |
| fn gather_unsigned(coords : vec2f, array : u32, depth_ref : f32) { |
| let l = textureGatherCompare(t, s, coords, array, depth_ref); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| gather_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.x); |
| gather_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.x); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureLoad_1D) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_1d<f32>; |
| |
| fn load_signed(coords : i32, level : i32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| fn load_unsigned(coords : u32, level : u32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| fn load_mixed(coords : i32, level : u32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(i32(non_uniform.x), i32(non_uniform.x)); |
| load_unsigned(u32(non_uniform.x), u32(non_uniform.x)); |
| load_mixed(i32(non_uniform.x), u32(non_uniform.x)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_1d<f32>; |
| |
| fn load_signed(coords : i32, level : i32) { |
| let level_idx = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, clamp(coords, 0, i32((textureDimensions(t, level_idx) - 1))), level_idx); |
| } |
| |
| fn load_unsigned(coords : u32, level : u32) { |
| let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - 1)), level_idx_1); |
| } |
| |
| fn load_mixed(coords : i32, level : u32) { |
| let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, clamp(coords, 0, i32((textureDimensions(t, level_idx_2) - 1))), level_idx_2); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(i32(non_uniform.x), i32(non_uniform.x)); |
| load_unsigned(u32(non_uniform.x), u32(non_uniform.x)); |
| load_mixed(i32(non_uniform.x), u32(non_uniform.x)); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_1d<f32>; |
| |
| fn load_signed(coords : i32, level : i32) { |
| let level_idx = u32(level); |
| let num_levels = textureNumLevels(t); |
| let coords_1 = u32(coords); |
| var predicated_value : vec4<f32>; |
| if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) { |
| predicated_value = textureLoad(t, coords_1, level_idx); |
| } |
| let l = predicated_value; |
| } |
| |
| fn load_unsigned(coords : u32, level : u32) { |
| let level_idx_1 = u32(level); |
| let num_levels_1 = textureNumLevels(t); |
| let coords_2 = u32(coords); |
| var predicated_value_1 : vec4<f32>; |
| if (((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1))))))) { |
| predicated_value_1 = textureLoad(t, coords_2, level_idx_1); |
| } |
| let l = predicated_value_1; |
| } |
| |
| fn load_mixed(coords : i32, level : u32) { |
| let level_idx_2 = u32(level); |
| let num_levels_2 = textureNumLevels(t); |
| let coords_3 = u32(coords); |
| var predicated_value_2 : vec4<f32>; |
| if (((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1))))))) { |
| predicated_value_2 = textureLoad(t, coords_3, level_idx_2); |
| } |
| let l = predicated_value_2; |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(i32(non_uniform.x), i32(non_uniform.x)); |
| load_unsigned(u32(non_uniform.x), u32(non_uniform.x)); |
| load_mixed(i32(non_uniform.x), u32(non_uniform.x)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureLoad_2D) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| fn load_signed(coords : vec2i, level : i32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| fn load_unsigned(coords : vec2u, level : u32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| fn load_mixed(coords : vec2u, level : i32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x)); |
| load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| fn load_signed(coords : vec2i, level : i32) { |
| let level_idx = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), level_idx); |
| } |
| |
| fn load_unsigned(coords : vec2u, level : u32) { |
| let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - vec2(1))), level_idx_1); |
| } |
| |
| fn load_mixed(coords : vec2u, level : i32) { |
| let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_2) - vec2(1))), level_idx_2); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x)); |
| load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x)); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| fn load_signed(coords : vec2i, level : i32) { |
| let level_idx = u32(level); |
| let num_levels = textureNumLevels(t); |
| let coords_1 = vec2<u32>(coords); |
| var predicated_value : vec4<f32>; |
| if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) { |
| predicated_value = textureLoad(t, coords_1, level_idx); |
| } |
| let l = predicated_value; |
| } |
| |
| fn load_unsigned(coords : vec2u, level : u32) { |
| let level_idx_1 = u32(level); |
| let num_levels_1 = textureNumLevels(t); |
| let coords_2 = vec2<u32>(coords); |
| var predicated_value_1 : vec4<f32>; |
| if (((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1))))))) { |
| predicated_value_1 = textureLoad(t, coords_2, level_idx_1); |
| } |
| let l = predicated_value_1; |
| } |
| |
| fn load_mixed(coords : vec2u, level : i32) { |
| let level_idx_2 = u32(level); |
| let num_levels_2 = textureNumLevels(t); |
| let coords_3 = vec2<u32>(coords); |
| var predicated_value_2 : vec4<f32>; |
| if (((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1))))))) { |
| predicated_value_2 = textureLoad(t, coords_3, level_idx_2); |
| } |
| let l = predicated_value_2; |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x)); |
| load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureLoad_2DArray) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d_array<f32>; |
| |
| fn load_signed(coords : vec2i, array : i32, level : i32) { |
| let l = textureLoad(t, coords, array, level); |
| } |
| |
| fn load_unsigned(coords : vec2u, array : u32, level : u32) { |
| let l = textureLoad(t, coords, array, level); |
| } |
| |
| fn load_mixed(coords : vec2u, array : i32, level : u32) { |
| let l = textureLoad(t, coords, array, level); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x)); |
| load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_2d_array<f32>; |
| |
| fn load_signed(coords : vec2i, array : i32, level : i32) { |
| let level_idx = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), clamp(array, 0, i32((textureNumLayers(t) - 1))), level_idx); |
| } |
| |
| fn load_unsigned(coords : vec2u, array : u32, level : u32) { |
| let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - vec2(1))), min(array, (textureNumLayers(t) - 1)), level_idx_1); |
| } |
| |
| fn load_mixed(coords : vec2u, array : i32, level : u32) { |
| let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_2) - vec2(1))), clamp(array, 0, i32((textureNumLayers(t) - 1))), level_idx_2); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x)); |
| load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x)); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_2d_array<f32>; |
| |
| fn load_signed(coords : vec2i, array : i32, level : i32) { |
| let level_idx = u32(level); |
| let num_levels = textureNumLevels(t); |
| let coords_1 = vec2<u32>(coords); |
| let array_idx = u32(array); |
| var predicated_value : vec4<f32>; |
| if ((((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1)))))) & (array_idx < textureNumLayers(t)))) { |
| predicated_value = textureLoad(t, coords_1, array_idx, level_idx); |
| } |
| let l = predicated_value; |
| } |
| |
| fn load_unsigned(coords : vec2u, array : u32, level : u32) { |
| let level_idx_1 = u32(level); |
| let num_levels_1 = textureNumLevels(t); |
| let coords_2 = vec2<u32>(coords); |
| let array_idx_1 = u32(array); |
| var predicated_value_1 : vec4<f32>; |
| if ((((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1)))))) & (array_idx_1 < textureNumLayers(t)))) { |
| predicated_value_1 = textureLoad(t, coords_2, array_idx_1, level_idx_1); |
| } |
| let l = predicated_value_1; |
| } |
| |
| fn load_mixed(coords : vec2u, array : i32, level : u32) { |
| let level_idx_2 = u32(level); |
| let num_levels_2 = textureNumLevels(t); |
| let coords_3 = vec2<u32>(coords); |
| let array_idx_2 = u32(array); |
| var predicated_value_2 : vec4<f32>; |
| if ((((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1)))))) & (array_idx_2 < textureNumLayers(t)))) { |
| predicated_value_2 = textureLoad(t, coords_3, array_idx_2, level_idx_2); |
| } |
| let l = predicated_value_2; |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x)); |
| load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureLoad_3D) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_3d<f32>; |
| |
| fn load_signed(coords : vec3i, level : i32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| fn load_unsigned(coords : vec3u, level : u32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| fn load_mixed(coords : vec3u, level : i32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec3i(non_uniform.xyz), i32(non_uniform.x)); |
| load_unsigned(vec3u(non_uniform.xyz), u32(non_uniform.x)); |
| load_mixed(vec3u(non_uniform.xyz), i32(non_uniform.x)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_3d<f32>; |
| |
| fn load_signed(coords : vec3i, level : i32) { |
| let level_idx = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, clamp(coords, vec3(0), vec3<i32>((textureDimensions(t, level_idx) - vec3(1)))), level_idx); |
| } |
| |
| fn load_unsigned(coords : vec3u, level : u32) { |
| let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - vec3(1))), level_idx_1); |
| } |
| |
| fn load_mixed(coords : vec3u, level : i32) { |
| let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_2) - vec3(1))), level_idx_2); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec3i(non_uniform.xyz), i32(non_uniform.x)); |
| load_unsigned(vec3u(non_uniform.xyz), u32(non_uniform.x)); |
| load_mixed(vec3u(non_uniform.xyz), i32(non_uniform.x)); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_3d<f32>; |
| |
| fn load_signed(coords : vec3i, level : i32) { |
| let level_idx = u32(level); |
| let num_levels = textureNumLevels(t); |
| let coords_1 = vec3<u32>(coords); |
| var predicated_value : vec4<f32>; |
| if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) { |
| predicated_value = textureLoad(t, coords_1, level_idx); |
| } |
| let l = predicated_value; |
| } |
| |
| fn load_unsigned(coords : vec3u, level : u32) { |
| let level_idx_1 = u32(level); |
| let num_levels_1 = textureNumLevels(t); |
| let coords_2 = vec3<u32>(coords); |
| var predicated_value_1 : vec4<f32>; |
| if (((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1))))))) { |
| predicated_value_1 = textureLoad(t, coords_2, level_idx_1); |
| } |
| let l = predicated_value_1; |
| } |
| |
| fn load_mixed(coords : vec3u, level : i32) { |
| let level_idx_2 = u32(level); |
| let num_levels_2 = textureNumLevels(t); |
| let coords_3 = vec3<u32>(coords); |
| var predicated_value_2 : vec4<f32>; |
| if (((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1))))))) { |
| predicated_value_2 = textureLoad(t, coords_3, level_idx_2); |
| } |
| let l = predicated_value_2; |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec3i(non_uniform.xyz), i32(non_uniform.x)); |
| load_unsigned(vec3u(non_uniform.xyz), u32(non_uniform.x)); |
| load_mixed(vec3u(non_uniform.xyz), i32(non_uniform.x)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureLoad_Multisampled2D) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_multisampled_2d<f32>; |
| |
| fn load_signed(coords : vec2i, sample : i32) { |
| let l = textureLoad(t, coords, sample); |
| } |
| |
| fn load_unsigned(coords : vec2u, sample : u32) { |
| let l = textureLoad(t, coords, sample); |
| } |
| |
| fn load_mixed(coords : vec2i, sample : u32) { |
| let l = textureLoad(t, coords, sample); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x)); |
| load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_multisampled_2d<f32>; |
| |
| fn load_signed(coords : vec2i, sample : i32) { |
| let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t) - vec2(1)))), sample); |
| } |
| |
| fn load_unsigned(coords : vec2u, sample : u32) { |
| let l = textureLoad(t, min(coords, (textureDimensions(t) - vec2(1))), sample); |
| } |
| |
| fn load_mixed(coords : vec2i, sample : u32) { |
| let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t) - vec2(1)))), sample); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x)); |
| load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x)); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_multisampled_2d<f32>; |
| |
| fn load_signed(coords : vec2i, sample : i32) { |
| let coords_1 = vec2<u32>(coords); |
| var predicated_value : vec4<f32>; |
| if (all((coords_1 < textureDimensions(t)))) { |
| predicated_value = textureLoad(t, coords_1, sample); |
| } |
| let l = predicated_value; |
| } |
| |
| fn load_unsigned(coords : vec2u, sample : u32) { |
| let coords_2 = vec2<u32>(coords); |
| var predicated_value_1 : vec4<f32>; |
| if (all((coords_2 < textureDimensions(t)))) { |
| predicated_value_1 = textureLoad(t, coords_2, sample); |
| } |
| let l = predicated_value_1; |
| } |
| |
| fn load_mixed(coords : vec2i, sample : u32) { |
| let coords_3 = vec2<u32>(coords); |
| var predicated_value_2 : vec4<f32>; |
| if (all((coords_3 < textureDimensions(t)))) { |
| predicated_value_2 = textureLoad(t, coords_3, sample); |
| } |
| let l = predicated_value_2; |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x)); |
| load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureLoad_Depth2D) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d; |
| |
| fn load_signed(coords : vec2i, level : i32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| fn load_unsigned(coords : vec2u, level : u32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| fn load_mixed(coords : vec2i, level : u32) { |
| let l = textureLoad(t, coords, level); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x)); |
| load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_depth_2d; |
| |
| fn load_signed(coords : vec2i, level : i32) { |
| let level_idx = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), level_idx); |
| } |
| |
| fn load_unsigned(coords : vec2u, level : u32) { |
| let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - vec2(1))), level_idx_1); |
| } |
| |
| fn load_mixed(coords : vec2i, level : u32) { |
| let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx_2) - vec2(1)))), level_idx_2); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x)); |
| load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x)); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_depth_2d; |
| |
| fn load_signed(coords : vec2i, level : i32) { |
| let level_idx = u32(level); |
| let num_levels = textureNumLevels(t); |
| let coords_1 = vec2<u32>(coords); |
| var predicated_value : f32; |
| if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) { |
| predicated_value = textureLoad(t, coords_1, level_idx); |
| } |
| let l = predicated_value; |
| } |
| |
| fn load_unsigned(coords : vec2u, level : u32) { |
| let level_idx_1 = u32(level); |
| let num_levels_1 = textureNumLevels(t); |
| let coords_2 = vec2<u32>(coords); |
| var predicated_value_1 : f32; |
| if (((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1))))))) { |
| predicated_value_1 = textureLoad(t, coords_2, level_idx_1); |
| } |
| let l = predicated_value_1; |
| } |
| |
| fn load_mixed(coords : vec2i, level : u32) { |
| let level_idx_2 = u32(level); |
| let num_levels_2 = textureNumLevels(t); |
| let coords_3 = vec2<u32>(coords); |
| var predicated_value_2 : f32; |
| if (((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1))))))) { |
| predicated_value_2 = textureLoad(t, coords_3, level_idx_2); |
| } |
| let l = predicated_value_2; |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x)); |
| load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureLoad_Depth2DArray) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d_array; |
| |
| fn load_signed(coords : vec2i, array : i32, level : i32) { |
| let l = textureLoad(t, coords, array, level); |
| } |
| |
| fn load_unsigned(coords : vec2u, array : u32, level : u32) { |
| let l = textureLoad(t, coords, array, level); |
| } |
| |
| fn load_mixed(coords : vec2u, array : i32, level : u32) { |
| let l = textureLoad(t, coords, array, level); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x)); |
| load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_depth_2d_array; |
| |
| fn load_signed(coords : vec2i, array : i32, level : i32) { |
| let level_idx = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), clamp(array, 0, i32((textureNumLayers(t) - 1))), level_idx); |
| } |
| |
| fn load_unsigned(coords : vec2u, array : u32, level : u32) { |
| let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - vec2(1))), min(array, (textureNumLayers(t) - 1)), level_idx_1); |
| } |
| |
| fn load_mixed(coords : vec2u, array : i32, level : u32) { |
| let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1)); |
| let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_2) - vec2(1))), clamp(array, 0, i32((textureNumLayers(t) - 1))), level_idx_2); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x)); |
| load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x)); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_depth_2d_array; |
| |
| fn load_signed(coords : vec2i, array : i32, level : i32) { |
| let level_idx = u32(level); |
| let num_levels = textureNumLevels(t); |
| let coords_1 = vec2<u32>(coords); |
| let array_idx = u32(array); |
| var predicated_value : f32; |
| if ((((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1)))))) & (array_idx < textureNumLayers(t)))) { |
| predicated_value = textureLoad(t, coords_1, array_idx, level_idx); |
| } |
| let l = predicated_value; |
| } |
| |
| fn load_unsigned(coords : vec2u, array : u32, level : u32) { |
| let level_idx_1 = u32(level); |
| let num_levels_1 = textureNumLevels(t); |
| let coords_2 = vec2<u32>(coords); |
| let array_idx_1 = u32(array); |
| var predicated_value_1 : f32; |
| if ((((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1)))))) & (array_idx_1 < textureNumLayers(t)))) { |
| predicated_value_1 = textureLoad(t, coords_2, array_idx_1, level_idx_1); |
| } |
| let l = predicated_value_1; |
| } |
| |
| fn load_mixed(coords : vec2u, array : i32, level : u32) { |
| let level_idx_2 = u32(level); |
| let num_levels_2 = textureNumLevels(t); |
| let coords_3 = vec2<u32>(coords); |
| let array_idx_2 = u32(array); |
| var predicated_value_2 : f32; |
| if ((((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1)))))) & (array_idx_2 < textureNumLayers(t)))) { |
| predicated_value_2 = textureLoad(t, coords_3, array_idx_2, level_idx_2); |
| } |
| let l = predicated_value_2; |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x)); |
| load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x)); |
| load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureLoad_External) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_external; |
| |
| fn load_signed(coords : vec2i) { |
| let l = textureLoad(t, coords); |
| } |
| |
| fn load_unsigned(coords : vec2u) { |
| let l = textureLoad(t, coords); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy)); |
| load_unsigned(vec2u(non_uniform.xy)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_external; |
| |
| fn load_signed(coords : vec2i) { |
| let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t) - vec2(1))))); |
| } |
| |
| fn load_unsigned(coords : vec2u) { |
| let l = textureLoad(t, min(coords, (textureDimensions(t) - vec2(1)))); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy)); |
| load_unsigned(vec2u(non_uniform.xy)); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_external; |
| |
| fn load_signed(coords : vec2i) { |
| let coords_1 = vec2<u32>(coords); |
| var predicated_value : vec4<f32>; |
| if (all((coords_1 < textureDimensions(t)))) { |
| predicated_value = textureLoad(t, coords_1); |
| } |
| let l = predicated_value; |
| } |
| |
| fn load_unsigned(coords : vec2u) { |
| let coords_2 = vec2<u32>(coords); |
| var predicated_value_1 : vec4<f32>; |
| if (all((coords_2 < textureDimensions(t)))) { |
| predicated_value_1 = textureLoad(t, coords_2); |
| } |
| let l = predicated_value_1; |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| load_signed(vec2i(non_uniform.xy)); |
| load_unsigned(vec2u(non_uniform.xy)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureNumLayers) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d_array; |
| |
| fn num_layers(coords : vec2f, depth_ref : f32) { |
| let l = textureNumLayers(t); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureNumLevels) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d; |
| |
| fn num_levels(coords : vec2f, depth_ref : f32) { |
| let l = textureNumLevels(t); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureNumSamples) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_multisampled_2d; |
| |
| fn num_levels(coords : vec2f, depth_ref : f32) { |
| let l = textureNumSamples(t); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSample) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample(coords : vec2f) { |
| let l = textureSample(t, s, coords); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSample_Offset) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample(coords : vec2f) { |
| const offset = vec2i(1); |
| let l = textureSample(t, s, coords, offset); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSample_ArrayIndex) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d_array<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample_signed(coords : vec2f, array : i32) { |
| let l = textureSample(t, s, coords, array); |
| } |
| |
| fn sample_unsigned(coords : vec2f, array : u32) { |
| let l = textureSample(t, s, coords, array); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| sample_signed(non_uniform.xy, i32(non_uniform.x)); |
| sample_unsigned(non_uniform.xy, u32(non_uniform.x)); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleBias) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample_bias(coords : vec2f, bias : f32) { |
| let l = textureSampleBias(t, s, coords, bias); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleBias_Offset) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample_bias(coords : vec2f, bias : f32) { |
| const offset = vec2i(1); |
| let l = textureSampleBias(t, s, coords, bias, offset); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleBias_ArrayIndex) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d_array<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample_bias_signed(coords : vec2f, array : i32, bias : f32) { |
| let l = textureSampleBias(t, s, coords, array, bias); |
| } |
| |
| fn sample_bias_unsigned(coords : vec2f, array : u32, bias : f32) { |
| let l = textureSampleBias(t, s, coords, array, bias); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| sample_bias_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.x); |
| sample_bias_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.x); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleCompare) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d; |
| |
| @group(0) @binding(1) var s : sampler_comparison; |
| |
| fn sample_compare(coords : vec2f, depth_ref : f32) { |
| let l = textureSampleCompare(t, s, coords, depth_ref); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleCompare_Offset) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d; |
| |
| @group(0) @binding(1) var s : sampler_comparison; |
| |
| fn sample_compare(coords : vec2f, depth_ref : f32) { |
| const offset = vec2i(1); |
| let l = textureSampleCompare(t, s, coords, depth_ref, offset); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleCompare_ArrayIndex) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d_array; |
| |
| @group(0) @binding(1) var s : sampler_comparison; |
| |
| fn sample_compare_signed(coords : vec2f, array : i32, depth_ref : f32) { |
| let l = textureSampleCompare(t, s, coords, array, depth_ref); |
| } |
| |
| fn sample_compare_unsigned(coords : vec2f, array : u32, depth_ref : f32) { |
| let l = textureSampleCompare(t, s, coords, array, depth_ref); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| sample_compare_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.x); |
| sample_compare_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.x); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleCompareLevel) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d; |
| |
| @group(0) @binding(1) var s : sampler_comparison; |
| |
| fn sample_compare_level(coords : vec2f, depth_ref : f32) { |
| let l = textureSampleCompareLevel(t, s, coords, depth_ref); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleCompareLevel_Offset) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d; |
| |
| @group(0) @binding(1) var s : sampler_comparison; |
| |
| fn sample_compare_level(coords : vec2f, depth_ref : f32) { |
| const offset = vec2i(1); |
| let l = textureSampleCompareLevel(t, s, coords, depth_ref, offset); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleCompareLevel_ArrayIndex) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_depth_2d_array; |
| |
| @group(0) @binding(1) var s : sampler_comparison; |
| |
| fn sample_compare_level_signed(coords : vec2f, array : i32, depth_ref : f32) { |
| let l = textureSampleCompareLevel(t, s, coords, array, depth_ref); |
| } |
| |
| fn sample_compare_level_unsigned(coords : vec2f, array : u32, depth_ref : f32) { |
| let l = textureSampleCompareLevel(t, s, coords, array, depth_ref); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| sample_compare_level_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.x); |
| sample_compare_level_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.x); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleGrad) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample_compare_level(coords : vec2f, ddx : vec2f, ddy : vec2f) { |
| let l = textureSampleGrad(t, s, coords, ddx, ddy); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleGrad_Offset) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample_compare_level(coords : vec2f, ddx : vec2f, ddy : vec2f) { |
| const offset = vec2i(1); |
| let l = textureSampleGrad(t, s, coords, ddx, ddy, offset); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleGrad_ArrayIndex) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d_array<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample_grad_signed(coords : vec2f, array : i32, ddx : vec2f, ddy : vec2f) { |
| let l = textureSampleGrad(t, s, coords, array, ddx, ddy); |
| } |
| |
| fn sample_grad_unsigned(coords : vec2f, array : u32, ddx : vec2f, ddy : vec2f) { |
| let l = textureSampleGrad(t, s, coords, array, ddx, ddy); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| sample_grad_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.xy, non_uniform.xy); |
| sample_grad_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.xy, non_uniform.xy); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleLevel) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample_compare_level(coords : vec2f, level : f32) { |
| let l = textureSampleLevel(t, s, coords, level); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleLevel_Offset) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample_compare_level(coords : vec2f, level : f32) { |
| const offset = vec2i(1); |
| let l = textureSampleLevel(t, s, coords, level, offset); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleLevel_ArrayIndex) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d_array<f32>; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample_compare_level_signed(coords : vec2f, array : i32, level : f32) { |
| let l = textureSampleLevel(t, s, coords, array, level); |
| } |
| |
| fn sample_compare_level_unsigned(coords : vec2f, array : u32, level : f32) { |
| let l = textureSampleLevel(t, s, coords, array, level); |
| } |
| |
| @fragment |
| fn main(@builtin(position) non_uniform : vec4f) { |
| sample_compare_level_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.x); |
| sample_compare_level_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.x); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureSampleBaseClampToEdge) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_external; |
| |
| @group(0) @binding(1) var s : sampler; |
| |
| fn sample_base_clamp_to_edge(coords : vec2f) { |
| let l = textureSampleBaseClampToEdge(t, s, coords); |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Other |
| //////////////////////////////////////////////////////////////////////////////// |
| TEST_P(RobustnessTest, ShadowedVariable) { |
| auto* src = R"( |
| fn f() { |
| var a : array<f32, 3>; |
| var i : u32; |
| { |
| var a : array<f32, 5>; |
| var b : f32 = a[i]; |
| } |
| var c : f32 = a[i]; |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| fn f() { |
| var a : array<f32, 3>; |
| var i : u32; |
| { |
| var a : array<f32, 5>; |
| var b : f32 = a[min(i, 4u)]; |
| } |
| var c : f32 = a[min(i, 2u)]; |
| } |
| )", |
| /* predicate */ R"( |
| fn f() { |
| var a : array<f32, 3>; |
| var i : u32; |
| { |
| var a : array<f32, 5>; |
| let index = i; |
| let predicate = (u32(index) <= 4u); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = a[index]; |
| } |
| var b : f32 = predicated_expr; |
| } |
| let index_1 = i; |
| let predicate_1 = (u32(index_1) <= 2u); |
| var predicated_expr_1 : f32; |
| if (predicate_1) { |
| predicated_expr_1 = a[index_1]; |
| } |
| var c : f32 = predicated_expr_1; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| // Check that existing use of min() and arrayLength() do not get renamed. |
| TEST_P(RobustnessTest, DontRenameSymbols) { |
| auto* src = R"( |
| struct S { |
| a : f32, |
| b : array<f32>, |
| } |
| |
| @group(0) @binding(0) var<storage, read> s : S; |
| |
| const c : u32 = 1u; |
| |
| fn f() { |
| let b : f32 = s.b[c]; |
| let x : i32 = min(1, 2); |
| let y : u32 = arrayLength(&(s.b)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| struct S { |
| a : f32, |
| b : array<f32>, |
| } |
| |
| @group(0) @binding(0) var<storage, read> s : S; |
| |
| const c : u32 = 1u; |
| |
| fn f() { |
| let b : f32 = s.b[min(c, (arrayLength(&(s.b)) - 1u))]; |
| let x : i32 = min(1, 2); |
| let y : u32 = arrayLength(&(s.b)); |
| } |
| )", |
| /* predicate */ R"( |
| struct S { |
| a : f32, |
| b : array<f32>, |
| } |
| |
| @group(0) @binding(0) var<storage, read> s : S; |
| |
| const c : u32 = 1u; |
| |
| fn f() { |
| let index = c; |
| let predicate = (u32(index) <= (arrayLength(&(s.b)) - 1u)); |
| var predicated_expr : f32; |
| if (predicate) { |
| predicated_expr = s.b[index]; |
| } |
| let b : f32 = predicated_expr; |
| let x : i32 = min(1, 2); |
| let y : u32 = arrayLength(&(s.b)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, WorkgroupOverrideCount) { |
| auto* src = R"( |
| override N = 123; |
| |
| var<workgroup> w : array<f32, N>; |
| |
| fn f() { |
| var b : f32 = w[1i]; |
| } |
| )"; |
| |
| auto* expect = |
| Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ |
| R"(error: array size is an override-expression, when expected a constant-expression. |
| Was the SubstituteOverride transform run?)", |
| /* predicate */ |
| R"(error: array size is an override-expression, when expected a constant-expression. |
| Was the SubstituteOverride transform run?)"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // atomic predication |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| TEST_P(RobustnessTest, AtomicLoad) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| let i = 0; |
| let r = atomicLoad(&(a[i])); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| let i = 0; |
| let r = atomicLoad(&(a[min(u32(i), 3u)])); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| let i = 0; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| var predicated_value : i32; |
| if (predicate) { |
| predicated_value = atomicLoad(&(a[index])); |
| } |
| let r = predicated_value; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, AtomicAnd) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| let i = 0; |
| atomicAnd(&(a[i]), 10); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| let i = 0; |
| atomicAnd(&(a[min(u32(i), 3u)]), 10); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| let i = 0; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| if (predicate) { |
| atomicAnd(&(a[index]), 10); |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // workgroupUniformLoad |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| TEST_P(RobustnessTest, WorkgroupUniformLoad) { |
| auto* src = R"( |
| var<workgroup> a : array<u32, 32>; |
| |
| @compute @workgroup_size(1) |
| fn f() { |
| let i = 1; |
| let p = &(a[i]); |
| let v = workgroupUniformLoad(p); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<workgroup> a : array<u32, 32>; |
| |
| @compute @workgroup_size(1) |
| fn f() { |
| let i = 1; |
| let p = &(a[min(u32(i), 31u)]); |
| let v = workgroupUniformLoad(p); |
| } |
| )", |
| /* predicate */ R"( |
| var<workgroup> a : array<u32, 32>; |
| |
| @compute @workgroup_size(1) |
| fn f() { |
| let i = 1; |
| let index = i; |
| let predicate = (u32(index) <= 31u); |
| let p = &(a[index]); |
| var predicated_value : u32; |
| if (predicate) { |
| predicated_value = workgroupUniformLoad(p); |
| } else { |
| workgroupBarrier(); |
| } |
| let v = predicated_value; |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Usage in loops |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| TEST_P(RobustnessTest, ArrayVal_ForLoopInit) { |
| auto* src = R"( |
| fn f() { |
| let a = array<i32, 3>(); |
| var v = 1; |
| for(var i = a[v]; (i < 3); i++) { |
| var in_loop = 42; |
| } |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| fn f() { |
| let a = array<i32, 3>(); |
| var v = 1; |
| for(var i = a[min(u32(v), 2u)]; (i < 3); i++) { |
| var in_loop = 42; |
| } |
| } |
| )", |
| /* predicate */ R"( |
| fn f() { |
| let a = array<i32, 3>(); |
| var v = 1; |
| { |
| let index = v; |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : i32; |
| if (predicate) { |
| predicated_expr = a[index]; |
| } |
| var i = predicated_expr; |
| loop { |
| if (!((i < 3))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| i++; |
| } |
| } |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, ArrayVal_ForLoopCond) { |
| auto* src = R"( |
| fn f() { |
| let a = array<i32, 3>(); |
| var v = 1; |
| for(var i = 0; (i < a[v]); i++) { |
| var in_loop = 42; |
| } |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| fn f() { |
| let a = array<i32, 3>(); |
| var v = 1; |
| for(var i = 0; (i < a[min(u32(v), 2u)]); i++) { |
| var in_loop = 42; |
| } |
| } |
| )", |
| /* predicate */ R"( |
| fn f() { |
| let a = array<i32, 3>(); |
| var v = 1; |
| { |
| var i = 0; |
| loop { |
| let index = v; |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : i32; |
| if (predicate) { |
| predicated_expr = a[index]; |
| } |
| if (!((i < predicated_expr))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| i++; |
| } |
| } |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, ArrayVal_ForLoopCont) { |
| auto* src = R"( |
| fn f() { |
| let a = array<i32, 3>(); |
| for(var i = 0; (i < 5); i = a[i]) { |
| var in_loop = 42; |
| } |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| fn f() { |
| let a = array<i32, 3>(); |
| for(var i = 0; (i < 5); i = a[min(u32(i), 2u)]) { |
| var in_loop = 42; |
| } |
| } |
| )", |
| /* predicate */ R"( |
| fn f() { |
| let a = array<i32, 3>(); |
| { |
| var i = 0; |
| loop { |
| if (!((i < 5))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| let index = i; |
| let predicate = (u32(index) <= 2u); |
| var predicated_expr : i32; |
| if (predicate) { |
| predicated_expr = a[index]; |
| } |
| i = predicated_expr; |
| } |
| } |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureLoad_ForLoopInit) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<i32>; |
| |
| fn f() { |
| var coords = vec2(1); |
| var level = 1; |
| for(var i = textureLoad(t, coords, level).x; (i < 3); i++) { |
| var in_loop = 42; |
| } |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_2d<i32>; |
| |
| fn f() { |
| var coords = vec2(1); |
| var level = 1; |
| { |
| let level_idx = min(u32(level), (textureNumLevels(t) - 1)); |
| var i = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), level_idx).x; |
| loop { |
| if (!((i < 3))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| i++; |
| } |
| } |
| } |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_2d<i32>; |
| |
| fn f() { |
| var coords = vec2(1); |
| var level = 1; |
| { |
| let level_idx = u32(level); |
| let num_levels = textureNumLevels(t); |
| let coords_1 = vec2<u32>(coords); |
| var predicated_value : vec4<i32>; |
| if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) { |
| predicated_value = textureLoad(t, coords_1, level_idx); |
| } |
| var i = predicated_value.x; |
| loop { |
| if (!((i < 3))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| i++; |
| } |
| } |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureLoad_ForLoopCond) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<i32>; |
| |
| fn f() { |
| var coords = vec2(1); |
| var level = 1; |
| for(var i = 0; (i < textureLoad(t, coords, level).x); i++) { |
| var in_loop = 42; |
| } |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_2d<i32>; |
| |
| fn f() { |
| var coords = vec2(1); |
| var level = 1; |
| { |
| var i = 0; |
| loop { |
| let level_idx = min(u32(level), (textureNumLevels(t) - 1)); |
| if (!((i < textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), level_idx).x))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| i++; |
| } |
| } |
| } |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_2d<i32>; |
| |
| fn f() { |
| var coords = vec2(1); |
| var level = 1; |
| { |
| var i = 0; |
| loop { |
| let level_idx = u32(level); |
| let num_levels = textureNumLevels(t); |
| let coords_1 = vec2<u32>(coords); |
| var predicated_value : vec4<i32>; |
| if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) { |
| predicated_value = textureLoad(t, coords_1, level_idx); |
| } |
| if (!((i < predicated_value.x))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| i++; |
| } |
| } |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, TextureLoad_ForLoopCont) { |
| auto* src = R"( |
| @group(0) @binding(0) var t : texture_2d<i32>; |
| |
| fn f() { |
| var level = 1; |
| for(var i = 0; (i < 5); i = textureLoad(t, vec2(i), i).x) { |
| var in_loop = 42; |
| } |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var t : texture_2d<i32>; |
| |
| fn f() { |
| var level = 1; |
| { |
| var i = 0; |
| loop { |
| if (!((i < 5))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| let level_idx = min(u32(i), (textureNumLevels(t) - 1)); |
| i = textureLoad(t, clamp(vec2(i), vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), level_idx).x; |
| } |
| } |
| } |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var t : texture_2d<i32>; |
| |
| fn f() { |
| var level = 1; |
| { |
| var i = 0; |
| loop { |
| if (!((i < 5))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| let level_idx = u32(i); |
| let num_levels = textureNumLevels(t); |
| let coords = vec2<u32>(vec2(i)); |
| var predicated_value : vec4<i32>; |
| if (((level_idx < num_levels) & all((coords < textureDimensions(t, min(level_idx, (num_levels - 1))))))) { |
| predicated_value = textureLoad(t, coords, level_idx); |
| } |
| i = predicated_value.x; |
| } |
| } |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, AtomicXor_ForLoopInit) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| var i = 0; |
| for(atomicXor(&(a[i]), 4); (i < 3); i++) { |
| var in_loop = 42; |
| } |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| var i = 0; |
| for(atomicXor(&(a[min(u32(i), 3u)]), 4); (i < 3); i++) { |
| var in_loop = 42; |
| } |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| var i = 0; |
| { |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| if (predicate) { |
| atomicXor(&(a[index]), 4); |
| } |
| loop { |
| if (!((i < 3))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| i++; |
| } |
| } |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, AtomicXor_ForLoopCond) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| for(var i = 0; (i < atomicXor(&(a[i]), 4)); i++) { |
| var in_loop = 42; |
| } |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| for(var i = 0; (i < atomicXor(&(a[min(u32(i), 3u)]), 4)); i++) { |
| var in_loop = 42; |
| } |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| { |
| var i = 0; |
| loop { |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| var predicated_value : i32; |
| if (predicate) { |
| predicated_value = atomicXor(&(a[index]), 4); |
| } |
| if (!((i < predicated_value))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| i++; |
| } |
| } |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, AtomicXor_ForLoopCont) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| for(var i = 0; (i < 5); i = atomicXor(&(a[i]), 4)) { |
| var in_loop = 42; |
| } |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| for(var i = 0; (i < 5); i = atomicXor(&(a[min(u32(i), 3u)]), 4)) { |
| var in_loop = 42; |
| } |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>; |
| |
| fn f() { |
| { |
| var i = 0; |
| loop { |
| if (!((i < 5))) { |
| break; |
| } |
| { |
| var in_loop = 42; |
| } |
| |
| continuing { |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| var predicated_value : i32; |
| if (predicate) { |
| predicated_value = atomicXor(&(a[index]), 4); |
| } |
| i = predicated_value; |
| } |
| } |
| } |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // User pointer parameters |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| TEST_P(RobustnessTest, Read_PrivatePointerParameter_IndexWithConstant) { |
| auto* src = R"( |
| var<private> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<private, i32>, post : i32) -> i32 { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<private, i32>, post : i32) -> i32 { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| y(1, &(a[1]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ src, |
| /* predicate */ R"( |
| var<private> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<private, i32>, p_predicate : bool, post : i32) -> i32 { |
| var predicated_expr : i32; |
| if (p_predicate) { |
| predicated_expr = *(p); |
| } |
| return ((pre + predicated_expr) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<private, i32>, p_predicate_1 : bool, post : i32) -> i32 { |
| return x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| y(1, &(a[1]), true, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_WorkgroupPointerParameter_IndexWithConstant) { |
| auto* src = R"( |
| var<workgroup> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| y(1, &(a[1]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ src, |
| /* predicate */ R"( |
| var<workgroup> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<workgroup, i32>, p_predicate : bool, post : i32) -> i32 { |
| var predicated_expr : i32; |
| if (p_predicate) { |
| predicated_expr = *(p); |
| } |
| return ((pre + predicated_expr) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<workgroup, i32>, p_predicate_1 : bool, post : i32) -> i32 { |
| return x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| y(1, &(a[1]), true, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_UniformPointerParameter_IndexWithConstant) { |
| auto* src = R"( |
| @group(0) @binding(0) var<uniform> a : array<vec4i, 4>; |
| |
| fn x(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| y(vec4(1), &(a[1]), vec4(2)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ src, |
| /* predicate */ R"( |
| @group(0) @binding(0) var<uniform> a : array<vec4i, 4>; |
| |
| fn x(pre : vec4i, p : ptr<uniform, vec4i>, p_predicate : bool, post : vec4i) -> vec4i { |
| var predicated_expr : vec4<i32>; |
| if (p_predicate) { |
| predicated_expr = *(p); |
| } |
| return ((pre + predicated_expr) + post); |
| } |
| |
| fn y(pre : vec4i, p : ptr<uniform, vec4i>, p_predicate_1 : bool, post : vec4i) -> vec4i { |
| return x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| y(vec4(1), &(a[1]), true, vec4(2)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_StoragePointerParameter_IndexWithConstant) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage> a : array<vec4i, 4>; |
| |
| fn x(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| y(vec4(1), &(a[1]), vec4(2)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ src, |
| /* predicate */ R"( |
| @group(0) @binding(0) var<storage> a : array<vec4i, 4>; |
| |
| fn x(pre : vec4i, p : ptr<storage, vec4i>, p_predicate : bool, post : vec4i) -> vec4i { |
| var predicated_expr : vec4<i32>; |
| if (p_predicate) { |
| predicated_expr = *(p); |
| } |
| return ((pre + predicated_expr) + post); |
| } |
| |
| fn y(pre : vec4i, p : ptr<storage, vec4i>, p_predicate_1 : bool, post : vec4i) -> vec4i { |
| return x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| y(vec4(1), &(a[1]), true, vec4(2)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_FunctionPointerParameter_IndexWithConstant) { |
| auto* src = R"( |
| fn x(pre : i32, p : ptr<function, i32>, post : i32) -> i32 { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<function, i32>, post : i32) -> i32 { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| var a : array<i32, 4>; |
| y(1, &(a[1]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ src, |
| /* predicate */ R"( |
| fn x(pre : i32, p : ptr<function, i32>, p_predicate : bool, post : i32) -> i32 { |
| var predicated_expr : i32; |
| if (p_predicate) { |
| predicated_expr = *(p); |
| } |
| return ((pre + predicated_expr) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<function, i32>, p_predicate_1 : bool, post : i32) -> i32 { |
| return x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| var a : array<i32, 4>; |
| y(1, &(a[1]), true, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_PrivatePointerParameter_IndexWithLet) { |
| auto* src = R"( |
| var<private> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<private, i32>, post : i32) -> i32 { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<private, i32>, post : i32) -> i32 { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(1, &(a[i]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<private, i32>, post : i32) -> i32 { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<private, i32>, post : i32) -> i32 { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(1, &(a[min(u32(i), 3u)]), 2); |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<private, i32>, p_predicate : bool, post : i32) -> i32 { |
| var predicated_expr : i32; |
| if (p_predicate) { |
| predicated_expr = *(p); |
| } |
| return ((pre + predicated_expr) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<private, i32>, p_predicate_1 : bool, post : i32) -> i32 { |
| return x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| y(1, &(a[index]), predicate, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_WorkgroupPointerParameter_IndexWithLet) { |
| auto* src = R"( |
| var<workgroup> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(1, &(a[i]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<workgroup> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(1, &(a[min(u32(i), 3u)]), 2); |
| } |
| )", |
| /* predicate */ R"( |
| var<workgroup> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<workgroup, i32>, p_predicate : bool, post : i32) -> i32 { |
| var predicated_expr : i32; |
| if (p_predicate) { |
| predicated_expr = *(p); |
| } |
| return ((pre + predicated_expr) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<workgroup, i32>, p_predicate_1 : bool, post : i32) -> i32 { |
| return x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| y(1, &(a[index]), predicate, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_UniformPointerParameter_IndexWithLet) { |
| auto* src = R"( |
| @group(0) @binding(0) var<uniform> a : array<vec4i, 4>; |
| |
| fn x(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(vec4(1), &(a[i]), vec4(2)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var<uniform> a : array<vec4i, 4>; |
| |
| fn x(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(vec4(1), &(a[min(u32(i), 3u)]), vec4(2)); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var<uniform> a : array<vec4i, 4>; |
| |
| fn x(pre : vec4i, p : ptr<uniform, vec4i>, p_predicate : bool, post : vec4i) -> vec4i { |
| var predicated_expr : vec4<i32>; |
| if (p_predicate) { |
| predicated_expr = *(p); |
| } |
| return ((pre + predicated_expr) + post); |
| } |
| |
| fn y(pre : vec4i, p : ptr<uniform, vec4i>, p_predicate_1 : bool, post : vec4i) -> vec4i { |
| return x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| y(vec4(1), &(a[index]), predicate, vec4(2)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_StoragePointerParameter_IndexWithLet) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage> a : array<vec4i, 4>; |
| |
| fn x(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(vec4(1), &(a[i]), vec4(2)); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var<storage> a : array<vec4i, 4>; |
| |
| fn x(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(vec4(1), &(a[min(u32(i), 3u)]), vec4(2)); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var<storage> a : array<vec4i, 4>; |
| |
| fn x(pre : vec4i, p : ptr<storage, vec4i>, p_predicate : bool, post : vec4i) -> vec4i { |
| var predicated_expr : vec4<i32>; |
| if (p_predicate) { |
| predicated_expr = *(p); |
| } |
| return ((pre + predicated_expr) + post); |
| } |
| |
| fn y(pre : vec4i, p : ptr<storage, vec4i>, p_predicate_1 : bool, post : vec4i) -> vec4i { |
| return x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| y(vec4(1), &(a[index]), predicate, vec4(2)); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_FunctionPointerParameter_IndexWithLet) { |
| auto* src = R"( |
| fn x(pre : i32, p : ptr<function, i32>, post : i32) -> i32 { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<function, i32>, post : i32) -> i32 { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| var a : array<i32, 4>; |
| let i = 0; |
| y(1, &(a[i]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| fn x(pre : i32, p : ptr<function, i32>, post : i32) -> i32 { |
| return ((pre + *(p)) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<function, i32>, post : i32) -> i32 { |
| return x(pre, p, post); |
| } |
| |
| fn z() { |
| var a : array<i32, 4>; |
| let i = 0; |
| y(1, &(a[min(u32(i), 3u)]), 2); |
| } |
| )", |
| /* predicate */ R"( |
| fn x(pre : i32, p : ptr<function, i32>, p_predicate : bool, post : i32) -> i32 { |
| var predicated_expr : i32; |
| if (p_predicate) { |
| predicated_expr = *(p); |
| } |
| return ((pre + predicated_expr) + post); |
| } |
| |
| fn y(pre : i32, p : ptr<function, i32>, p_predicate_1 : bool, post : i32) -> i32 { |
| return x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| var a : array<i32, 4>; |
| let i = 0; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| y(1, &(a[index]), predicate, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Write_PrivatePointerParameter_IndexWithConstant) { |
| auto* src = R"( |
| var<private> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<private, i32>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<private, i32>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| y(1, &(a[1]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ src, |
| /* predicate */ R"( |
| var<private> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<private, i32>, p_predicate : bool, post : i32) { |
| if (p_predicate) { |
| *(p) = (pre + post); |
| } |
| } |
| |
| fn y(pre : i32, p : ptr<private, i32>, p_predicate_1 : bool, post : i32) { |
| x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| y(1, &(a[1]), true, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Write_WorkgroupPointerParameter_IndexWithConstant) { |
| auto* src = R"( |
| var<workgroup> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| y(1, &(a[1]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ src, |
| /* predicate */ R"( |
| var<workgroup> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<workgroup, i32>, p_predicate : bool, post : i32) { |
| if (p_predicate) { |
| *(p) = (pre + post); |
| } |
| } |
| |
| fn y(pre : i32, p : ptr<workgroup, i32>, p_predicate_1 : bool, post : i32) { |
| x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| y(1, &(a[1]), true, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Write_StoragePointerParameter_IndexWithConstant) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<storage, i32, read_write>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<storage, i32, read_write>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| y(1, &(a[1]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ src, |
| /* predicate */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<storage, i32, read_write>, p_predicate : bool, post : i32) { |
| if (p_predicate) { |
| *(p) = (pre + post); |
| } |
| } |
| |
| fn y(pre : i32, p : ptr<storage, i32, read_write>, p_predicate_1 : bool, post : i32) { |
| x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| y(1, &(a[1]), true, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Write_FunctionPointerParameter_IndexWithConstant) { |
| auto* src = R"( |
| fn x(pre : i32, p : ptr<function, i32>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<function, i32>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| var a : array<i32, 4>; |
| y(1, &(a[1]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ src, |
| /* predicate */ R"( |
| fn x(pre : i32, p : ptr<function, i32>, p_predicate : bool, post : i32) { |
| if (p_predicate) { |
| *(p) = (pre + post); |
| } |
| } |
| |
| fn y(pre : i32, p : ptr<function, i32>, p_predicate_1 : bool, post : i32) { |
| x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| var a : array<i32, 4>; |
| y(1, &(a[1]), true, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Write_PrivatePointerParameter_IndexWithLet) { |
| auto* src = R"( |
| var<private> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<private, i32>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<private, i32>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(1, &(a[i]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<private> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<private, i32>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<private, i32>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(1, &(a[min(u32(i), 3u)]), 2); |
| } |
| )", |
| /* predicate */ R"( |
| var<private> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<private, i32>, p_predicate : bool, post : i32) { |
| if (p_predicate) { |
| *(p) = (pre + post); |
| } |
| } |
| |
| fn y(pre : i32, p : ptr<private, i32>, p_predicate_1 : bool, post : i32) { |
| x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| y(1, &(a[index]), predicate, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Write_WorkgroupPointerParameter_IndexWithLet) { |
| auto* src = R"( |
| var<workgroup> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(1, &(a[i]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| var<workgroup> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(1, &(a[min(u32(i), 3u)]), 2); |
| } |
| )", |
| /* predicate */ R"( |
| var<workgroup> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<workgroup, i32>, p_predicate : bool, post : i32) { |
| if (p_predicate) { |
| *(p) = (pre + post); |
| } |
| } |
| |
| fn y(pre : i32, p : ptr<workgroup, i32>, p_predicate_1 : bool, post : i32) { |
| x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| y(1, &(a[index]), predicate, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Write_StoragePointerParameter_IndexWithLet) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<storage, i32, read_write>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<storage, i32, read_write>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(1, &(a[i]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<storage, i32, read_write>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<storage, i32, read_write>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| y(1, &(a[min(u32(i), 3u)]), 2); |
| } |
| )", |
| /* predicate */ R"( |
| @group(0) @binding(0) var<storage, read_write> a : array<i32, 4>; |
| |
| fn x(pre : i32, p : ptr<storage, i32, read_write>, p_predicate : bool, post : i32) { |
| if (p_predicate) { |
| *(p) = (pre + post); |
| } |
| } |
| |
| fn y(pre : i32, p : ptr<storage, i32, read_write>, p_predicate_1 : bool, post : i32) { |
| x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| let i = 0; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| y(1, &(a[index]), predicate, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Write_FunctionPointerParameter_IndexWithLet) { |
| auto* src = R"( |
| fn x(pre : i32, p : ptr<function, i32>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<function, i32>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| var a : array<i32, 4>; |
| let i = 0; |
| y(1, &(a[i]), 2); |
| } |
| )"; |
| |
| auto* expect = Expect(GetParam(), |
| /* ignore */ src, |
| /* clamp */ R"( |
| fn x(pre : i32, p : ptr<function, i32>, post : i32) { |
| *(p) = (pre + post); |
| } |
| |
| fn y(pre : i32, p : ptr<function, i32>, post : i32) { |
| x(pre, p, post); |
| } |
| |
| fn z() { |
| var a : array<i32, 4>; |
| let i = 0; |
| y(1, &(a[min(u32(i), 3u)]), 2); |
| } |
| )", |
| /* predicate */ R"( |
| fn x(pre : i32, p : ptr<function, i32>, p_predicate : bool, post : i32) { |
| if (p_predicate) { |
| *(p) = (pre + post); |
| } |
| } |
| |
| fn y(pre : i32, p : ptr<function, i32>, p_predicate_1 : bool, post : i32) { |
| x(pre, p, p_predicate_1, post); |
| } |
| |
| fn z() { |
| var a : array<i32, 4>; |
| let i = 0; |
| let index = i; |
| let predicate = (u32(index) <= 3u); |
| y(1, &(a[index]), predicate, 2); |
| } |
| )"); |
| |
| auto got = Run<Robustness>(src, Config(GetParam())); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // disable_runtime_sized_array_index_clamping == true |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| TEST_P(RobustnessTest, Read_disable_unsized_array_index_clamping_i32) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read> s : array<f32>; |
| |
| fn f() { |
| let i = 25i; |
| var d : f32 = s[i]; |
| } |
| )"; |
| |
| auto* expect = R"( |
| @group(0) @binding(0) var<storage, read> s : array<f32>; |
| |
| fn f() { |
| let i = 25i; |
| var d : f32 = s[u32(i)]; |
| } |
| )"; |
| |
| auto got = Run<Robustness>(src, Config(GetParam(), true)); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_disable_unsized_array_index_clamping_u32) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read> s : array<f32>; |
| |
| fn f() { |
| let i = 25u; |
| var d : f32 = s[i]; |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam(), true)); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_disable_unsized_array_index_clamping_abstract_int) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read> s : array<f32>; |
| |
| fn f() { |
| var d : f32 = s[25]; |
| } |
| )"; |
| |
| auto* expect = R"( |
| @group(0) @binding(0) var<storage, read> s : array<f32>; |
| |
| fn f() { |
| var d : f32 = s[u32(25)]; |
| } |
| )"; |
| |
| auto got = Run<Robustness>(src, Config(GetParam(), true)); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Read_disable_unsized_array_index_clamping_abstract_int_ViaPointerIndex) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read> s : array<f32>; |
| |
| fn f() { |
| let p = &(s); |
| var d : f32 = p[25]; |
| } |
| )"; |
| |
| auto* expect = R"( |
| @group(0) @binding(0) var<storage, read> s : array<f32>; |
| |
| fn f() { |
| let p = &(s); |
| var d : f32 = p[u32(25)]; |
| } |
| )"; |
| |
| auto got = Run<Robustness>(src, Config(GetParam(), true)); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Assign_disable_unsized_array_index_clamping_i32) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read_write> s : array<f32>; |
| |
| fn f() { |
| let i = 25i; |
| s[i] = 0.5f; |
| } |
| )"; |
| |
| auto* expect = R"( |
| @group(0) @binding(0) var<storage, read_write> s : array<f32>; |
| |
| fn f() { |
| let i = 25i; |
| s[u32(i)] = 0.5f; |
| } |
| )"; |
| |
| auto got = Run<Robustness>(src, Config(GetParam(), true)); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Assign_disable_unsized_array_index_clamping_u32) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read_write> s : array<f32>; |
| |
| fn f() { |
| let i = 25u; |
| s[i] = 0.5f; |
| } |
| )"; |
| |
| auto* expect = src; |
| |
| auto got = Run<Robustness>(src, Config(GetParam(), true)); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Assign_disable_unsized_array_index_clamping_abstract_int) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read_write> s : array<f32>; |
| |
| fn f() { |
| s[25] = 0.5f; |
| } |
| )"; |
| |
| auto* expect = R"( |
| @group(0) @binding(0) var<storage, read_write> s : array<f32>; |
| |
| fn f() { |
| s[u32(25)] = 0.5f; |
| } |
| )"; |
| |
| auto got = Run<Robustness>(src, Config(GetParam(), true)); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| TEST_P(RobustnessTest, Assign_disable_unsized_array_index_clamping_abstract_int_ViaPointerIndex) { |
| auto* src = R"( |
| @group(0) @binding(0) var<storage, read_write> s : array<f32>; |
| |
| fn f() { |
| let p = &(s); |
| p[25] = 0.5f; |
| } |
| )"; |
| |
| auto* expect = R"( |
| @group(0) @binding(0) var<storage, read_write> s : array<f32>; |
| |
| fn f() { |
| let p = &(s); |
| p[u32(25)] = 0.5f; |
| } |
| )"; |
| |
| auto got = Run<Robustness>(src, Config(GetParam(), true)); |
| |
| EXPECT_EQ(expect, str(got)); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(, |
| RobustnessTest, |
| testing::Values(Robustness::Action::kIgnore, |
| Robustness::Action::kClamp, |
| Robustness::Action::kPredicate)); |
| } // namespace |
| } // namespace tint::ast::transform |