tint: Error if statically indexing out of bounds.
Fixed: tint:1665
Change-Id: Icd5f24f3b4d6ebbdc18b536dc426da92558a3a4b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/101183
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/docs/tint/origin-trial-changes.md b/docs/tint/origin-trial-changes.md
index 93c53e5..6c9e632 100644
--- a/docs/tint/origin-trial-changes.md
+++ b/docs/tint/origin-trial-changes.md
@@ -7,6 +7,10 @@
* `array()` constructor can now infer type and count. [tint:1628](crbug.com/tint/1628)
* `static_assert` statement has been added. [tint:1625](crbug.com/tint/1625)
+### Breaking changes
+
+* Indexing an array, vector or matrix with a compile-time expression that's out-of-bounds is now an error [tint:1665](crbug.com/tint/1665)
+
### Deprecated Features
* The list of reserved words has been sync'd to the WGSL specification. [tint:1463](crbug.com/tint/1463)
diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc
index a0974e4..8e46f9a 100644
--- a/src/tint/resolver/const_eval.cc
+++ b/src/tint/resolver/const_eval.cc
@@ -899,27 +899,28 @@
ConstEval::ConstantResult ConstEval::Index(const sem::Expression* obj_expr,
const sem::Expression* idx_expr) {
- auto obj_val = obj_expr->ConstantValue();
- if (!obj_val) {
- return nullptr;
- }
-
auto idx_val = idx_expr->ConstantValue();
if (!idx_val) {
return nullptr;
}
uint32_t el_count = 0;
- sem::Type::ElementOf(obj_val->Type(), &el_count);
+ sem::Type::ElementOf(obj_expr->Type()->UnwrapRef(), &el_count);
AInt idx = idx_val->As<AInt>();
- if (idx < 0 || idx >= el_count) {
- auto clamped = std::min<AInt::type>(std::max<AInt::type>(idx, 0), el_count - 1);
- AddWarning("index " + std::to_string(idx) + " out of bounds [0.." +
- std::to_string(el_count - 1) + "]. Clamping index to " +
- std::to_string(clamped),
- idx_expr->Declaration()->source);
- idx = clamped;
+ if (idx < 0 || (el_count > 0 && idx >= el_count)) {
+ std::string range;
+ if (el_count > 0) {
+ range = " [0.." + std::to_string(el_count - 1) + "]";
+ }
+ AddError("index " + std::to_string(idx) + " out of bounds" + range,
+ idx_expr->Declaration()->source);
+ return utils::Failure;
+ }
+
+ auto obj_val = obj_expr->ConstantValue();
+ if (!obj_val) {
+ return nullptr;
}
return obj_val->Index(static_cast<size_t>(idx));
diff --git a/src/tint/resolver/const_eval_test.cc b/src/tint/resolver/const_eval_test.cc
index 1d5b7d25..f06fa32 100644
--- a/src/tint/resolver/const_eval_test.cc
+++ b/src/tint/resolver/const_eval_test.cc
@@ -2498,34 +2498,16 @@
auto* expr = IndexAccessor(vec3<i32>(1_i, 2_i, 3_i), Expr(Source{{12, 34}}, 3_i));
WrapInFunction(expr);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), "12:34 warning: index 3 out of bounds [0..2]. Clamping index to 2");
-
- auto* sem = Sem().Get(expr);
- ASSERT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::I32>());
- EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue()->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->AllZero());
- EXPECT_EQ(sem->ConstantValue()->As<i32>(), 3_i);
+ EXPECT_FALSE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 error: index 3 out of bounds [0..2]");
}
TEST_F(ResolverConstEvalTest, Vec3_Index_OOB_Low) {
auto* expr = IndexAccessor(vec3<i32>(1_i, 2_i, 3_i), Expr(Source{{12, 34}}, -3_i));
WrapInFunction(expr);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), "12:34 warning: index -3 out of bounds [0..2]. Clamping index to 0");
-
- auto* sem = Sem().Get(expr);
- ASSERT_NE(sem, nullptr);
- ASSERT_TRUE(sem->Type()->Is<sem::I32>());
- EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue()->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->AllZero());
- EXPECT_EQ(sem->ConstantValue()->As<i32>(), 1_i);
+ EXPECT_FALSE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 error: index -3 out of bounds [0..2]");
}
TEST_F(ResolverConstEvalTest, Vec3_Swizzle_Scalar) {
@@ -2616,25 +2598,8 @@
Expr(Source{{12, 34}}, 3_i));
WrapInFunction(expr);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), "12:34 warning: index 3 out of bounds [0..2]. Clamping index to 2");
-
- auto* sem = Sem().Get(expr);
- ASSERT_NE(sem, nullptr);
- auto* vec = sem->Type()->As<sem::Vector>();
- ASSERT_NE(vec, nullptr);
- EXPECT_EQ(vec->Width(), 2u);
- EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
-
- EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
- EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 5._a);
-
- EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
- EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 6._a);
+ EXPECT_FALSE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 error: index 3 out of bounds [0..2]");
}
TEST_F(ResolverConstEvalTest, Mat3x2_Index_OOB_Low) {
@@ -2643,25 +2608,8 @@
Expr(Source{{12, 34}}, -3_i));
WrapInFunction(expr);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), "12:34 warning: index -3 out of bounds [0..2]. Clamping index to 0");
-
- auto* sem = Sem().Get(expr);
- ASSERT_NE(sem, nullptr);
- auto* vec = sem->Type()->As<sem::Vector>();
- ASSERT_NE(vec, nullptr);
- EXPECT_EQ(vec->Width(), 2u);
- EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
-
- EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
- EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 1._a);
-
- EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
- EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 2._a);
+ EXPECT_FALSE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 error: index -3 out of bounds [0..2]");
}
TEST_F(ResolverConstEvalTest, Array_vec3_f32_Index) {
@@ -2702,31 +2650,8 @@
Expr(Source{{12, 34}}, 2_i));
WrapInFunction(expr);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), "12:34 warning: index 2 out of bounds [0..1]. Clamping index to 1");
-
- auto* sem = Sem().Get(expr);
- ASSERT_NE(sem, nullptr);
- auto* vec = sem->Type()->As<sem::Vector>();
- ASSERT_NE(vec, nullptr);
- EXPECT_TRUE(vec->type()->Is<sem::F32>());
- EXPECT_EQ(vec->Width(), 3u);
- EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
-
- EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
- EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 4_f);
-
- EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
- EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 5_f);
-
- EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
- EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 6_f);
+ EXPECT_FALSE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 error: index 2 out of bounds [0..1]");
}
TEST_F(ResolverConstEvalTest, Array_vec3_f32_Index_OOB_Low) {
@@ -2735,34 +2660,18 @@
Expr(Source{{12, 34}}, -2_i));
WrapInFunction(expr);
- EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), "12:34 warning: index -2 out of bounds [0..1]. Clamping index to 0");
+ EXPECT_FALSE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 error: index -2 out of bounds [0..1]");
+}
- auto* sem = Sem().Get(expr);
- ASSERT_NE(sem, nullptr);
- auto* vec = sem->Type()->As<sem::Vector>();
- ASSERT_NE(vec, nullptr);
- EXPECT_TRUE(vec->type()->Is<sem::F32>());
- EXPECT_EQ(vec->Width(), 3u);
- EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
- EXPECT_FALSE(sem->ConstantValue()->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->AllZero());
+TEST_F(ResolverConstEvalTest, RuntimeArray_vec3_f32_Index_OOB_Low) {
+ auto* sb = GlobalVar("sb", ty.array(ty.vec3<f32>()), Group(0_a), Binding(0_a),
+ ast::StorageClass::kStorage);
+ auto* expr = IndexAccessor(sb, Expr(Source{{12, 34}}, -2_i));
+ WrapInFunction(expr);
- EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
- EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 1_f);
-
- EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
- EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 2_f);
-
- EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
- EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
- EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
- EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 3_f);
+ EXPECT_FALSE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 error: index -2 out of bounds");
}
TEST_F(ResolverConstEvalTest, ChainedIndex) {
@@ -2861,105 +2770,6 @@
}
}
-TEST_F(ResolverConstEvalTest, ChainedIndex_OOB) {
- auto* arr_expr = Construct(ty.array(ty.mat2x3<f32>(), 2_u), // array<mat2x3<f32>, 2u>
- mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), //
- vec3<f32>(4_f, 5_f, 6_f)), //
- mat2x3<f32>(vec3<f32>(7_f, 8_f, 9_f), //
- vec3<f32>(10_f, 11_f, 12_f)));
-
- auto* mat_expr = IndexAccessor(arr_expr, Expr(Source{{1, 2}}, -3_i)); // arr[3]
- auto* vec_expr = IndexAccessor(mat_expr, Expr(Source{{3, 4}}, -2_i)); // arr[3][-2]
- auto* f32_expr = IndexAccessor(vec_expr, Expr(Source{{5, 6}}, 4_i)); // arr[3][-2][4]
- WrapInFunction(f32_expr);
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), R"(1:2 warning: index -3 out of bounds [0..1]. Clamping index to 0
-3:4 warning: index -2 out of bounds [0..1]. Clamping index to 0
-5:6 warning: index 4 out of bounds [0..2]. Clamping index to 2)");
-
- {
- auto* mat = Sem().Get(mat_expr);
- EXPECT_NE(mat, nullptr);
- auto* ty = mat->Type()->As<sem::Matrix>();
- ASSERT_NE(mat->Type(), nullptr);
- EXPECT_TRUE(ty->ColumnType()->Is<sem::Vector>());
- EXPECT_EQ(ty->columns(), 2u);
- EXPECT_EQ(ty->rows(), 3u);
- EXPECT_EQ(mat->ConstantValue()->Type(), mat->Type());
- EXPECT_FALSE(mat->ConstantValue()->AllEqual());
- EXPECT_FALSE(mat->ConstantValue()->AnyZero());
- EXPECT_FALSE(mat->ConstantValue()->AllZero());
-
- EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(0)->AllEqual());
- EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(0)->AnyZero());
- EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(0)->AllZero());
- EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(0)->As<f32>(), 1_f);
-
- EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(1)->AllEqual());
- EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(1)->AnyZero());
- EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(1)->AllZero());
- EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(1)->As<f32>(), 2_f);
-
- EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(2)->AllEqual());
- EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(2)->AnyZero());
- EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(2)->AllZero());
- EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(2)->As<f32>(), 3_f);
-
- EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(0)->AllEqual());
- EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(0)->AnyZero());
- EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(0)->AllZero());
- EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(0)->As<f32>(), 4_f);
-
- EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(1)->AllEqual());
- EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(1)->AnyZero());
- EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(1)->AllZero());
- EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(1)->As<f32>(), 5_f);
-
- EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(2)->AllEqual());
- EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(2)->AnyZero());
- EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(2)->AllZero());
- EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(2)->As<f32>(), 6_f);
- }
- {
- auto* vec = Sem().Get(vec_expr);
- EXPECT_NE(vec, nullptr);
- auto* ty = vec->Type()->As<sem::Vector>();
- ASSERT_NE(vec->Type(), nullptr);
- EXPECT_TRUE(ty->type()->Is<sem::F32>());
- EXPECT_EQ(ty->Width(), 3u);
- EXPECT_EQ(vec->ConstantValue()->Type(), vec->Type());
- EXPECT_FALSE(vec->ConstantValue()->AllEqual());
- EXPECT_FALSE(vec->ConstantValue()->AnyZero());
- EXPECT_FALSE(vec->ConstantValue()->AllZero());
-
- EXPECT_TRUE(vec->ConstantValue()->Index(0)->AllEqual());
- EXPECT_FALSE(vec->ConstantValue()->Index(0)->AnyZero());
- EXPECT_FALSE(vec->ConstantValue()->Index(0)->AllZero());
- EXPECT_EQ(vec->ConstantValue()->Index(0)->As<f32>(), 1_f);
-
- EXPECT_TRUE(vec->ConstantValue()->Index(1)->AllEqual());
- EXPECT_FALSE(vec->ConstantValue()->Index(1)->AnyZero());
- EXPECT_FALSE(vec->ConstantValue()->Index(1)->AllZero());
- EXPECT_EQ(vec->ConstantValue()->Index(1)->As<f32>(), 2_f);
-
- EXPECT_TRUE(vec->ConstantValue()->Index(2)->AllEqual());
- EXPECT_FALSE(vec->ConstantValue()->Index(2)->AnyZero());
- EXPECT_FALSE(vec->ConstantValue()->Index(2)->AllZero());
- EXPECT_EQ(vec->ConstantValue()->Index(2)->As<f32>(), 3_f);
- }
- {
- auto* f = Sem().Get(f32_expr);
- EXPECT_NE(f, nullptr);
- EXPECT_TRUE(f->Type()->Is<sem::F32>());
- EXPECT_EQ(f->ConstantValue()->Type(), f->Type());
- EXPECT_TRUE(f->ConstantValue()->AllEqual());
- EXPECT_FALSE(f->ConstantValue()->AnyZero());
- EXPECT_FALSE(f->ConstantValue()->AllZero());
- EXPECT_EQ(f->ConstantValue()->As<f32>(), 3_f);
- }
-}
-
////////////////////////////////////////////////////////////////////////////////////////////////////
// Member accessing
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tint/transform/robustness.cc b/src/tint/transform/robustness.cc
index beb1108..e662e56 100644
--- a/src/tint/transform/robustness.cc
+++ b/src/tint/transform/robustness.cc
@@ -22,6 +22,7 @@
#include "src/tint/sem/block_statement.h"
#include "src/tint/sem/call.h"
#include "src/tint/sem/expression.h"
+#include "src/tint/sem/index_accessor_expression.h"
#include "src/tint/sem/reference.h"
#include "src/tint/sem/statement.h"
@@ -48,150 +49,80 @@
/// Apply bounds clamping to array, vector and matrix indexing
/// @param expr the array, vector or matrix index expression
- /// @return the clamped replacement expression, or nullptr if `expr` should be
- /// cloned without changes.
+ /// @return the clamped replacement expression, or nullptr if `expr` should be cloned without
+ /// changes.
const ast::IndexAccessorExpression* Transform(const ast::IndexAccessorExpression* expr) {
- auto* ret_type = ctx.src->Sem().Get(expr->object)->Type();
+ auto* sem =
+ ctx.src->Sem().Get(expr)->UnwrapMaterialize()->As<sem::IndexAccessorExpression>();
+ auto* ret_type = sem->Type();
auto* ref = ret_type->As<sem::Reference>();
if (ref && omitted_classes.count(ref->StorageClass()) != 0) {
return nullptr;
}
- auto* ret_unwrapped = ret_type->UnwrapRef();
-
ProgramBuilder& b = *ctx.dst;
- struct Value {
- const ast::Expression* expr = nullptr; // If null, then is a constant
- union {
- uint32_t u32 = 0; // use if is_signed == false
- int32_t i32; // use if is_signed == true
- };
- bool is_signed = false;
+ // idx return the cloned index expression, as a u32.
+ auto idx = [&]() -> const ast::Expression* {
+ auto* i = ctx.Clone(expr->index);
+ if (sem->Index()->Type()->UnwrapRef()->is_signed_integer_scalar()) {
+ return b.Construct(b.ty.u32(), i); // u32(idx)
+ }
+ return i;
};
- Value size; // size of the array, vector or matrix
- size.is_signed = false; // size is always unsigned
- if (auto* vec = ret_unwrapped->As<sem::Vector>()) {
- size.u32 = vec->Width();
-
- } else if (auto* arr = ret_unwrapped->As<sem::Array>()) {
- size.u32 = arr->Count();
- } else if (auto* mat = ret_unwrapped->As<sem::Matrix>()) {
- // The row accessor would have been an embedded index accessor and already
- // handled, so we just need to do columns here.
- size.u32 = mat->columns();
- } else {
- return nullptr;
- }
-
- if (size.u32 == 0) {
- if (!ret_unwrapped->Is<sem::Array>()) {
- b.Diagnostics().add_error(diag::System::Transform, "invalid 0 sized non-array",
- expr->source);
- return nullptr;
- }
- // Runtime sized array
- auto* arr = ctx.Clone(expr->object);
- size.expr = b.Call("arrayLength", b.AddressOf(arr));
- }
-
- // Calculate the maximum possible index value (size-1u)
- // Size must be positive (non-zero), so we can safely subtract 1 here
- // without underflow.
- Value limit;
- limit.is_signed = false; // Like size, limit is always unsigned.
- if (size.expr) {
- // Dynamic size
- limit.expr = b.Sub(size.expr, 1_u);
- } else {
- // Constant size
- limit.u32 = size.u32 - 1u;
- }
-
- Value idx; // index value
-
- auto* idx_sem = ctx.src->Sem().Get(expr->index);
- auto* idx_ty = idx_sem->Type()->UnwrapRef();
- if (!idx_ty->IsAnyOf<sem::I32, sem::U32>()) {
- TINT_ICE(Transform, b.Diagnostics())
- << "index must be u32 or i32, got " << idx_sem->Type()->TypeInfo().name;
- return nullptr;
- }
-
- if (auto* idx_constant = idx_sem->ConstantValue()) {
- // Constant value index
- auto val = std::get<AInt>(idx_constant->Value());
- if (idx_constant->Type()->Is<sem::I32>()) {
- idx.i32 = static_cast<int32_t>(val);
- idx.is_signed = true;
- } else if (idx_constant->Type()->Is<sem::U32>()) {
- idx.u32 = static_cast<uint32_t>(val);
- idx.is_signed = false;
- } else {
- TINT_ICE(Transform, b.Diagnostics()) << "unsupported constant value for accessor "
- << idx_constant->Type()->TypeInfo().name;
- return nullptr;
- }
- } else {
- // Dynamic value index
- idx.expr = ctx.Clone(expr->index);
- idx.is_signed = idx_ty->Is<sem::I32>();
- }
-
- // Clamp the index so that it cannot exceed limit.
- if (idx.expr || limit.expr) {
- // One of, or both of idx and limit are non-constant.
-
- // If the index is signed, cast it to a u32 (with clamping if constant).
- if (idx.is_signed) {
- if (idx.expr) {
- // We don't use a max(idx, 0) here, as that incurs a runtime
- // performance cost, and if the unsigned value will be clamped by
- // limit, resulting in a value between [0..limit)
- idx.expr = b.Construct<u32>(idx.expr);
- idx.is_signed = false;
- } else {
- idx.u32 = static_cast<uint32_t>(std::max(idx.i32, 0));
- idx.is_signed = false;
+ auto* clamped_idx = Switch(
+ sem->Object()->Type()->UnwrapRef(), //
+ [&](const sem::Vector* vec) -> const ast::Expression* {
+ if (sem->Index()->ConstantValue()) {
+ // Index and size is constant.
+ // Validation will have rejected any OOB accesses.
+ return nullptr;
}
- }
- // Convert idx and limit to expressions, so we can emit `min(idx, limit)`.
- if (!idx.expr) {
- idx.expr = b.Expr(u32(idx.u32));
- }
- if (!limit.expr) {
- limit.expr = b.Expr(u32(limit.u32));
- }
+ return b.Call("min", idx(), u32(vec->Width() - 1u));
+ },
+ [&](const sem::Matrix* mat) -> const ast::Expression* {
+ if (sem->Index()->ConstantValue()) {
+ // Index and size is constant.
+ // Validation will have rejected any OOB accesses.
+ return nullptr;
+ }
- // Perform the clamp with `min(idx, limit)`
- idx.expr = b.Call("min", idx.expr, limit.expr);
- } else {
- // Both idx and max are constant.
- if (idx.is_signed) {
- // The index is signed. Calculate limit as signed.
- int32_t signed_limit = static_cast<int32_t>(
- std::min<uint32_t>(limit.u32, std::numeric_limits<int32_t>::max()));
- idx.i32 = std::max(idx.i32, 0);
- idx.i32 = std::min(idx.i32, signed_limit);
- } else {
- // The index is unsigned.
- idx.u32 = std::min(idx.u32, limit.u32);
- }
+ return b.Call("min", idx(), u32(mat->columns() - 1u));
+ },
+ [&](const sem::Array* arr) -> const ast::Expression* {
+ const ast::Expression* max = nullptr;
+ if (arr->IsRuntimeSized()) {
+ // Size is unknown until runtime.
+ // Must clamp, even if the index is constant.
+ auto* arr_ptr = b.AddressOf(ctx.Clone(expr->object));
+ max = b.Sub(b.Call("arrayLength", arr_ptr), 1_u);
+ } else {
+ if (sem->Index()->ConstantValue()) {
+ // Index and size is constant.
+ // Validation will have rejected any OOB accesses.
+ return nullptr;
+ }
+ max = b.Expr(u32(arr->Count() - 1u));
+ }
+ return b.Call("min", idx(), max);
+ },
+ [&](Default) {
+ TINT_ICE(Transform, b.Diagnostics())
+ << "unhandled object type in robustness of array index: "
+ << ctx.src->FriendlyName(ret_type->UnwrapRef());
+ return nullptr;
+ });
+
+ if (!clamped_idx) {
+ return nullptr; // Clamping not needed
}
- // Convert idx to an expression, so we can emit the new accessor.
- if (!idx.expr) {
- idx.expr = idx.is_signed ? static_cast<const ast::Expression*>(b.Expr(i32(idx.i32)))
- : static_cast<const ast::Expression*>(b.Expr(u32(idx.u32)));
- }
-
- // Clone arguments outside of create() call to have deterministic ordering
auto src = ctx.Clone(expr->source);
auto* obj = ctx.Clone(expr->object);
- return b.IndexAccessor(src, obj, idx.expr);
+ return b.IndexAccessor(src, obj, clamped_idx);
}
/// @param type builtin type
diff --git a/src/tint/transform/robustness_test.cc b/src/tint/transform/robustness_test.cc
index 8dab595..e3d08f0 100644
--- a/src/tint/transform/robustness_test.cc
+++ b/src/tint/transform/robustness_test.cc
@@ -25,20 +25,18 @@
auto* src = R"(
var<private> a : array<f32, 3>;
-let c : u32 = 1u;
-
fn f() {
- let b : f32 = a[c];
+ let l : u32 = 1u;
+ let b : f32 = a[l];
}
)";
auto* expect = R"(
var<private> a : array<f32, 3>;
-const c : u32 = 1u;
-
fn f() {
- let b : f32 = a[1u];
+ let l : u32 = 1u;
+ let b : f32 = a[min(l, 2u)];
}
)";
@@ -47,6 +45,30 @@
EXPECT_EQ(expect, str(got));
}
+TEST_F(RobustnessTest, Array_Let_Idx_Clamp_OutOfOrder) {
+ auto* src = R"(
+fn f() {
+ let c : u32 = 1u;
+ let b : f32 = a[c];
+}
+
+var<private> a : array<f32, 3>;
+)";
+
+ auto* expect = R"(
+fn f() {
+ let c : u32 = 1u;
+ let b : f32 = a[min(c, 2u)];
+}
+
+var<private> a : array<f32, 3>;
+)";
+
+ auto got = Run<Robustness>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(RobustnessTest, Array_Const_Idx_Clamp) {
auto* src = R"(
var<private> a : array<f32, 3>;
@@ -64,34 +86,8 @@
const c : u32 = 1u;
fn f() {
- let b : f32 = a[1u];
-}
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Array_Let_Idx_Clamp_OutOfOrder) {
- auto* src = R"(
-fn f() {
let b : f32 = a[c];
}
-
-let c : u32 = 1u;
-
-var<private> a : array<f32, 3>;
-)";
-
- auto* expect = R"(
-fn f() {
- let b : f32 = a[1u];
-}
-
-const c : u32 = 1u;
-
-var<private> a : array<f32, 3>;
)";
auto got = Run<Robustness>(src);
@@ -112,7 +108,7 @@
auto* expect = R"(
fn f() {
- let b : f32 = a[1u];
+ let b : f32 = a[c];
}
const c : u32 = 1u;
@@ -281,94 +277,6 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(RobustnessTest, Array_Idx_Negative) {
- auto* src = R"(
-var<private> a : array<f32, 3>;
-
-fn f() {
- var b : f32 = a[-1];
-}
-)";
-
- auto* expect = R"(
-var<private> a : array<f32, 3>;
-
-fn f() {
- var b : f32 = a[0i];
-}
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Array_Idx_Negative_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var b : f32 = a[-1];
-}
-
-var<private> a : array<f32, 3>;
-)";
-
- auto* expect = R"(
-fn f() {
- var b : f32 = a[0i];
-}
-
-var<private> a : array<f32, 3>;
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Array_Idx_OutOfBounds) {
- auto* src = R"(
-var<private> a : array<f32, 3>;
-
-fn f() {
- var b : f32 = a[3];
-}
-)";
-
- auto* expect = R"(
-var<private> a : array<f32, 3>;
-
-fn f() {
- var b : f32 = a[2i];
-}
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Array_Idx_OutOfBounds_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var b : f32 = a[3];
-}
-
-var<private> a : array<f32, 3>;
-)";
-
- auto* expect = R"(
-fn f() {
- var b : f32 = a[2i];
-}
-
-var<private> a : array<f32, 3>;
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
// TODO(crbug.com/tint/1177) - Validation currently forbids arrays larger than
// 0xffffffff. If WGSL supports 64-bit indexing, re-enable this test.
TEST_F(RobustnessTest, DISABLED_LargeArrays_Idx) {
@@ -545,50 +453,6 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(RobustnessTest, Vector_Swizzle_Idx_Scalar) {
- auto* src = R"(
-var<private> a : vec3<f32>;
-
-fn f() {
- var b : f32 = a.xy[2];
-}
-)";
-
- auto* expect = R"(
-var<private> a : vec3<f32>;
-
-fn f() {
- var b : f32 = a.xy[1i];
-}
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Vector_Swizzle_Idx_Scalar_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var b : f32 = a.xy[2];
-}
-
-var<private> a : vec3<f32>;
-)";
-
- auto* expect = R"(
-fn f() {
- var b : f32 = a.xy[1i];
-}
-
-var<private> a : vec3<f32>;
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
TEST_F(RobustnessTest, Vector_Swizzle_Idx_Var) {
auto* src = R"(
var<private> a : vec3<f32>;
@@ -693,94 +557,6 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(RobustnessTest, Vector_Idx_Negative) {
- auto* src = R"(
-var<private> a : vec3<f32>;
-
-fn f() {
- var b : f32 = a[-1];
-}
-)";
-
- auto* expect = R"(
-var<private> a : vec3<f32>;
-
-fn f() {
- var b : f32 = a[0i];
-}
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Vector_Idx_Negative_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var b : f32 = a[-1];
-}
-
-var<private> a : vec3<f32>;
-)";
-
- auto* expect = R"(
-fn f() {
- var b : f32 = a[0i];
-}
-
-var<private> a : vec3<f32>;
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Vector_Idx_OutOfBounds) {
- auto* src = R"(
-var<private> a : vec3<f32>;
-
-fn f() {
- var b : f32 = a[3];
-}
-)";
-
- auto* expect = R"(
-var<private> a : vec3<f32>;
-
-fn f() {
- var b : f32 = a[2i];
-}
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Vector_Idx_OutOfBounds_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var b : f32 = a[3];
-}
-
-var<private> a : vec3<f32>;
-)";
-
- auto* expect = R"(
-fn f() {
- var b : f32 = a[2i];
-}
-
-var<private> a : vec3<f32>;
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
TEST_F(RobustnessTest, Matrix_Idx_Scalar) {
auto* src = R"(
var<private> a : mat3x2<f32>;
@@ -842,7 +618,7 @@
var<private> c : i32;
fn f() {
- var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1i];
+ var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1];
}
)";
@@ -864,7 +640,7 @@
auto* expect = R"(
fn f() {
- var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1i];
+ var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1];
}
var<private> c : i32;
@@ -894,7 +670,7 @@
var<private> c : i32;
fn f() {
- var b : f32 = a[1i][min(u32(((c + 2) - 3)), 1u)];
+ var b : f32 = a[1][min(u32(((c + 2) - 3)), 1u)];
}
)";
@@ -916,7 +692,7 @@
auto* expect = R"(
fn f() {
- var b : f32 = a[1i][min(u32(((c + 2) - 3)), 1u)];
+ var b : f32 = a[1][min(u32(((c + 2) - 3)), 1u)];
}
var<private> c : i32;
@@ -929,182 +705,6 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(RobustnessTest, Matrix_Idx_Negative_Column) {
- auto* src = R"(
-var<private> a : mat3x2<f32>;
-
-fn f() {
- var b : f32 = a[-1][1];
-}
-)";
-
- auto* expect = R"(
-var<private> a : mat3x2<f32>;
-
-fn f() {
- var b : f32 = a[0i][1i];
-}
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Matrix_Idx_Negative_Column_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var b : f32 = a[-1][1];
-}
-
-var<private> a : mat3x2<f32>;
-)";
-
- auto* expect = R"(
-fn f() {
- var b : f32 = a[0i][1i];
-}
-
-var<private> a : mat3x2<f32>;
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Matrix_Idx_Negative_Row) {
- auto* src = R"(
-var<private> a : mat3x2<f32>;
-
-fn f() {
- var b : f32 = a[2][-1];
-}
-)";
-
- auto* expect = R"(
-var<private> a : mat3x2<f32>;
-
-fn f() {
- var b : f32 = a[2i][0i];
-}
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Matrix_Idx_Negative_Row_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var b : f32 = a[2][-1];
-}
-
-var<private> a : mat3x2<f32>;
-)";
-
- auto* expect = R"(
-fn f() {
- var b : f32 = a[2i][0i];
-}
-
-var<private> a : mat3x2<f32>;
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Column) {
- auto* src = R"(
-var<private> a : mat3x2<f32>;
-
-fn f() {
- var b : f32 = a[5][1];
-}
-)";
-
- auto* expect = R"(
-var<private> a : mat3x2<f32>;
-
-fn f() {
- var b : f32 = a[2i][1i];
-}
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Column_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var b : f32 = a[5][1];
-}
-
-var<private> a : mat3x2<f32>;
-)";
-
- auto* expect = R"(
-fn f() {
- var b : f32 = a[2i][1i];
-}
-
-var<private> a : mat3x2<f32>;
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Row) {
- auto* src = R"(
-var<private> a : mat3x2<f32>;
-
-fn f() {
- var b : f32 = a[2][5];
-}
-)";
-
- auto* expect = R"(
-var<private> a : mat3x2<f32>;
-
-fn f() {
- var b : f32 = a[2i][1i];
-}
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Row_OutOfOrder) {
- auto* src = R"(
-fn f() {
- var b : f32 = a[2][5];
-}
-
-var<private> a : mat3x2<f32>;
-)";
-
- auto* expect = R"(
-fn f() {
- var b : f32 = a[2i][1i];
-}
-
-var<private> a : mat3x2<f32>;
-)";
-
- auto got = Run<Robustness>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
// TODO(dsinclair): Implement when constant_id exists
TEST_F(RobustnessTest, DISABLED_Vector_Constant_Id_Clamps) {
// @id(1300) override idx : i32;
@@ -1163,7 +763,7 @@
@group(0) @binding(0) var<storage, read> s : S;
fn f() {
- var d : f32 = s.b[min(25u, (arrayLength(&(s.b)) - 1u))];
+ var d : f32 = s.b[min(u32(25), (arrayLength(&(s.b)) - 1u))];
}
)";
@@ -1188,7 +788,7 @@
auto* expect = R"(
fn f() {
- var d : f32 = s.b[min(25u, (arrayLength(&(s.b)) - 1u))];
+ var d : f32 = s.b[min(u32(25), (arrayLength(&(s.b)) - 1u))];
}
@group(0) @binding(0) var<storage, read> s : S;
@@ -1464,7 +1064,7 @@
const c : u32 = 1u;
fn f() {
- let b : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
+ let b : f32 = s.b[min(c, (arrayLength(&(s.b)) - 1u))];
let x : i32 = min(1, 2);
let y : u32 = arrayLength(&(s.b));
}
@@ -1477,112 +1077,79 @@
const char* kOmitSourceShader = R"(
struct S {
- a : array<f32, 4>,
- b : array<f32>,
+ vector : vec3<f32>,
+ fixed_arr : array<f32, 4>,
+ runtime_arr : array<f32>,
};
@group(0) @binding(0) var<storage, read> s : S;
-type UArr = array<vec4<f32>, 4>;
struct U {
- a : UArr,
+ vector : vec4<f32>,
+ fixed_arr : array<vec4<f32>, 4>,
};
@group(1) @binding(0) var<uniform> u : U;
fn f() {
- // Signed
- var i32_sa1 : f32 = s.a[4];
- var i32_sa2 : f32 = s.a[1];
- var i32_sa3 : f32 = s.a[0];
- var i32_sa4 : f32 = s.a[-1];
- var i32_sa5 : f32 = s.a[-4];
-
- var i32_sb1 : f32 = s.b[4];
- var i32_sb2 : f32 = s.b[1];
- var i32_sb3 : f32 = s.b[0];
- var i32_sb4 : f32 = s.b[-1];
- var i32_sb5 : f32 = s.b[-4];
-
- var i32_ua1 : f32 = u.a[4].x;
- var i32_ua2 : f32 = u.a[1].x;
- var i32_ua3 : f32 = u.a[0].x;
- var i32_ua4 : f32 = u.a[-1].x;
- var i32_ua5 : f32 = u.a[-4].x;
-
- // Unsigned
- var u32_sa1 : f32 = s.a[0u];
- var u32_sa2 : f32 = s.a[1u];
- var u32_sa3 : f32 = s.a[3u];
- var u32_sa4 : f32 = s.a[4u];
- var u32_sa5 : f32 = s.a[10u];
- var u32_sa6 : f32 = s.a[100u];
-
- var u32_sb1 : f32 = s.b[0u];
- var u32_sb2 : f32 = s.b[1u];
- var u32_sb3 : f32 = s.b[3u];
- var u32_sb4 : f32 = s.b[4u];
- var u32_sb5 : f32 = s.b[10u];
- var u32_sb6 : f32 = s.b[100u];
-
- var u32_ua1 : f32 = u.a[0u].x;
- var u32_ua2 : f32 = u.a[1u].x;
- var u32_ua3 : f32 = u.a[3u].x;
- var u32_ua4 : f32 = u.a[4u].x;
- var u32_ua5 : f32 = u.a[10u].x;
- var u32_ua6 : f32 = u.a[100u].x;
+ // i32
+ {
+ let i = 0i;
+ var storage_vector : f32 = s.vector[i];
+ var storage_fixed_arr : f32 = s.fixed_arr[i];
+ var storage_runtime_arr : f32 = s.runtime_arr[i];
+ var uniform_vector : f32 = u.vector[i];
+ var uniform_fixed_arr : vec4<f32> = u.fixed_arr[i];
+ var uniform_fixed_arr_vector : f32 = u.fixed_arr[0][i];
+ }
+ // u32
+ {
+ let i = 0u;
+ var storage_vector : f32 = s.vector[i];
+ var storage_fixed_arr : f32 = s.fixed_arr[i];
+ var storage_runtime_arr : f32 = s.runtime_arr[i];
+ var uniform_vector : f32 = u.vector[i];
+ var uniform_fixed_arr : vec4<f32> = u.fixed_arr[i];
+ var uniform_fixed_arr_vector : f32 = u.fixed_arr[0][i];
+ }
}
)";
TEST_F(RobustnessTest, OmitNone) {
- auto* expect = R"(
+ auto* expect =
+ R"(
struct S {
- a : array<f32, 4>,
- b : array<f32>,
+ vector : vec3<f32>,
+ fixed_arr : array<f32, 4>,
+ runtime_arr : array<f32>,
}
@group(0) @binding(0) var<storage, read> s : S;
-type UArr = array<vec4<f32>, 4>;
-
struct U {
- a : UArr,
+ vector : vec4<f32>,
+ fixed_arr : array<vec4<f32>, 4>,
}
@group(1) @binding(0) var<uniform> u : U;
fn f() {
- var i32_sa1 : f32 = s.a[3i];
- var i32_sa2 : f32 = s.a[1i];
- var i32_sa3 : f32 = s.a[0i];
- var i32_sa4 : f32 = s.a[0i];
- var i32_sa5 : f32 = s.a[0i];
- var i32_sb1 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
- var i32_sb2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
- var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
- var i32_sb4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
- var i32_sb5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
- var i32_ua1 : f32 = u.a[3i].x;
- var i32_ua2 : f32 = u.a[1i].x;
- var i32_ua3 : f32 = u.a[0i].x;
- var i32_ua4 : f32 = u.a[0i].x;
- var i32_ua5 : f32 = u.a[0i].x;
- var u32_sa1 : f32 = s.a[0u];
- var u32_sa2 : f32 = s.a[1u];
- var u32_sa3 : f32 = s.a[3u];
- var u32_sa4 : f32 = s.a[3u];
- var u32_sa5 : f32 = s.a[3u];
- var u32_sa6 : f32 = s.a[3u];
- var u32_sb1 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
- var u32_sb2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
- var u32_sb3 : f32 = s.b[min(3u, (arrayLength(&(s.b)) - 1u))];
- var u32_sb4 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
- var u32_sb5 : f32 = s.b[min(10u, (arrayLength(&(s.b)) - 1u))];
- var u32_sb6 : f32 = s.b[min(100u, (arrayLength(&(s.b)) - 1u))];
- var u32_ua1 : f32 = u.a[0u].x;
- var u32_ua2 : f32 = u.a[1u].x;
- var u32_ua3 : f32 = u.a[3u].x;
- var u32_ua4 : f32 = u.a[3u].x;
- var u32_ua5 : f32 = u.a[3u].x;
- var u32_ua6 : f32 = u.a[3u].x;
+ {
+ let i = 0i;
+ var storage_vector : f32 = s.vector[min(u32(i), 2u)];
+ var storage_fixed_arr : f32 = s.fixed_arr[min(u32(i), 3u)];
+ var storage_runtime_arr : f32 = s.runtime_arr[min(u32(i), (arrayLength(&(s.runtime_arr)) - 1u))];
+ var uniform_vector : f32 = u.vector[min(u32(i), 3u)];
+ var uniform_fixed_arr : vec4<f32> = u.fixed_arr[min(u32(i), 3u)];
+ var uniform_fixed_arr_vector : f32 = u.fixed_arr[0][min(u32(i), 3u)];
+ }
+ {
+ let i = 0u;
+ var storage_vector : f32 = s.vector[min(i, 2u)];
+ var storage_fixed_arr : f32 = s.fixed_arr[min(i, 3u)];
+ var storage_runtime_arr : f32 = s.runtime_arr[min(i, (arrayLength(&(s.runtime_arr)) - 1u))];
+ var uniform_vector : f32 = u.vector[min(i, 3u)];
+ var uniform_fixed_arr : vec4<f32> = u.fixed_arr[min(i, 3u)];
+ var uniform_fixed_arr_vector : f32 = u.fixed_arr[0][min(i, 3u)];
+ }
}
)";
@@ -1596,56 +1163,42 @@
}
TEST_F(RobustnessTest, OmitStorage) {
- auto* expect = R"(
+ auto* expect =
+ R"(
struct S {
- a : array<f32, 4>,
- b : array<f32>,
+ vector : vec3<f32>,
+ fixed_arr : array<f32, 4>,
+ runtime_arr : array<f32>,
}
@group(0) @binding(0) var<storage, read> s : S;
-type UArr = array<vec4<f32>, 4>;
-
struct U {
- a : UArr,
+ vector : vec4<f32>,
+ fixed_arr : array<vec4<f32>, 4>,
}
@group(1) @binding(0) var<uniform> u : U;
fn f() {
- var i32_sa1 : f32 = s.a[4];
- var i32_sa2 : f32 = s.a[1];
- var i32_sa3 : f32 = s.a[0];
- var i32_sa4 : f32 = s.a[-1];
- var i32_sa5 : f32 = s.a[-4];
- var i32_sb1 : f32 = s.b[4];
- var i32_sb2 : f32 = s.b[1];
- var i32_sb3 : f32 = s.b[0];
- var i32_sb4 : f32 = s.b[-1];
- var i32_sb5 : f32 = s.b[-4];
- var i32_ua1 : f32 = u.a[3i].x;
- var i32_ua2 : f32 = u.a[1i].x;
- var i32_ua3 : f32 = u.a[0i].x;
- var i32_ua4 : f32 = u.a[0i].x;
- var i32_ua5 : f32 = u.a[0i].x;
- var u32_sa1 : f32 = s.a[0u];
- var u32_sa2 : f32 = s.a[1u];
- var u32_sa3 : f32 = s.a[3u];
- var u32_sa4 : f32 = s.a[4u];
- var u32_sa5 : f32 = s.a[10u];
- var u32_sa6 : f32 = s.a[100u];
- var u32_sb1 : f32 = s.b[0u];
- var u32_sb2 : f32 = s.b[1u];
- var u32_sb3 : f32 = s.b[3u];
- var u32_sb4 : f32 = s.b[4u];
- var u32_sb5 : f32 = s.b[10u];
- var u32_sb6 : f32 = s.b[100u];
- var u32_ua1 : f32 = u.a[0u].x;
- var u32_ua2 : f32 = u.a[1u].x;
- var u32_ua3 : f32 = u.a[3u].x;
- var u32_ua4 : f32 = u.a[3u].x;
- var u32_ua5 : f32 = u.a[3u].x;
- var u32_ua6 : f32 = u.a[3u].x;
+ {
+ let i = 0i;
+ var storage_vector : f32 = s.vector[i];
+ var storage_fixed_arr : f32 = s.fixed_arr[i];
+ var storage_runtime_arr : f32 = s.runtime_arr[i];
+ var uniform_vector : f32 = u.vector[min(u32(i), 3u)];
+ var uniform_fixed_arr : vec4<f32> = u.fixed_arr[min(u32(i), 3u)];
+ var uniform_fixed_arr_vector : f32 = u.fixed_arr[0][min(u32(i), 3u)];
+ }
+ {
+ let i = 0u;
+ var storage_vector : f32 = s.vector[i];
+ var storage_fixed_arr : f32 = s.fixed_arr[i];
+ var storage_runtime_arr : f32 = s.runtime_arr[i];
+ var uniform_vector : f32 = u.vector[min(i, 3u)];
+ var uniform_fixed_arr : vec4<f32> = u.fixed_arr[min(i, 3u)];
+ var uniform_fixed_arr_vector : f32 = u.fixed_arr[0][min(i, 3u)];
+ }
}
)";
@@ -1661,56 +1214,42 @@
}
TEST_F(RobustnessTest, OmitUniform) {
- auto* expect = R"(
+ auto* expect =
+ R"(
struct S {
- a : array<f32, 4>,
- b : array<f32>,
+ vector : vec3<f32>,
+ fixed_arr : array<f32, 4>,
+ runtime_arr : array<f32>,
}
@group(0) @binding(0) var<storage, read> s : S;
-type UArr = array<vec4<f32>, 4>;
-
struct U {
- a : UArr,
+ vector : vec4<f32>,
+ fixed_arr : array<vec4<f32>, 4>,
}
@group(1) @binding(0) var<uniform> u : U;
fn f() {
- var i32_sa1 : f32 = s.a[3i];
- var i32_sa2 : f32 = s.a[1i];
- var i32_sa3 : f32 = s.a[0i];
- var i32_sa4 : f32 = s.a[0i];
- var i32_sa5 : f32 = s.a[0i];
- var i32_sb1 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
- var i32_sb2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
- var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
- var i32_sb4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
- var i32_sb5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
- var i32_ua1 : f32 = u.a[4].x;
- var i32_ua2 : f32 = u.a[1].x;
- var i32_ua3 : f32 = u.a[0].x;
- var i32_ua4 : f32 = u.a[-1].x;
- var i32_ua5 : f32 = u.a[-4].x;
- var u32_sa1 : f32 = s.a[0u];
- var u32_sa2 : f32 = s.a[1u];
- var u32_sa3 : f32 = s.a[3u];
- var u32_sa4 : f32 = s.a[3u];
- var u32_sa5 : f32 = s.a[3u];
- var u32_sa6 : f32 = s.a[3u];
- var u32_sb1 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
- var u32_sb2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
- var u32_sb3 : f32 = s.b[min(3u, (arrayLength(&(s.b)) - 1u))];
- var u32_sb4 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
- var u32_sb5 : f32 = s.b[min(10u, (arrayLength(&(s.b)) - 1u))];
- var u32_sb6 : f32 = s.b[min(100u, (arrayLength(&(s.b)) - 1u))];
- var u32_ua1 : f32 = u.a[0u].x;
- var u32_ua2 : f32 = u.a[1u].x;
- var u32_ua3 : f32 = u.a[3u].x;
- var u32_ua4 : f32 = u.a[4u].x;
- var u32_ua5 : f32 = u.a[10u].x;
- var u32_ua6 : f32 = u.a[100u].x;
+ {
+ let i = 0i;
+ var storage_vector : f32 = s.vector[min(u32(i), 2u)];
+ var storage_fixed_arr : f32 = s.fixed_arr[min(u32(i), 3u)];
+ var storage_runtime_arr : f32 = s.runtime_arr[min(u32(i), (arrayLength(&(s.runtime_arr)) - 1u))];
+ var uniform_vector : f32 = u.vector[i];
+ var uniform_fixed_arr : vec4<f32> = u.fixed_arr[i];
+ var uniform_fixed_arr_vector : f32 = u.fixed_arr[0][i];
+ }
+ {
+ let i = 0u;
+ var storage_vector : f32 = s.vector[min(i, 2u)];
+ var storage_fixed_arr : f32 = s.fixed_arr[min(i, 3u)];
+ var storage_runtime_arr : f32 = s.runtime_arr[min(i, (arrayLength(&(s.runtime_arr)) - 1u))];
+ var uniform_vector : f32 = u.vector[i];
+ var uniform_fixed_arr : vec4<f32> = u.fixed_arr[i];
+ var uniform_fixed_arr_vector : f32 = u.fixed_arr[0][i];
+ }
}
)";
@@ -1726,56 +1265,42 @@
}
TEST_F(RobustnessTest, OmitBoth) {
- auto* expect = R"(
+ auto* expect =
+ R"(
struct S {
- a : array<f32, 4>,
- b : array<f32>,
+ vector : vec3<f32>,
+ fixed_arr : array<f32, 4>,
+ runtime_arr : array<f32>,
}
@group(0) @binding(0) var<storage, read> s : S;
-type UArr = array<vec4<f32>, 4>;
-
struct U {
- a : UArr,
+ vector : vec4<f32>,
+ fixed_arr : array<vec4<f32>, 4>,
}
@group(1) @binding(0) var<uniform> u : U;
fn f() {
- var i32_sa1 : f32 = s.a[4];
- var i32_sa2 : f32 = s.a[1];
- var i32_sa3 : f32 = s.a[0];
- var i32_sa4 : f32 = s.a[-1];
- var i32_sa5 : f32 = s.a[-4];
- var i32_sb1 : f32 = s.b[4];
- var i32_sb2 : f32 = s.b[1];
- var i32_sb3 : f32 = s.b[0];
- var i32_sb4 : f32 = s.b[-1];
- var i32_sb5 : f32 = s.b[-4];
- var i32_ua1 : f32 = u.a[4].x;
- var i32_ua2 : f32 = u.a[1].x;
- var i32_ua3 : f32 = u.a[0].x;
- var i32_ua4 : f32 = u.a[-1].x;
- var i32_ua5 : f32 = u.a[-4].x;
- var u32_sa1 : f32 = s.a[0u];
- var u32_sa2 : f32 = s.a[1u];
- var u32_sa3 : f32 = s.a[3u];
- var u32_sa4 : f32 = s.a[4u];
- var u32_sa5 : f32 = s.a[10u];
- var u32_sa6 : f32 = s.a[100u];
- var u32_sb1 : f32 = s.b[0u];
- var u32_sb2 : f32 = s.b[1u];
- var u32_sb3 : f32 = s.b[3u];
- var u32_sb4 : f32 = s.b[4u];
- var u32_sb5 : f32 = s.b[10u];
- var u32_sb6 : f32 = s.b[100u];
- var u32_ua1 : f32 = u.a[0u].x;
- var u32_ua2 : f32 = u.a[1u].x;
- var u32_ua3 : f32 = u.a[3u].x;
- var u32_ua4 : f32 = u.a[4u].x;
- var u32_ua5 : f32 = u.a[10u].x;
- var u32_ua6 : f32 = u.a[100u].x;
+ {
+ let i = 0i;
+ var storage_vector : f32 = s.vector[i];
+ var storage_fixed_arr : f32 = s.fixed_arr[i];
+ var storage_runtime_arr : f32 = s.runtime_arr[i];
+ var uniform_vector : f32 = u.vector[i];
+ var uniform_fixed_arr : vec4<f32> = u.fixed_arr[i];
+ var uniform_fixed_arr_vector : f32 = u.fixed_arr[0][i];
+ }
+ {
+ let i = 0u;
+ var storage_vector : f32 = s.vector[i];
+ var storage_fixed_arr : f32 = s.fixed_arr[i];
+ var storage_runtime_arr : f32 = s.runtime_arr[i];
+ var uniform_vector : f32 = u.vector[i];
+ var uniform_fixed_arr : vec4<f32> = u.fixed_arr[i];
+ var uniform_fixed_arr_vector : f32 = u.fixed_arr[0][i];
+ }
}
)";