blob: e2074ef43da3ca77cd73d2ed41f1c3046f3eb01c [file] [log] [blame]
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#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_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_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_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, Conf