[spirv] Fix use-after-move in Std140 transform
This is only observed when the index list to get the matrix is long
enough.
Change-Id: I8dded7ad2de2d067f7753742fa33a22de313e0d9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/192223
Auto-Submit: James Price <jrprice@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/tint/lang/core/ir/transform/std140.cc b/src/tint/lang/core/ir/transform/std140.cc
index a61b8bc..c21f490 100644
--- a/src/tint/lang/core/ir/transform/std140.cc
+++ b/src/tint/lang/core/ir/transform/std140.cc
@@ -239,9 +239,9 @@
Value* RebuildMatrix(const core::type::Matrix* mat, Value* root, VectorRef<Value*> indices) {
// Recombine each column vector from the struct and reconstruct the original matrix type.
bool is_ptr = root->Type()->Is<core::type::Pointer>();
+ auto first_column = indices.Back()->As<Constant>()->Value()->ValueAs<uint32_t>();
Vector<Value*, 4> column_indices(std::move(indices));
Vector<Value*, 4> args;
- auto first_column = indices.Back()->As<Constant>()->Value()->ValueAs<uint32_t>();
for (uint32_t i = 0; i < mat->columns(); i++) {
column_indices.Back() = b.Constant(u32(first_column + i));
if (is_ptr) {
diff --git a/src/tint/lang/core/ir/transform/std140_test.cc b/src/tint/lang/core/ir/transform/std140_test.cc
index 28a67fa..f139e38 100644
--- a/src/tint/lang/core/ir/transform/std140_test.cc
+++ b/src/tint/lang/core/ir/transform/std140_test.cc
@@ -874,6 +874,99 @@
EXPECT_EQ(expect, str());
}
+TEST_F(IR_Std140Test, Mat3x2_Nested_AccessInstructionWithManyIndices_LoadMatrix) {
+ auto* mat = ty.mat3x2<f32>();
+ auto* inner = ty.Struct(mod.symbols.New("Inner"), {
+ {mod.symbols.New("m"), ty.array(mat, 4)},
+ });
+ auto* arr = ty.array(inner, 4u);
+ auto* outer = ty.Struct(mod.symbols.New("Outer"), {
+ {mod.symbols.New("arr"), arr},
+ });
+ outer->SetStructFlag(core::type::kBlock);
+
+ auto* buffer = b.Var("buffer", ty.ptr(uniform, outer));
+ buffer->SetBindingPoint(0, 0);
+ mod.root_block->Append(buffer);
+
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* mat_ptr = b.Access(ty.ptr(uniform, mat), buffer, 0_u, 1_u, 0_u, 2_u);
+ b.Let("mat", b.Load(mat_ptr));
+ b.Return(func);
+ });
+
+ auto* src = R"(
+Inner = struct @align(8) {
+ m:array<mat3x2<f32>, 4> @offset(0)
+}
+
+Outer = struct @align(8), @block {
+ arr:array<Inner, 4> @offset(0)
+}
+
+$B1: { # root
+ %buffer:ptr<uniform, Outer, read> = var @binding_point(0, 0)
+}
+
+%foo = func():void {
+ $B2: {
+ %3:ptr<uniform, mat3x2<f32>, read> = access %buffer, 0u, 1u, 0u, 2u
+ %4:mat3x2<f32> = load %3
+ %mat:mat3x2<f32> = let %4
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+Inner = struct @align(8) {
+ m:array<mat3x2<f32>, 4> @offset(0)
+}
+
+Outer = struct @align(8), @block {
+ arr:array<Inner, 4> @offset(0)
+}
+
+mat3x2_f32_std140 = struct @align(8) {
+ col0:vec2<f32> @offset(0)
+ col1:vec2<f32> @offset(8)
+ col2:vec2<f32> @offset(16)
+}
+
+Inner_std140 = struct @align(8) {
+ m:array<mat3x2_f32_std140, 4> @offset(0)
+}
+
+Outer_std140 = struct @align(8), @block {
+ arr:array<Inner_std140, 4> @offset(0)
+}
+
+$B1: { # root
+ %buffer:ptr<uniform, Outer_std140, read> = var @binding_point(0, 0)
+}
+
+%foo = func():void {
+ $B2: {
+ %3:ptr<uniform, vec2<f32>, read> = access %buffer, 0u, 1u, 0u, 2u, 0u
+ %4:vec2<f32> = load %3
+ %5:ptr<uniform, vec2<f32>, read> = access %buffer, 0u, 1u, 0u, 2u, 1u
+ %6:vec2<f32> = load %5
+ %7:ptr<uniform, vec2<f32>, read> = access %buffer, 0u, 1u, 0u, 2u, 2u
+ %8:vec2<f32> = load %7
+ %9:mat3x2<f32> = construct %4, %6, %8
+ %mat:mat3x2<f32> = let %9
+ ret
+ }
+}
+)";
+
+ Run(Std140);
+
+ EXPECT_EQ(expect, str());
+}
+
TEST_F(IR_Std140Test, Mat3x2_Nested_ChainOfAccessInstructions) {
auto* mat = ty.mat3x2<f32>();
auto* inner = ty.Struct(mod.symbols.New("Inner"), {