dawn-cmake/src/tint/transform/robustness_test.cc
Ben Clayton 8525ff29da tint/transform/robustness: Implement predicated mode
This change overhauls the Robustness transform to support three modes,
per address space:
* ignore    - Disable robustness checks for the address space
* clamp     - Clamp indices / texture args to ensure they're in
              bounds. This was the old behavior, and continues to
              be the default.
* predicate - Condition all indexing / textureLoad / textureStore /
              atomic* operations on the bounds check. If any
              dependent value is out of bounds, then the operation
              is skipped.

This change also fixes multiple expression evaluation of the texture
builtin 'level' argument.

Change-Id: I2e300ddff2c8d3183a9701f06985ce1b262baf2c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/122343
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Ben Clayton <bclayton@chromium.org>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
2023-03-06 21:05:01 +00:00

5500 lines
128 KiB
C++

// 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/transform/robustness.h"
#include "src/tint/transform/test_helper.h"
namespace tint::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) {
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;
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
////////////////////////////////////////////////////////////////////////////////
TEST_P(RobustnessTest, TextureDimensions) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
fn dimensions() {
let l = textureDimensions(t);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureDimensions_Level) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
fn dimensions_signed(level : i32) {
let l = textureDimensions(t, level);
}
fn dimensions_unsigned(level : u32) {
let l = textureDimensions(t, level);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
dimensions_signed(i32(non_uniform.x));
dimensions_unsigned(u32(non_uniform.x));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_2d<f32>;
fn dimensions_signed(level : i32) {
let level_idx = min(u32(level), (textureNumLevels(t) - 1));
let l = textureDimensions(t, level_idx);
}
fn dimensions_unsigned(level : u32) {
let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureDimensions(t, level_idx_1);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
dimensions_signed(i32(non_uniform.x));
dimensions_unsigned(u32(non_uniform.x));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_2d<f32>;
fn dimensions_signed(level : i32) {
let level_idx = u32(level);
let num_levels = textureNumLevels(t);
var predicated_value : vec2<u32>;
if ((level_idx < num_levels)) {
predicated_value = textureDimensions(t, level_idx);
}
let l = predicated_value;
}
fn dimensions_unsigned(level : u32) {
let level_idx_1 = u32(level);
let num_levels_1 = textureNumLevels(t);
var predicated_value_1 : vec2<u32>;
if ((level_idx_1 < num_levels_1)) {
predicated_value_1 = textureDimensions(t, level_idx_1);
}
let l = predicated_value_1;
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
dimensions_signed(i32(non_uniform.x));
dimensions_unsigned(u32(non_uniform.x));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureGather) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn gather(coords : vec2f) {
let l = textureGather(0, t, s, coords);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureGather_Array) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d_array<f32>;
@group(0) @binding(1) var s : sampler;
fn gather_signed(coords : vec2f, array : i32) {
let l = textureGather(1, t, s, coords, array);
}
fn gather_unsigned(coords : vec2f, array : u32) {
let l = textureGather(1, t, s, coords, array);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
gather_signed(non_uniform.xy, i32(non_uniform.x));
gather_unsigned(non_uniform.xy, u32(non_uniform.x));
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureGatherCompare) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d;
@group(0) @binding(1) var s : sampler_comparison;
fn gather(coords : vec2f, depth_ref : f32) {
let l = textureGatherCompare(t, s, coords, depth_ref);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureGatherCompare_Array) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d_array;
@group(0) @binding(1) var s : sampler_comparison;
fn gather_signed(coords : vec2f, array : i32, depth_ref : f32) {
let l = textureGatherCompare(t, s, coords, array, depth_ref);
}
fn gather_unsigned(coords : vec2f, array : u32, depth_ref : f32) {
let l = textureGatherCompare(t, s, coords, array, depth_ref);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
gather_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.x);
gather_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.x);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureLoad_1D) {
auto* src = R"(
@group(0) @binding(0) var t : texture_1d<f32>;
fn load_signed(coords : i32, level : i32) {
let l = textureLoad(t, coords, level);
}
fn load_unsigned(coords : u32, level : u32) {
let l = textureLoad(t, coords, level);
}
fn load_mixed(coords : i32, level : u32) {
let l = textureLoad(t, coords, level);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(i32(non_uniform.x), i32(non_uniform.x));
load_unsigned(u32(non_uniform.x), u32(non_uniform.x));
load_mixed(i32(non_uniform.x), u32(non_uniform.x));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_1d<f32>;
fn load_signed(coords : i32, level : i32) {
let level_idx = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, clamp(coords, 0, i32((textureDimensions(t, level_idx) - 1))), level_idx);
}
fn load_unsigned(coords : u32, level : u32) {
let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - 1)), level_idx_1);
}
fn load_mixed(coords : i32, level : u32) {
let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, clamp(coords, 0, i32((textureDimensions(t, level_idx_2) - 1))), level_idx_2);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(i32(non_uniform.x), i32(non_uniform.x));
load_unsigned(u32(non_uniform.x), u32(non_uniform.x));
load_mixed(i32(non_uniform.x), u32(non_uniform.x));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_1d<f32>;
fn load_signed(coords : i32, level : i32) {
let level_idx = u32(level);
let num_levels = textureNumLevels(t);
let coords_1 = u32(coords);
var predicated_value : vec4<f32>;
if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) {
predicated_value = textureLoad(t, coords_1, level_idx);
}
let l = predicated_value;
}
fn load_unsigned(coords : u32, level : u32) {
let level_idx_1 = u32(level);
let num_levels_1 = textureNumLevels(t);
let coords_2 = u32(coords);
var predicated_value_1 : vec4<f32>;
if (((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1))))))) {
predicated_value_1 = textureLoad(t, coords_2, level_idx_1);
}
let l = predicated_value_1;
}
fn load_mixed(coords : i32, level : u32) {
let level_idx_2 = u32(level);
let num_levels_2 = textureNumLevels(t);
let coords_3 = u32(coords);
var predicated_value_2 : vec4<f32>;
if (((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1))))))) {
predicated_value_2 = textureLoad(t, coords_3, level_idx_2);
}
let l = predicated_value_2;
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(i32(non_uniform.x), i32(non_uniform.x));
load_unsigned(u32(non_uniform.x), u32(non_uniform.x));
load_mixed(i32(non_uniform.x), u32(non_uniform.x));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureLoad_2D) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
fn load_signed(coords : vec2i, level : i32) {
let l = textureLoad(t, coords, level);
}
fn load_unsigned(coords : vec2u, level : u32) {
let l = textureLoad(t, coords, level);
}
fn load_mixed(coords : vec2u, level : i32) {
let l = textureLoad(t, coords, level);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x));
load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_2d<f32>;
fn load_signed(coords : vec2i, level : i32) {
let level_idx = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), level_idx);
}
fn load_unsigned(coords : vec2u, level : u32) {
let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - vec2(1))), level_idx_1);
}
fn load_mixed(coords : vec2u, level : i32) {
let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_2) - vec2(1))), level_idx_2);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x));
load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_2d<f32>;
fn load_signed(coords : vec2i, level : i32) {
let level_idx = u32(level);
let num_levels = textureNumLevels(t);
let coords_1 = vec2<u32>(coords);
var predicated_value : vec4<f32>;
if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) {
predicated_value = textureLoad(t, coords_1, level_idx);
}
let l = predicated_value;
}
fn load_unsigned(coords : vec2u, level : u32) {
let level_idx_1 = u32(level);
let num_levels_1 = textureNumLevels(t);
let coords_2 = vec2<u32>(coords);
var predicated_value_1 : vec4<f32>;
if (((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1))))))) {
predicated_value_1 = textureLoad(t, coords_2, level_idx_1);
}
let l = predicated_value_1;
}
fn load_mixed(coords : vec2u, level : i32) {
let level_idx_2 = u32(level);
let num_levels_2 = textureNumLevels(t);
let coords_3 = vec2<u32>(coords);
var predicated_value_2 : vec4<f32>;
if (((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1))))))) {
predicated_value_2 = textureLoad(t, coords_3, level_idx_2);
}
let l = predicated_value_2;
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x));
load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureLoad_2DArray) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d_array<f32>;
fn load_signed(coords : vec2i, array : i32, level : i32) {
let l = textureLoad(t, coords, array, level);
}
fn load_unsigned(coords : vec2u, array : u32, level : u32) {
let l = textureLoad(t, coords, array, level);
}
fn load_mixed(coords : vec2u, array : i32, level : u32) {
let l = textureLoad(t, coords, array, level);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x));
load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_2d_array<f32>;
fn load_signed(coords : vec2i, array : i32, level : i32) {
let level_idx = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), clamp(array, 0, i32((textureNumLayers(t) - 1))), level_idx);
}
fn load_unsigned(coords : vec2u, array : u32, level : u32) {
let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - vec2(1))), min(array, (textureNumLayers(t) - 1)), level_idx_1);
}
fn load_mixed(coords : vec2u, array : i32, level : u32) {
let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_2) - vec2(1))), clamp(array, 0, i32((textureNumLayers(t) - 1))), level_idx_2);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x));
load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_2d_array<f32>;
fn load_signed(coords : vec2i, array : i32, level : i32) {
let level_idx = u32(level);
let num_levels = textureNumLevels(t);
let coords_1 = vec2<u32>(coords);
let array_idx = u32(array);
var predicated_value : vec4<f32>;
if ((((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1)))))) & (array_idx < textureNumLayers(t)))) {
predicated_value = textureLoad(t, coords_1, array_idx, level_idx);
}
let l = predicated_value;
}
fn load_unsigned(coords : vec2u, array : u32, level : u32) {
let level_idx_1 = u32(level);
let num_levels_1 = textureNumLevels(t);
let coords_2 = vec2<u32>(coords);
let array_idx_1 = u32(array);
var predicated_value_1 : vec4<f32>;
if ((((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1)))))) & (array_idx_1 < textureNumLayers(t)))) {
predicated_value_1 = textureLoad(t, coords_2, array_idx_1, level_idx_1);
}
let l = predicated_value_1;
}
fn load_mixed(coords : vec2u, array : i32, level : u32) {
let level_idx_2 = u32(level);
let num_levels_2 = textureNumLevels(t);
let coords_3 = vec2<u32>(coords);
let array_idx_2 = u32(array);
var predicated_value_2 : vec4<f32>;
if ((((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1)))))) & (array_idx_2 < textureNumLayers(t)))) {
predicated_value_2 = textureLoad(t, coords_3, array_idx_2, level_idx_2);
}
let l = predicated_value_2;
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x));
load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureLoad_3D) {
auto* src = R"(
@group(0) @binding(0) var t : texture_3d<f32>;
fn load_signed(coords : vec3i, level : i32) {
let l = textureLoad(t, coords, level);
}
fn load_unsigned(coords : vec3u, level : u32) {
let l = textureLoad(t, coords, level);
}
fn load_mixed(coords : vec3u, level : i32) {
let l = textureLoad(t, coords, level);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec3i(non_uniform.xyz), i32(non_uniform.x));
load_unsigned(vec3u(non_uniform.xyz), u32(non_uniform.x));
load_mixed(vec3u(non_uniform.xyz), i32(non_uniform.x));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_3d<f32>;
fn load_signed(coords : vec3i, level : i32) {
let level_idx = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, clamp(coords, vec3(0), vec3<i32>((textureDimensions(t, level_idx) - vec3(1)))), level_idx);
}
fn load_unsigned(coords : vec3u, level : u32) {
let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - vec3(1))), level_idx_1);
}
fn load_mixed(coords : vec3u, level : i32) {
let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_2) - vec3(1))), level_idx_2);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec3i(non_uniform.xyz), i32(non_uniform.x));
load_unsigned(vec3u(non_uniform.xyz), u32(non_uniform.x));
load_mixed(vec3u(non_uniform.xyz), i32(non_uniform.x));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_3d<f32>;
fn load_signed(coords : vec3i, level : i32) {
let level_idx = u32(level);
let num_levels = textureNumLevels(t);
let coords_1 = vec3<u32>(coords);
var predicated_value : vec4<f32>;
if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) {
predicated_value = textureLoad(t, coords_1, level_idx);
}
let l = predicated_value;
}
fn load_unsigned(coords : vec3u, level : u32) {
let level_idx_1 = u32(level);
let num_levels_1 = textureNumLevels(t);
let coords_2 = vec3<u32>(coords);
var predicated_value_1 : vec4<f32>;
if (((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1))))))) {
predicated_value_1 = textureLoad(t, coords_2, level_idx_1);
}
let l = predicated_value_1;
}
fn load_mixed(coords : vec3u, level : i32) {
let level_idx_2 = u32(level);
let num_levels_2 = textureNumLevels(t);
let coords_3 = vec3<u32>(coords);
var predicated_value_2 : vec4<f32>;
if (((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1))))))) {
predicated_value_2 = textureLoad(t, coords_3, level_idx_2);
}
let l = predicated_value_2;
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec3i(non_uniform.xyz), i32(non_uniform.x));
load_unsigned(vec3u(non_uniform.xyz), u32(non_uniform.x));
load_mixed(vec3u(non_uniform.xyz), i32(non_uniform.x));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureLoad_Multisampled2D) {
auto* src = R"(
@group(0) @binding(0) var t : texture_multisampled_2d<f32>;
fn load_signed(coords : vec2i, sample : i32) {
let l = textureLoad(t, coords, sample);
}
fn load_unsigned(coords : vec2u, sample : u32) {
let l = textureLoad(t, coords, sample);
}
fn load_mixed(coords : vec2i, sample : u32) {
let l = textureLoad(t, coords, sample);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x));
load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_multisampled_2d<f32>;
fn load_signed(coords : vec2i, sample : i32) {
let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t) - vec2(1)))), sample);
}
fn load_unsigned(coords : vec2u, sample : u32) {
let l = textureLoad(t, min(coords, (textureDimensions(t) - vec2(1))), sample);
}
fn load_mixed(coords : vec2i, sample : u32) {
let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t) - vec2(1)))), sample);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x));
load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_multisampled_2d<f32>;
fn load_signed(coords : vec2i, sample : i32) {
let coords_1 = vec2<u32>(coords);
var predicated_value : vec4<f32>;
if (all((coords_1 < textureDimensions(t)))) {
predicated_value = textureLoad(t, coords_1, sample);
}
let l = predicated_value;
}
fn load_unsigned(coords : vec2u, sample : u32) {
let coords_2 = vec2<u32>(coords);
var predicated_value_1 : vec4<f32>;
if (all((coords_2 < textureDimensions(t)))) {
predicated_value_1 = textureLoad(t, coords_2, sample);
}
let l = predicated_value_1;
}
fn load_mixed(coords : vec2i, sample : u32) {
let coords_3 = vec2<u32>(coords);
var predicated_value_2 : vec4<f32>;
if (all((coords_3 < textureDimensions(t)))) {
predicated_value_2 = textureLoad(t, coords_3, sample);
}
let l = predicated_value_2;
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x));
load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureLoad_Depth2D) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d;
fn load_signed(coords : vec2i, level : i32) {
let l = textureLoad(t, coords, level);
}
fn load_unsigned(coords : vec2u, level : u32) {
let l = textureLoad(t, coords, level);
}
fn load_mixed(coords : vec2i, level : u32) {
let l = textureLoad(t, coords, level);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x));
load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_depth_2d;
fn load_signed(coords : vec2i, level : i32) {
let level_idx = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), level_idx);
}
fn load_unsigned(coords : vec2u, level : u32) {
let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - vec2(1))), level_idx_1);
}
fn load_mixed(coords : vec2i, level : u32) {
let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx_2) - vec2(1)))), level_idx_2);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x));
load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_depth_2d;
fn load_signed(coords : vec2i, level : i32) {
let level_idx = u32(level);
let num_levels = textureNumLevels(t);
let coords_1 = vec2<u32>(coords);
var predicated_value : f32;
if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) {
predicated_value = textureLoad(t, coords_1, level_idx);
}
let l = predicated_value;
}
fn load_unsigned(coords : vec2u, level : u32) {
let level_idx_1 = u32(level);
let num_levels_1 = textureNumLevels(t);
let coords_2 = vec2<u32>(coords);
var predicated_value_1 : f32;
if (((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1))))))) {
predicated_value_1 = textureLoad(t, coords_2, level_idx_1);
}
let l = predicated_value_1;
}
fn load_mixed(coords : vec2i, level : u32) {
let level_idx_2 = u32(level);
let num_levels_2 = textureNumLevels(t);
let coords_3 = vec2<u32>(coords);
var predicated_value_2 : f32;
if (((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1))))))) {
predicated_value_2 = textureLoad(t, coords_3, level_idx_2);
}
let l = predicated_value_2;
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x));
load_mixed(vec2i(non_uniform.xy), u32(non_uniform.x));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureLoad_Depth2DArray) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d_array;
fn load_signed(coords : vec2i, array : i32, level : i32) {
let l = textureLoad(t, coords, array, level);
}
fn load_unsigned(coords : vec2u, array : u32, level : u32) {
let l = textureLoad(t, coords, array, level);
}
fn load_mixed(coords : vec2u, array : i32, level : u32) {
let l = textureLoad(t, coords, array, level);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x));
load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_depth_2d_array;
fn load_signed(coords : vec2i, array : i32, level : i32) {
let level_idx = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), clamp(array, 0, i32((textureNumLayers(t) - 1))), level_idx);
}
fn load_unsigned(coords : vec2u, array : u32, level : u32) {
let level_idx_1 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_1) - vec2(1))), min(array, (textureNumLayers(t) - 1)), level_idx_1);
}
fn load_mixed(coords : vec2u, array : i32, level : u32) {
let level_idx_2 = min(u32(level), (textureNumLevels(t) - 1));
let l = textureLoad(t, min(coords, (textureDimensions(t, level_idx_2) - vec2(1))), clamp(array, 0, i32((textureNumLayers(t) - 1))), level_idx_2);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x));
load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_depth_2d_array;
fn load_signed(coords : vec2i, array : i32, level : i32) {
let level_idx = u32(level);
let num_levels = textureNumLevels(t);
let coords_1 = vec2<u32>(coords);
let array_idx = u32(array);
var predicated_value : f32;
if ((((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1)))))) & (array_idx < textureNumLayers(t)))) {
predicated_value = textureLoad(t, coords_1, array_idx, level_idx);
}
let l = predicated_value;
}
fn load_unsigned(coords : vec2u, array : u32, level : u32) {
let level_idx_1 = u32(level);
let num_levels_1 = textureNumLevels(t);
let coords_2 = vec2<u32>(coords);
let array_idx_1 = u32(array);
var predicated_value_1 : f32;
if ((((level_idx_1 < num_levels_1) & all((coords_2 < textureDimensions(t, min(level_idx_1, (num_levels_1 - 1)))))) & (array_idx_1 < textureNumLayers(t)))) {
predicated_value_1 = textureLoad(t, coords_2, array_idx_1, level_idx_1);
}
let l = predicated_value_1;
}
fn load_mixed(coords : vec2u, array : i32, level : u32) {
let level_idx_2 = u32(level);
let num_levels_2 = textureNumLevels(t);
let coords_3 = vec2<u32>(coords);
let array_idx_2 = u32(array);
var predicated_value_2 : f32;
if ((((level_idx_2 < num_levels_2) & all((coords_3 < textureDimensions(t, min(level_idx_2, (num_levels_2 - 1)))))) & (array_idx_2 < textureNumLayers(t)))) {
predicated_value_2 = textureLoad(t, coords_3, array_idx_2, level_idx_2);
}
let l = predicated_value_2;
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy), i32(non_uniform.x), i32(non_uniform.x));
load_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), u32(non_uniform.x));
load_mixed(vec2u(non_uniform.xy), i32(non_uniform.x), u32(non_uniform.x));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureLoad_External) {
auto* src = R"(
@group(0) @binding(0) var t : texture_external;
fn load_signed(coords : vec2i) {
let l = textureLoad(t, coords);
}
fn load_unsigned(coords : vec2u) {
let l = textureLoad(t, coords);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy));
load_unsigned(vec2u(non_uniform.xy));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_external;
fn load_signed(coords : vec2i) {
let l = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t) - vec2(1)))));
}
fn load_unsigned(coords : vec2u) {
let l = textureLoad(t, min(coords, (textureDimensions(t) - vec2(1))));
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy));
load_unsigned(vec2u(non_uniform.xy));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_external;
fn load_signed(coords : vec2i) {
let coords_1 = vec2<u32>(coords);
var predicated_value : vec4<f32>;
if (all((coords_1 < textureDimensions(t)))) {
predicated_value = textureLoad(t, coords_1);
}
let l = predicated_value;
}
fn load_unsigned(coords : vec2u) {
let coords_2 = vec2<u32>(coords);
var predicated_value_1 : vec4<f32>;
if (all((coords_2 < textureDimensions(t)))) {
predicated_value_1 = textureLoad(t, coords_2);
}
let l = predicated_value_1;
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
load_signed(vec2i(non_uniform.xy));
load_unsigned(vec2u(non_uniform.xy));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureNumLayers) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d_array;
fn num_layers(coords : vec2f, depth_ref : f32) {
let l = textureNumLayers(t);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureNumLevels) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d;
fn num_levels(coords : vec2f, depth_ref : f32) {
let l = textureNumLevels(t);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureNumSamples) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_multisampled_2d;
fn num_levels(coords : vec2f, depth_ref : f32) {
let l = textureNumSamples(t);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSample) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn sample(coords : vec2f) {
let l = textureSample(t, s, coords);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSample_Offset) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn sample(coords : vec2f) {
const offset = vec2i(1);
let l = textureSample(t, s, coords, offset);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSample_ArrayIndex) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d_array<f32>;
@group(0) @binding(1) var s : sampler;
fn sample_signed(coords : vec2f, array : i32) {
let l = textureSample(t, s, coords, array);
}
fn sample_unsigned(coords : vec2f, array : u32) {
let l = textureSample(t, s, coords, array);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
sample_signed(non_uniform.xy, i32(non_uniform.x));
sample_unsigned(non_uniform.xy, u32(non_uniform.x));
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleBias) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn sample_bias(coords : vec2f, bias : f32) {
let l = textureSampleBias(t, s, coords, bias);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleBias_Offset) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn sample_bias(coords : vec2f, bias : f32) {
const offset = vec2i(1);
let l = textureSampleBias(t, s, coords, bias, offset);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleBias_ArrayIndex) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d_array<f32>;
@group(0) @binding(1) var s : sampler;
fn sample_bias_signed(coords : vec2f, array : i32, bias : f32) {
let l = textureSampleBias(t, s, coords, array, bias);
}
fn sample_bias_unsigned(coords : vec2f, array : u32, bias : f32) {
let l = textureSampleBias(t, s, coords, array, bias);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
sample_bias_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.x);
sample_bias_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.x);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleCompare) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d;
@group(0) @binding(1) var s : sampler_comparison;
fn sample_compare(coords : vec2f, depth_ref : f32) {
let l = textureSampleCompare(t, s, coords, depth_ref);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleCompare_Offset) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d;
@group(0) @binding(1) var s : sampler_comparison;
fn sample_compare(coords : vec2f, depth_ref : f32) {
const offset = vec2i(1);
let l = textureSampleCompare(t, s, coords, depth_ref, offset);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleCompare_ArrayIndex) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d_array;
@group(0) @binding(1) var s : sampler_comparison;
fn sample_compare_signed(coords : vec2f, array : i32, depth_ref : f32) {
let l = textureSampleCompare(t, s, coords, array, depth_ref);
}
fn sample_compare_unsigned(coords : vec2f, array : u32, depth_ref : f32) {
let l = textureSampleCompare(t, s, coords, array, depth_ref);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
sample_compare_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.x);
sample_compare_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.x);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleCompareLevel) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d;
@group(0) @binding(1) var s : sampler_comparison;
fn sample_compare_level(coords : vec2f, depth_ref : f32) {
let l = textureSampleCompareLevel(t, s, coords, depth_ref);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleCompareLevel_Offset) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d;
@group(0) @binding(1) var s : sampler_comparison;
fn sample_compare_level(coords : vec2f, depth_ref : f32) {
const offset = vec2i(1);
let l = textureSampleCompareLevel(t, s, coords, depth_ref, offset);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleCompareLevel_ArrayIndex) {
auto* src = R"(
@group(0) @binding(0) var t : texture_depth_2d_array;
@group(0) @binding(1) var s : sampler_comparison;
fn sample_compare_level_signed(coords : vec2f, array : i32, depth_ref : f32) {
let l = textureSampleCompareLevel(t, s, coords, array, depth_ref);
}
fn sample_compare_level_unsigned(coords : vec2f, array : u32, depth_ref : f32) {
let l = textureSampleCompareLevel(t, s, coords, array, depth_ref);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
sample_compare_level_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.x);
sample_compare_level_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.x);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleGrad) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn sample_compare_level(coords : vec2f, ddx : vec2f, ddy : vec2f) {
let l = textureSampleGrad(t, s, coords, ddx, ddy);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleGrad_Offset) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn sample_compare_level(coords : vec2f, ddx : vec2f, ddy : vec2f) {
const offset = vec2i(1);
let l = textureSampleGrad(t, s, coords, ddx, ddy, offset);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleGrad_ArrayIndex) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d_array<f32>;
@group(0) @binding(1) var s : sampler;
fn sample_grad_signed(coords : vec2f, array : i32, ddx : vec2f, ddy : vec2f) {
let l = textureSampleGrad(t, s, coords, array, ddx, ddy);
}
fn sample_grad_unsigned(coords : vec2f, array : u32, ddx : vec2f, ddy : vec2f) {
let l = textureSampleGrad(t, s, coords, array, ddx, ddy);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
sample_grad_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.xy, non_uniform.xy);
sample_grad_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.xy, non_uniform.xy);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleLevel) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn sample_compare_level(coords : vec2f, level : f32) {
let l = textureSampleLevel(t, s, coords, level);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleLevel_Offset) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;
fn sample_compare_level(coords : vec2f, level : f32) {
const offset = vec2i(1);
let l = textureSampleLevel(t, s, coords, level, offset);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleLevel_ArrayIndex) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d_array<f32>;
@group(0) @binding(1) var s : sampler;
fn sample_compare_level_signed(coords : vec2f, array : i32, level : f32) {
let l = textureSampleLevel(t, s, coords, array, level);
}
fn sample_compare_level_unsigned(coords : vec2f, array : u32, level : f32) {
let l = textureSampleLevel(t, s, coords, array, level);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
sample_compare_level_signed(non_uniform.xy, i32(non_uniform.x), non_uniform.x);
sample_compare_level_unsigned(non_uniform.xy, u32(non_uniform.x), non_uniform.x);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureSampleBaseClampToEdge) {
auto* src = R"(
@group(0) @binding(0) var t : texture_external;
@group(0) @binding(1) var s : sampler;
fn sample_base_clamp_to_edge(coords : vec2f) {
let l = textureSampleBaseClampToEdge(t, s, coords);
}
)";
auto* expect = src;
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureStore_1D) {
auto* src = R"(
@group(0) @binding(0) var t : texture_storage_1d<rgba8sint, write>;
fn store_signed(coords : i32, value : vec4i) {
textureStore(t, coords, value);
}
fn store_unsigned(coords : u32, value : vec4i) {
textureStore(t, coords, value);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(i32(non_uniform.x), vec4i(non_uniform));
store_unsigned(u32(non_uniform.x), vec4i(non_uniform));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_storage_1d<rgba8sint, write>;
fn store_signed(coords : i32, value : vec4i) {
textureStore(t, clamp(coords, 0, i32((textureDimensions(t) - 1))), value);
}
fn store_unsigned(coords : u32, value : vec4i) {
textureStore(t, min(coords, (textureDimensions(t) - 1)), value);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(i32(non_uniform.x), vec4i(non_uniform));
store_unsigned(u32(non_uniform.x), vec4i(non_uniform));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_storage_1d<rgba8sint, write>;
fn store_signed(coords : i32, value : vec4i) {
let coords_1 = u32(coords);
if (all((coords_1 < textureDimensions(t)))) {
textureStore(t, coords_1, value);
}
}
fn store_unsigned(coords : u32, value : vec4i) {
let coords_2 = u32(coords);
if (all((coords_2 < textureDimensions(t)))) {
textureStore(t, coords_2, value);
}
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(i32(non_uniform.x), vec4i(non_uniform));
store_unsigned(u32(non_uniform.x), vec4i(non_uniform));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureStore_2D) {
auto* src = R"(
@group(0) @binding(0) var t : texture_storage_2d<rgba8sint, write>;
fn store_signed(coords : vec2i, value : vec4i) {
textureStore(t, coords, value);
}
fn store_unsigned(coords : vec2u, value : vec4i) {
textureStore(t, coords, value);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(vec2i(non_uniform.xy), vec4i(non_uniform));
store_unsigned(vec2u(non_uniform.xy), vec4i(non_uniform));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_storage_2d<rgba8sint, write>;
fn store_signed(coords : vec2i, value : vec4i) {
textureStore(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t) - vec2(1)))), value);
}
fn store_unsigned(coords : vec2u, value : vec4i) {
textureStore(t, min(coords, (textureDimensions(t) - vec2(1))), value);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(vec2i(non_uniform.xy), vec4i(non_uniform));
store_unsigned(vec2u(non_uniform.xy), vec4i(non_uniform));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_storage_2d<rgba8sint, write>;
fn store_signed(coords : vec2i, value : vec4i) {
let coords_1 = vec2<u32>(coords);
if (all((coords_1 < textureDimensions(t)))) {
textureStore(t, coords_1, value);
}
}
fn store_unsigned(coords : vec2u, value : vec4i) {
let coords_2 = vec2<u32>(coords);
if (all((coords_2 < textureDimensions(t)))) {
textureStore(t, coords_2, value);
}
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(vec2i(non_uniform.xy), vec4i(non_uniform));
store_unsigned(vec2u(non_uniform.xy), vec4i(non_uniform));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureStore_2DArray) {
auto* src = R"(
@group(0) @binding(0) var t : texture_storage_2d_array<rgba8sint, write>;
fn store_signed(coords : vec2i, array : i32, value : vec4i) {
textureStore(t, coords, array, value);
}
fn store_unsigned(coords : vec2u, array : u32, value : vec4i) {
textureStore(t, coords, array, value);
}
fn store_mixed(coords : vec2i, array : u32, value : vec4i) {
textureStore(t, coords, array, value);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(vec2i(non_uniform.xy), i32(non_uniform.x), vec4i(non_uniform));
store_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), vec4i(non_uniform));
store_mixed(vec2i(non_uniform.xy), u32(non_uniform.x), vec4i(non_uniform));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_storage_2d_array<rgba8sint, write>;
fn store_signed(coords : vec2i, array : i32, value : vec4i) {
textureStore(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t) - vec2(1)))), clamp(array, 0, i32((textureNumLayers(t) - 1))), value);
}
fn store_unsigned(coords : vec2u, array : u32, value : vec4i) {
textureStore(t, min(coords, (textureDimensions(t) - vec2(1))), min(array, (textureNumLayers(t) - 1)), value);
}
fn store_mixed(coords : vec2i, array : u32, value : vec4i) {
textureStore(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t) - vec2(1)))), min(array, (textureNumLayers(t) - 1)), value);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(vec2i(non_uniform.xy), i32(non_uniform.x), vec4i(non_uniform));
store_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), vec4i(non_uniform));
store_mixed(vec2i(non_uniform.xy), u32(non_uniform.x), vec4i(non_uniform));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_storage_2d_array<rgba8sint, write>;
fn store_signed(coords : vec2i, array : i32, value : vec4i) {
let coords_1 = vec2<u32>(coords);
let array_idx = u32(array);
if ((all((coords_1 < textureDimensions(t))) & (array_idx < textureNumLayers(t)))) {
textureStore(t, coords_1, array_idx, value);
}
}
fn store_unsigned(coords : vec2u, array : u32, value : vec4i) {
let coords_2 = vec2<u32>(coords);
let array_idx_1 = u32(array);
if ((all((coords_2 < textureDimensions(t))) & (array_idx_1 < textureNumLayers(t)))) {
textureStore(t, coords_2, array_idx_1, value);
}
}
fn store_mixed(coords : vec2i, array : u32, value : vec4i) {
let coords_3 = vec2<u32>(coords);
let array_idx_2 = u32(array);
if ((all((coords_3 < textureDimensions(t))) & (array_idx_2 < textureNumLayers(t)))) {
textureStore(t, coords_3, array_idx_2, value);
}
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(vec2i(non_uniform.xy), i32(non_uniform.x), vec4i(non_uniform));
store_unsigned(vec2u(non_uniform.xy), u32(non_uniform.x), vec4i(non_uniform));
store_mixed(vec2i(non_uniform.xy), u32(non_uniform.x), vec4i(non_uniform));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureStore_3D) {
auto* src = R"(
@group(0) @binding(0) var t : texture_storage_3d<rgba8sint, write>;
fn store_signed(coords : vec3i, value : vec4i) {
textureStore(t, coords, value);
}
fn store_unsigned(coords : vec3u, value : vec4i) {
textureStore(t, coords, value);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(vec3i(non_uniform.xyz), vec4i(non_uniform));
store_unsigned(vec3u(non_uniform.xyz), vec4i(non_uniform));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_storage_3d<rgba8sint, write>;
fn store_signed(coords : vec3i, value : vec4i) {
textureStore(t, clamp(coords, vec3(0), vec3<i32>((textureDimensions(t) - vec3(1)))), value);
}
fn store_unsigned(coords : vec3u, value : vec4i) {
textureStore(t, min(coords, (textureDimensions(t) - vec3(1))), value);
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(vec3i(non_uniform.xyz), vec4i(non_uniform));
store_unsigned(vec3u(non_uniform.xyz), vec4i(non_uniform));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_storage_3d<rgba8sint, write>;
fn store_signed(coords : vec3i, value : vec4i) {
let coords_1 = vec3<u32>(coords);
if (all((coords_1 < textureDimensions(t)))) {
textureStore(t, coords_1, value);
}
}
fn store_unsigned(coords : vec3u, value : vec4i) {
let coords_2 = vec3<u32>(coords);
if (all((coords_2 < textureDimensions(t)))) {
textureStore(t, coords_2, value);
}
}
@fragment
fn main(@builtin(position) non_uniform : vec4f) {
store_signed(vec3i(non_uniform.xyz), vec4i(non_uniform));
store_unsigned(vec3u(non_uniform.xyz), vec4i(non_uniform));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
////////////////////////////////////////////////////////////////////////////////
// Other
////////////////////////////////////////////////////////////////////////////////
TEST_P(RobustnessTest, ShadowedVariable) {
auto* src = R"(
fn f() {
var a : array<f32, 3>;
var i : u32;
{
var a : array<f32, 5>;
var b : f32 = a[i];
}
var c : f32 = a[i];
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
fn f() {
var a : array<f32, 3>;
var i : u32;
{
var a : array<f32, 5>;
var b : f32 = a[min(i, 4u)];
}
var c : f32 = a[min(i, 2u)];
}
)",
/* predicate */ R"(
fn f() {
var a : array<f32, 3>;
var i : u32;
{
var a : array<f32, 5>;
let index = i;
let predicate = (u32(index) <= 4u);
var predicated_expr : f32;
if (predicate) {
predicated_expr = a[index];
}
var b : f32 = predicated_expr;
}
let index_1 = i;
let predicate_1 = (u32(index_1) <= 2u);
var predicated_expr_1 : f32;
if (predicate_1) {
predicated_expr_1 = a[index_1];
}
var c : f32 = predicated_expr_1;
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
// Check that existing use of min() and arrayLength() do not get renamed.
TEST_P(RobustnessTest, DontRenameSymbols) {
auto* src = R"(
struct S {
a : f32,
b : array<f32>,
}
@group(0) @binding(0) var<storage, read> s : S;
const c : u32 = 1u;
fn f() {
let b : f32 = s.b[c];
let x : i32 = min(1, 2);
let y : u32 = arrayLength(&(s.b));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
struct S {
a : f32,
b : array<f32>,
}
@group(0) @binding(0) var<storage, read> s : S;
const c : u32 = 1u;
fn f() {
let b : f32 = s.b[min(c, (arrayLength(&(s.b)) - 1u))];
let x : i32 = min(1, 2);
let y : u32 = arrayLength(&(s.b));
}
)",
/* predicate */ R"(
struct S {
a : f32,
b : array<f32>,
}
@group(0) @binding(0) var<storage, read> s : S;
const c : u32 = 1u;
fn f() {
let index = c;
let predicate = (u32(index) <= (arrayLength(&(s.b)) - 1u));
var predicated_expr : f32;
if (predicate) {
predicated_expr = s.b[index];
}
let b : f32 = predicated_expr;
let x : i32 = min(1, 2);
let y : u32 = arrayLength(&(s.b));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, WorkgroupOverrideCount) {
auto* src = R"(
override N = 123;
var<workgroup> w : array<f32, N>;
fn f() {
var b : f32 = w[1i];
}
)";
auto* expect =
Expect(GetParam(),
/* ignore */ src,
/* clamp */
R"(error: array size is an override-expression, when expected a constant-expression.
Was the SubstituteOverride transform run?)",
/* predicate */
R"(error: array size is an override-expression, when expected a constant-expression.
Was the SubstituteOverride transform run?)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
////////////////////////////////////////////////////////////////////////////////
// atomic predication
////////////////////////////////////////////////////////////////////////////////
TEST_P(RobustnessTest, AtomicLoad) {
auto* src = R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
let i = 0;
let r = atomicLoad(&(a[i]));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
let i = 0;
let r = atomicLoad(&(a[min(u32(i), 3u)]));
}
)",
/* predicate */ R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
let i = 0;
let index = i;
let predicate = (u32(index) <= 3u);
var predicated_value : i32;
if (predicate) {
predicated_value = atomicLoad(&(a[index]));
}
let r = predicated_value;
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, AtomicAnd) {
auto* src = R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
let i = 0;
atomicAnd(&(a[i]), 10);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
let i = 0;
atomicAnd(&(a[min(u32(i), 3u)]), 10);
}
)",
/* predicate */ R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
let i = 0;
let index = i;
let predicate = (u32(index) <= 3u);
if (predicate) {
atomicAnd(&(a[index]), 10);
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
////////////////////////////////////////////////////////////////////////////////
// workgroupUniformLoad
////////////////////////////////////////////////////////////////////////////////
TEST_P(RobustnessTest, WorkgroupUniformLoad) {
auto* src = R"(
var<workgroup> a : array<u32, 32>;
@compute @workgroup_size(1)
fn f() {
let i = 1;
let p = &(a[i]);
let v = workgroupUniformLoad(p);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
var<workgroup> a : array<u32, 32>;
@compute @workgroup_size(1)
fn f() {
let i = 1;
let p = &(a[min(u32(i), 31u)]);
let v = workgroupUniformLoad(p);
}
)",
/* predicate */ R"(
var<workgroup> a : array<u32, 32>;
@compute @workgroup_size(1)
fn f() {
let i = 1;
let index = i;
let predicate = (u32(index) <= 31u);
let p = &(a[index]);
var predicated_value : u32;
if (predicate) {
predicated_value = workgroupUniformLoad(p);
} else {
workgroupBarrier();
}
let v = predicated_value;
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
////////////////////////////////////////////////////////////////////////////////
// Usage in loops
////////////////////////////////////////////////////////////////////////////////
TEST_P(RobustnessTest, ArrayVal_ForLoopInit) {
auto* src = R"(
fn f() {
let a = array<i32, 3>();
var v = 1;
for(var i = a[v]; (i < 3); i++) {
var in_loop = 42;
}
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
fn f() {
let a = array<i32, 3>();
var v = 1;
for(var i = a[min(u32(v), 2u)]; (i < 3); i++) {
var in_loop = 42;
}
}
)",
/* predicate */ R"(
fn f() {
let a = array<i32, 3>();
var v = 1;
{
let index = v;
let predicate = (u32(index) <= 2u);
var predicated_expr : i32;
if (predicate) {
predicated_expr = a[index];
}
var i = predicated_expr;
loop {
if (!((i < 3))) {
break;
}
{
var in_loop = 42;
}
continuing {
i++;
}
}
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, ArrayVal_ForLoopCond) {
auto* src = R"(
fn f() {
let a = array<i32, 3>();
var v = 1;
for(var i = 0; (i < a[v]); i++) {
var in_loop = 42;
}
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
fn f() {
let a = array<i32, 3>();
var v = 1;
for(var i = 0; (i < a[min(u32(v), 2u)]); i++) {
var in_loop = 42;
}
}
)",
/* predicate */ R"(
fn f() {
let a = array<i32, 3>();
var v = 1;
{
var i = 0;
loop {
let index = v;
let predicate = (u32(index) <= 2u);
var predicated_expr : i32;
if (predicate) {
predicated_expr = a[index];
}
if (!((i < predicated_expr))) {
break;
}
{
var in_loop = 42;
}
continuing {
i++;
}
}
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, ArrayVal_ForLoopCont) {
auto* src = R"(
fn f() {
let a = array<i32, 3>();
for(var i = 0; (i < 5); i = a[i]) {
var in_loop = 42;
}
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
fn f() {
let a = array<i32, 3>();
for(var i = 0; (i < 5); i = a[min(u32(i), 2u)]) {
var in_loop = 42;
}
}
)",
/* predicate */ R"(
fn f() {
let a = array<i32, 3>();
{
var i = 0;
loop {
if (!((i < 5))) {
break;
}
{
var in_loop = 42;
}
continuing {
let index = i;
let predicate = (u32(index) <= 2u);
var predicated_expr : i32;
if (predicate) {
predicated_expr = a[index];
}
i = predicated_expr;
}
}
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureLoad_ForLoopInit) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<i32>;
fn f() {
var coords = vec2(1);
var level = 1;
for(var i = textureLoad(t, coords, level).x; (i < 3); i++) {
var in_loop = 42;
}
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_2d<i32>;
fn f() {
var coords = vec2(1);
var level = 1;
{
let level_idx = min(u32(level), (textureNumLevels(t) - 1));
var i = textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), level_idx).x;
loop {
if (!((i < 3))) {
break;
}
{
var in_loop = 42;
}
continuing {
i++;
}
}
}
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_2d<i32>;
fn f() {
var coords = vec2(1);
var level = 1;
{
let level_idx = u32(level);
let num_levels = textureNumLevels(t);
let coords_1 = vec2<u32>(coords);
var predicated_value : vec4<i32>;
if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) {
predicated_value = textureLoad(t, coords_1, level_idx);
}
var i = predicated_value.x;
loop {
if (!((i < 3))) {
break;
}
{
var in_loop = 42;
}
continuing {
i++;
}
}
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureLoad_ForLoopCond) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<i32>;
fn f() {
var coords = vec2(1);
var level = 1;
for(var i = 0; (i < textureLoad(t, coords, level).x); i++) {
var in_loop = 42;
}
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_2d<i32>;
fn f() {
var coords = vec2(1);
var level = 1;
{
var i = 0;
loop {
let level_idx = min(u32(level), (textureNumLevels(t) - 1));
if (!((i < textureLoad(t, clamp(coords, vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), level_idx).x))) {
break;
}
{
var in_loop = 42;
}
continuing {
i++;
}
}
}
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_2d<i32>;
fn f() {
var coords = vec2(1);
var level = 1;
{
var i = 0;
loop {
let level_idx = u32(level);
let num_levels = textureNumLevels(t);
let coords_1 = vec2<u32>(coords);
var predicated_value : vec4<i32>;
if (((level_idx < num_levels) & all((coords_1 < textureDimensions(t, min(level_idx, (num_levels - 1))))))) {
predicated_value = textureLoad(t, coords_1, level_idx);
}
if (!((i < predicated_value.x))) {
break;
}
{
var in_loop = 42;
}
continuing {
i++;
}
}
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureLoad_ForLoopCont) {
auto* src = R"(
@group(0) @binding(0) var t : texture_2d<i32>;
fn f() {
var level = 1;
for(var i = 0; (i < 5); i = textureLoad(t, vec2(i), i).x) {
var in_loop = 42;
}
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_2d<i32>;
fn f() {
var level = 1;
{
var i = 0;
loop {
if (!((i < 5))) {
break;
}
{
var in_loop = 42;
}
continuing {
let level_idx = min(u32(i), (textureNumLevels(t) - 1));
i = textureLoad(t, clamp(vec2(i), vec2(0), vec2<i32>((textureDimensions(t, level_idx) - vec2(1)))), level_idx).x;
}
}
}
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_2d<i32>;
fn f() {
var level = 1;
{
var i = 0;
loop {
if (!((i < 5))) {
break;
}
{
var in_loop = 42;
}
continuing {
let level_idx = u32(i);
let num_levels = textureNumLevels(t);
let coords = vec2<u32>(vec2(i));
var predicated_value : vec4<i32>;
if (((level_idx < num_levels) & all((coords < textureDimensions(t, min(level_idx, (num_levels - 1))))))) {
predicated_value = textureLoad(t, coords, level_idx);
}
i = predicated_value.x;
}
}
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureStore_ForLoopInit) {
auto* src = R"(
@group(0) @binding(0) var t : texture_storage_1d<rgba8sint, write>;
fn f() {
var coords = 1;
var value = vec4(1);
var i = 0;
for(textureStore(t, coords, value); (i < 3); i++) {
var in_loop = 42;
}
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_storage_1d<rgba8sint, write>;
fn f() {
var coords = 1;
var value = vec4(1);
var i = 0;
for(textureStore(t, clamp(coords, 0, i32((textureDimensions(t) - 1))), value); (i < 3); i++) {
var in_loop = 42;
}
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_storage_1d<rgba8sint, write>;
fn f() {
var coords = 1;
var value = vec4(1);
var i = 0;
{
let coords_1 = u32(coords);
if (all((coords_1 < textureDimensions(t)))) {
textureStore(t, coords_1, value);
}
loop {
if (!((i < 3))) {
break;
}
{
var in_loop = 42;
}
continuing {
i++;
}
}
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, TextureStore_ForLoopCont) {
auto* src = R"(
@group(0) @binding(0) var t : texture_storage_1d<rgba8sint, write>;
fn f() {
var level = 1;
var value = vec4(1);
for(var i = 0; (i < 3); textureStore(t, i, value)) {
var in_loop = 42;
}
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var t : texture_storage_1d<rgba8sint, write>;
fn f() {
var level = 1;
var value = vec4(1);
for(var i = 0; (i < 3); textureStore(t, clamp(i, 0, i32((textureDimensions(t) - 1))), value)) {
var in_loop = 42;
}
}
)",
/* predicate */ R"(
@group(0) @binding(0) var t : texture_storage_1d<rgba8sint, write>;
fn f() {
var level = 1;
var value = vec4(1);
{
var i = 0;
loop {
if (!((i < 3))) {
break;
}
{
var in_loop = 42;
}
continuing {
let coords = u32(i);
if (all((coords < textureDimensions(t)))) {
textureStore(t, coords, value);
}
}
}
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, AtomicXor_ForLoopInit) {
auto* src = R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
var i = 0;
for(atomicXor(&(a[i]), 4); (i < 3); i++) {
var in_loop = 42;
}
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
var i = 0;
for(atomicXor(&(a[min(u32(i), 3u)]), 4); (i < 3); i++) {
var in_loop = 42;
}
}
)",
/* predicate */ R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
var i = 0;
{
let index = i;
let predicate = (u32(index) <= 3u);
if (predicate) {
atomicXor(&(a[index]), 4);
}
loop {
if (!((i < 3))) {
break;
}
{
var in_loop = 42;
}
continuing {
i++;
}
}
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, AtomicXor_ForLoopCond) {
auto* src = R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
for(var i = 0; (i < atomicXor(&(a[i]), 4)); i++) {
var in_loop = 42;
}
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
for(var i = 0; (i < atomicXor(&(a[min(u32(i), 3u)]), 4)); i++) {
var in_loop = 42;
}
}
)",
/* predicate */ R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
{
var i = 0;
loop {
let index = i;
let predicate = (u32(index) <= 3u);
var predicated_value : i32;
if (predicate) {
predicated_value = atomicXor(&(a[index]), 4);
}
if (!((i < predicated_value))) {
break;
}
{
var in_loop = 42;
}
continuing {
i++;
}
}
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, AtomicXor_ForLoopCont) {
auto* src = R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
for(var i = 0; (i < 5); i = atomicXor(&(a[i]), 4)) {
var in_loop = 42;
}
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
for(var i = 0; (i < 5); i = atomicXor(&(a[min(u32(i), 3u)]), 4)) {
var in_loop = 42;
}
}
)",
/* predicate */ R"(
@group(0) @binding(0) var<storage, read_write> a : array<atomic<i32>, 4>;
fn f() {
{
var i = 0;
loop {
if (!((i < 5))) {
break;
}
{
var in_loop = 42;
}
continuing {
let index = i;
let predicate = (u32(index) <= 3u);
var predicated_value : i32;
if (predicate) {
predicated_value = atomicXor(&(a[index]), 4);
}
i = predicated_value;
}
}
}
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
////////////////////////////////////////////////////////////////////////////////
// User pointer parameters
////////////////////////////////////////////////////////////////////////////////
TEST_P(RobustnessTest, Read_PrivatePointerParameter_IndexWithConstant) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
var<private> a : array<i32, 4>;
fn x(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
return ((pre + *(p)) + post);
}
fn y(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
return x(pre, p, post);
}
fn z() {
y(1, &(a[1]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ src,
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
var<private> a : array<i32, 4>;
fn x(pre : i32, p : ptr<private, i32>, p_predicate : bool, post : i32) -> i32 {
var predicated_expr : i32;
if (p_predicate) {
predicated_expr = *(p);
}
return ((pre + predicated_expr) + post);
}
fn y(pre : i32, p : ptr<private, i32>, p_predicate_1 : bool, post : i32) -> i32 {
return x(pre, p, p_predicate_1, post);
}
fn z() {
y(1, &(a[1]), true, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Read_WorkgroupPointerParameter_IndexWithConstant) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
var<workgroup> a : array<i32, 4>;
fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 {
return ((pre + *(p)) + post);
}
fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 {
return x(pre, p, post);
}
fn z() {
y(1, &(a[1]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ src,
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
var<workgroup> a : array<i32, 4>;
fn x(pre : i32, p : ptr<workgroup, i32>, p_predicate : bool, post : i32) -> i32 {
var predicated_expr : i32;
if (p_predicate) {
predicated_expr = *(p);
}
return ((pre + predicated_expr) + post);
}
fn y(pre : i32, p : ptr<workgroup, i32>, p_predicate_1 : bool, post : i32) -> i32 {
return x(pre, p, p_predicate_1, post);
}
fn z() {
y(1, &(a[1]), true, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Read_UniformPointerParameter_IndexWithConstant) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<uniform> a : array<vec4i, 4>;
fn x(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i {
return ((pre + *(p)) + post);
}
fn y(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i {
return x(pre, p, post);
}
fn z() {
y(vec4(1), &(a[1]), vec4(2));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ src,
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<uniform> a : array<vec4i, 4>;
fn x(pre : vec4i, p : ptr<uniform, vec4i>, p_predicate : bool, post : vec4i) -> vec4i {
var predicated_expr : vec4<i32>;
if (p_predicate) {
predicated_expr = *(p);
}
return ((pre + predicated_expr) + post);
}
fn y(pre : vec4i, p : ptr<uniform, vec4i>, p_predicate_1 : bool, post : vec4i) -> vec4i {
return x(pre, p, p_predicate_1, post);
}
fn z() {
y(vec4(1), &(a[1]), true, vec4(2));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Read_StoragePointerParameter_IndexWithConstant) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<storage> a : array<vec4i, 4>;
fn x(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i {
return ((pre + *(p)) + post);
}
fn y(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i {
return x(pre, p, post);
}
fn z() {
y(vec4(1), &(a[1]), vec4(2));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ src,
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<storage> a : array<vec4i, 4>;
fn x(pre : vec4i, p : ptr<storage, vec4i>, p_predicate : bool, post : vec4i) -> vec4i {
var predicated_expr : vec4<i32>;
if (p_predicate) {
predicated_expr = *(p);
}
return ((pre + predicated_expr) + post);
}
fn y(pre : vec4i, p : ptr<storage, vec4i>, p_predicate_1 : bool, post : vec4i) -> vec4i {
return x(pre, p, p_predicate_1, post);
}
fn z() {
y(vec4(1), &(a[1]), true, vec4(2));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Read_FunctionPointerParameter_IndexWithConstant) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
fn x(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
return ((pre + *(p)) + post);
}
fn y(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
return x(pre, p, post);
}
fn z() {
var a : array<i32, 4>;
y(1, &(a[1]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ src,
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
fn x(pre : i32, p : ptr<function, i32>, p_predicate : bool, post : i32) -> i32 {
var predicated_expr : i32;
if (p_predicate) {
predicated_expr = *(p);
}
return ((pre + predicated_expr) + post);
}
fn y(pre : i32, p : ptr<function, i32>, p_predicate_1 : bool, post : i32) -> i32 {
return x(pre, p, p_predicate_1, post);
}
fn z() {
var a : array<i32, 4>;
y(1, &(a[1]), true, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Read_PrivatePointerParameter_IndexWithLet) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
var<private> a : array<i32, 4>;
fn x(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
return ((pre + *(p)) + post);
}
fn y(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
return x(pre, p, post);
}
fn z() {
let i = 0;
y(1, &(a[i]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
enable chromium_experimental_full_ptr_parameters;
var<private> a : array<i32, 4>;
fn x(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
return ((pre + *(p)) + post);
}
fn y(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
return x(pre, p, post);
}
fn z() {
let i = 0;
y(1, &(a[min(u32(i), 3u)]), 2);
}
)",
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
var<private> a : array<i32, 4>;
fn x(pre : i32, p : ptr<private, i32>, p_predicate : bool, post : i32) -> i32 {
var predicated_expr : i32;
if (p_predicate) {
predicated_expr = *(p);
}
return ((pre + predicated_expr) + post);
}
fn y(pre : i32, p : ptr<private, i32>, p_predicate_1 : bool, post : i32) -> i32 {
return x(pre, p, p_predicate_1, post);
}
fn z() {
let i = 0;
let index = i;
let predicate = (u32(index) <= 3u);
y(1, &(a[index]), predicate, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Read_WorkgroupPointerParameter_IndexWithLet) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
var<workgroup> a : array<i32, 4>;
fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 {
return ((pre + *(p)) + post);
}
fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 {
return x(pre, p, post);
}
fn z() {
let i = 0;
y(1, &(a[i]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
enable chromium_experimental_full_ptr_parameters;
var<workgroup> a : array<i32, 4>;
fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 {
return ((pre + *(p)) + post);
}
fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 {
return x(pre, p, post);
}
fn z() {
let i = 0;
y(1, &(a[min(u32(i), 3u)]), 2);
}
)",
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
var<workgroup> a : array<i32, 4>;
fn x(pre : i32, p : ptr<workgroup, i32>, p_predicate : bool, post : i32) -> i32 {
var predicated_expr : i32;
if (p_predicate) {
predicated_expr = *(p);
}
return ((pre + predicated_expr) + post);
}
fn y(pre : i32, p : ptr<workgroup, i32>, p_predicate_1 : bool, post : i32) -> i32 {
return x(pre, p, p_predicate_1, post);
}
fn z() {
let i = 0;
let index = i;
let predicate = (u32(index) <= 3u);
y(1, &(a[index]), predicate, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Read_UniformPointerParameter_IndexWithLet) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<uniform> a : array<vec4i, 4>;
fn x(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i {
return ((pre + *(p)) + post);
}
fn y(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i {
return x(pre, p, post);
}
fn z() {
let i = 0;
y(vec4(1), &(a[i]), vec4(2));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<uniform> a : array<vec4i, 4>;
fn x(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i {
return ((pre + *(p)) + post);
}
fn y(pre : vec4i, p : ptr<uniform, vec4i>, post : vec4i) -> vec4i {
return x(pre, p, post);
}
fn z() {
let i = 0;
y(vec4(1), &(a[min(u32(i), 3u)]), vec4(2));
}
)",
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<uniform> a : array<vec4i, 4>;
fn x(pre : vec4i, p : ptr<uniform, vec4i>, p_predicate : bool, post : vec4i) -> vec4i {
var predicated_expr : vec4<i32>;
if (p_predicate) {
predicated_expr = *(p);
}
return ((pre + predicated_expr) + post);
}
fn y(pre : vec4i, p : ptr<uniform, vec4i>, p_predicate_1 : bool, post : vec4i) -> vec4i {
return x(pre, p, p_predicate_1, post);
}
fn z() {
let i = 0;
let index = i;
let predicate = (u32(index) <= 3u);
y(vec4(1), &(a[index]), predicate, vec4(2));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Read_StoragePointerParameter_IndexWithLet) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<storage> a : array<vec4i, 4>;
fn x(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i {
return ((pre + *(p)) + post);
}
fn y(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i {
return x(pre, p, post);
}
fn z() {
let i = 0;
y(vec4(1), &(a[i]), vec4(2));
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<storage> a : array<vec4i, 4>;
fn x(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i {
return ((pre + *(p)) + post);
}
fn y(pre : vec4i, p : ptr<storage, vec4i>, post : vec4i) -> vec4i {
return x(pre, p, post);
}
fn z() {
let i = 0;
y(vec4(1), &(a[min(u32(i), 3u)]), vec4(2));
}
)",
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<storage> a : array<vec4i, 4>;
fn x(pre : vec4i, p : ptr<storage, vec4i>, p_predicate : bool, post : vec4i) -> vec4i {
var predicated_expr : vec4<i32>;
if (p_predicate) {
predicated_expr = *(p);
}
return ((pre + predicated_expr) + post);
}
fn y(pre : vec4i, p : ptr<storage, vec4i>, p_predicate_1 : bool, post : vec4i) -> vec4i {
return x(pre, p, p_predicate_1, post);
}
fn z() {
let i = 0;
let index = i;
let predicate = (u32(index) <= 3u);
y(vec4(1), &(a[index]), predicate, vec4(2));
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Read_FunctionPointerParameter_IndexWithLet) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
fn x(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
return ((pre + *(p)) + post);
}
fn y(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
return x(pre, p, post);
}
fn z() {
var a : array<i32, 4>;
let i = 0;
y(1, &(a[i]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
enable chromium_experimental_full_ptr_parameters;
fn x(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
return ((pre + *(p)) + post);
}
fn y(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
return x(pre, p, post);
}
fn z() {
var a : array<i32, 4>;
let i = 0;
y(1, &(a[min(u32(i), 3u)]), 2);
}
)",
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
fn x(pre : i32, p : ptr<function, i32>, p_predicate : bool, post : i32) -> i32 {
var predicated_expr : i32;
if (p_predicate) {
predicated_expr = *(p);
}
return ((pre + predicated_expr) + post);
}
fn y(pre : i32, p : ptr<function, i32>, p_predicate_1 : bool, post : i32) -> i32 {
return x(pre, p, p_predicate_1, post);
}
fn z() {
var a : array<i32, 4>;
let i = 0;
let index = i;
let predicate = (u32(index) <= 3u);
y(1, &(a[index]), predicate, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Write_PrivatePointerParameter_IndexWithConstant) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
var<private> a : array<i32, 4>;
fn x(pre : i32, p : ptr<private, i32>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<private, i32>, post : i32) {
x(pre, p, post);
}
fn z() {
y(1, &(a[1]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ src,
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
var<private> a : array<i32, 4>;
fn x(pre : i32, p : ptr<private, i32>, p_predicate : bool, post : i32) {
if (p_predicate) {
*(p) = (pre + post);
}
}
fn y(pre : i32, p : ptr<private, i32>, p_predicate_1 : bool, post : i32) {
x(pre, p, p_predicate_1, post);
}
fn z() {
y(1, &(a[1]), true, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Write_WorkgroupPointerParameter_IndexWithConstant) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
var<workgroup> a : array<i32, 4>;
fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) {
x(pre, p, post);
}
fn z() {
y(1, &(a[1]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ src,
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
var<workgroup> a : array<i32, 4>;
fn x(pre : i32, p : ptr<workgroup, i32>, p_predicate : bool, post : i32) {
if (p_predicate) {
*(p) = (pre + post);
}
}
fn y(pre : i32, p : ptr<workgroup, i32>, p_predicate_1 : bool, post : i32) {
x(pre, p, p_predicate_1, post);
}
fn z() {
y(1, &(a[1]), true, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Write_StoragePointerParameter_IndexWithConstant) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<storage, read_write> a : array<i32, 4>;
fn x(pre : i32, p : ptr<storage, i32, read_write>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<storage, i32, read_write>, post : i32) {
x(pre, p, post);
}
fn z() {
y(1, &(a[1]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ src,
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<storage, read_write> a : array<i32, 4>;
fn x(pre : i32, p : ptr<storage, i32, read_write>, p_predicate : bool, post : i32) {
if (p_predicate) {
*(p) = (pre + post);
}
}
fn y(pre : i32, p : ptr<storage, i32, read_write>, p_predicate_1 : bool, post : i32) {
x(pre, p, p_predicate_1, post);
}
fn z() {
y(1, &(a[1]), true, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Write_FunctionPointerParameter_IndexWithConstant) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
fn x(pre : i32, p : ptr<function, i32>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<function, i32>, post : i32) {
x(pre, p, post);
}
fn z() {
var a : array<i32, 4>;
y(1, &(a[1]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ src,
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
fn x(pre : i32, p : ptr<function, i32>, p_predicate : bool, post : i32) {
if (p_predicate) {
*(p) = (pre + post);
}
}
fn y(pre : i32, p : ptr<function, i32>, p_predicate_1 : bool, post : i32) {
x(pre, p, p_predicate_1, post);
}
fn z() {
var a : array<i32, 4>;
y(1, &(a[1]), true, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Write_PrivatePointerParameter_IndexWithLet) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
var<private> a : array<i32, 4>;
fn x(pre : i32, p : ptr<private, i32>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<private, i32>, post : i32) {
x(pre, p, post);
}
fn z() {
let i = 0;
y(1, &(a[i]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
enable chromium_experimental_full_ptr_parameters;
var<private> a : array<i32, 4>;
fn x(pre : i32, p : ptr<private, i32>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<private, i32>, post : i32) {
x(pre, p, post);
}
fn z() {
let i = 0;
y(1, &(a[min(u32(i), 3u)]), 2);
}
)",
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
var<private> a : array<i32, 4>;
fn x(pre : i32, p : ptr<private, i32>, p_predicate : bool, post : i32) {
if (p_predicate) {
*(p) = (pre + post);
}
}
fn y(pre : i32, p : ptr<private, i32>, p_predicate_1 : bool, post : i32) {
x(pre, p, p_predicate_1, post);
}
fn z() {
let i = 0;
let index = i;
let predicate = (u32(index) <= 3u);
y(1, &(a[index]), predicate, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Write_WorkgroupPointerParameter_IndexWithLet) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
var<workgroup> a : array<i32, 4>;
fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) {
x(pre, p, post);
}
fn z() {
let i = 0;
y(1, &(a[i]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
enable chromium_experimental_full_ptr_parameters;
var<workgroup> a : array<i32, 4>;
fn x(pre : i32, p : ptr<workgroup, i32>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<workgroup, i32>, post : i32) {
x(pre, p, post);
}
fn z() {
let i = 0;
y(1, &(a[min(u32(i), 3u)]), 2);
}
)",
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
var<workgroup> a : array<i32, 4>;
fn x(pre : i32, p : ptr<workgroup, i32>, p_predicate : bool, post : i32) {
if (p_predicate) {
*(p) = (pre + post);
}
}
fn y(pre : i32, p : ptr<workgroup, i32>, p_predicate_1 : bool, post : i32) {
x(pre, p, p_predicate_1, post);
}
fn z() {
let i = 0;
let index = i;
let predicate = (u32(index) <= 3u);
y(1, &(a[index]), predicate, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Write_StoragePointerParameter_IndexWithLet) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<storage, read_write> a : array<i32, 4>;
fn x(pre : i32, p : ptr<storage, i32, read_write>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<storage, i32, read_write>, post : i32) {
x(pre, p, post);
}
fn z() {
let i = 0;
y(1, &(a[i]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<storage, read_write> a : array<i32, 4>;
fn x(pre : i32, p : ptr<storage, i32, read_write>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<storage, i32, read_write>, post : i32) {
x(pre, p, post);
}
fn z() {
let i = 0;
y(1, &(a[min(u32(i), 3u)]), 2);
}
)",
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
@group(0) @binding(0) var<storage, read_write> a : array<i32, 4>;
fn x(pre : i32, p : ptr<storage, i32, read_write>, p_predicate : bool, post : i32) {
if (p_predicate) {
*(p) = (pre + post);
}
}
fn y(pre : i32, p : ptr<storage, i32, read_write>, p_predicate_1 : bool, post : i32) {
x(pre, p, p_predicate_1, post);
}
fn z() {
let i = 0;
let index = i;
let predicate = (u32(index) <= 3u);
y(1, &(a[index]), predicate, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
TEST_P(RobustnessTest, Write_FunctionPointerParameter_IndexWithLet) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
fn x(pre : i32, p : ptr<function, i32>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<function, i32>, post : i32) {
x(pre, p, post);
}
fn z() {
var a : array<i32, 4>;
let i = 0;
y(1, &(a[i]), 2);
}
)";
auto* expect = Expect(GetParam(),
/* ignore */ src,
/* clamp */ R"(
enable chromium_experimental_full_ptr_parameters;
fn x(pre : i32, p : ptr<function, i32>, post : i32) {
*(p) = (pre + post);
}
fn y(pre : i32, p : ptr<function, i32>, post : i32) {
x(pre, p, post);
}
fn z() {
var a : array<i32, 4>;
let i = 0;
y(1, &(a[min(u32(i), 3u)]), 2);
}
)",
/* predicate */ R"(
enable chromium_experimental_full_ptr_parameters;
fn x(pre : i32, p : ptr<function, i32>, p_predicate : bool, post : i32) {
if (p_predicate) {
*(p) = (pre + post);
}
}
fn y(pre : i32, p : ptr<function, i32>, p_predicate_1 : bool, post : i32) {
x(pre, p, p_predicate_1, post);
}
fn z() {
var a : array<i32, 4>;
let i = 0;
let index = i;
let predicate = (u32(index) <= 3u);
y(1, &(a[index]), predicate, 2);
}
)");
auto got = Run<Robustness>(src, Config(GetParam()));
EXPECT_EQ(expect, str(got));
}
INSTANTIATE_TEST_SUITE_P(,
RobustnessTest,
testing::Values(Robustness::Action::kIgnore,
Robustness::Action::kClamp,
Robustness::Action::kPredicate));
} // namespace
} // namespace tint::transform