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>
This commit is contained in:
parent
75943c234f
commit
f3d9ea4bea
|
@ -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)
|
||||
|
|
|
@ -899,27 +899,28 @@ ConstEval::ConstantResult ConstEval::MatCtorV(const sem::Type* ty,
|
|||
|
||||
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),
|
||||
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);
|
||||
idx = clamped;
|
||||
return utils::Failure;
|
||||
}
|
||||
|
||||
auto obj_val = obj_expr->ConstantValue();
|
||||
if (!obj_val) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return obj_val->Index(static_cast<size_t>(idx));
|
||||
|
|
|
@ -2498,34 +2498,16 @@ TEST_F(ResolverConstEvalTest, Vec3_Index_OOB_High) {
|
|||
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 @@ TEST_F(ResolverConstEvalTest, Mat3x2_Index_OOB_High) {
|
|||
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 @@ TEST_F(ResolverConstEvalTest, Mat3x2_Index_OOB_Low) {
|
|||
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 @@ TEST_F(ResolverConstEvalTest, Array_vec3_f32_Index_OOB_High) {
|
|||
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 @@ TEST_F(ResolverConstEvalTest, Array_vec3_f32_Index_OOB_Low) {
|
|||
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) {
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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 @@ struct Robustness::State {
|
|||
|
||||
/// 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 {
|
||||
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;
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
// 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);
|
||||
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 {
|
||||
// Constant size
|
||||
limit.u32 = size.u32 - 1u;
|
||||
if (sem->Index()->ConstantValue()) {
|
||||
// Index and size is constant.
|
||||
// Validation will have rejected any OOB accesses.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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>()) {
|
||||
max = b.Expr(u32(arr->Count() - 1u));
|
||||
}
|
||||
return b.Call("min", idx(), max);
|
||||
},
|
||||
[&](Default) {
|
||||
TINT_ICE(Transform, b.Diagnostics())
|
||||
<< "index must be u32 or i32, got " << idx_sem->Type()->TypeInfo().name;
|
||||
<< "unhandled object type in robustness of array index: "
|
||||
<< ctx.src->FriendlyName(ret_type->UnwrapRef());
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
if (!clamped_idx) {
|
||||
return nullptr; // Clamping not needed
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
@ -25,20 +25,18 @@ TEST_F(RobustnessTest, Array_Let_Idx_Clamp) {
|
|||
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 @@ fn f() {
|
|||
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>;
|
||||
|
@ -63,35 +85,9 @@ var<private> a : array<f32, 3>;
|
|||
|
||||
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 @@ var<private> a : array<f32, 3>;
|
|||
|
||||
auto* expect = R"(
|
||||
fn f() {
|
||||
let b : f32 = a[1u];
|
||||
let b : f32 = a[c];
|
||||
}
|
||||
|
||||
const c : u32 = 1u;
|
||||
|
@ -281,94 +277,6 @@ var<private> a : array<f32, 3>;
|
|||
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 @@ var<private> a : vec3<f32>;
|
|||
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 @@ var<private> a : vec3<f32>;
|
|||
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> a : mat3x2<f32>;
|
|||
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 @@ var<private> a : mat3x2<f32>;
|
|||
|
||||
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> a : mat3x2<f32>;
|
|||
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 @@ var<private> a : mat3x2<f32>;
|
|||
|
||||
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 @@ var<private> a : mat3x2<f32>;
|
|||
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 @@ struct S {
|
|||
@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 @@ struct S {
|
|||
|
||||
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 @@ struct S {
|
|||
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 @@ fn f() {
|
|||
|
||||
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 @@ fn f() {
|
|||
}
|
||||
|
||||
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 @@ fn f() {
|
|||
}
|
||||
|
||||
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 @@ fn f() {
|
|||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
|
|
Loading…
Reference in New Issue