| // 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); |
| } |
| |