[tint] Add VectorizeScalarMatrixConstructors
Several target languages are missing these constructors. Use it from
the SPIR-V backend.
Fixed: tint:2078
Change-Id: I908360d464c9d5eaa324cf8302780ccc2a73d9d9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/158204
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/core/ir/transform/BUILD.bazel b/src/tint/lang/core/ir/transform/BUILD.bazel
index 44a3f6a..c5b1f51 100644
--- a/src/tint/lang/core/ir/transform/BUILD.bazel
+++ b/src/tint/lang/core/ir/transform/BUILD.bazel
@@ -54,6 +54,7 @@
"robustness.cc",
"shader_io.cc",
"std140.cc",
+ "vectorize_scalar_matrix_constructors.cc",
"zero_init_workgroup_memory.cc",
],
hdrs = [
@@ -72,6 +73,7 @@
"robustness.h",
"shader_io.h",
"std140.h",
+ "vectorize_scalar_matrix_constructors.h",
"zero_init_workgroup_memory.h",
],
deps = [
@@ -118,6 +120,7 @@
"preserve_padding_test.cc",
"robustness_test.cc",
"std140_test.cc",
+ "vectorize_scalar_matrix_constructors_test.cc",
"zero_init_workgroup_memory_test.cc",
] + select({
"//conditions:default": [],
diff --git a/src/tint/lang/core/ir/transform/BUILD.cmake b/src/tint/lang/core/ir/transform/BUILD.cmake
index ed4ae4b3..40c0852 100644
--- a/src/tint/lang/core/ir/transform/BUILD.cmake
+++ b/src/tint/lang/core/ir/transform/BUILD.cmake
@@ -69,6 +69,8 @@
lang/core/ir/transform/shader_io.h
lang/core/ir/transform/std140.cc
lang/core/ir/transform/std140.h
+ lang/core/ir/transform/vectorize_scalar_matrix_constructors.cc
+ lang/core/ir/transform/vectorize_scalar_matrix_constructors.h
lang/core/ir/transform/zero_init_workgroup_memory.cc
lang/core/ir/transform/zero_init_workgroup_memory.h
)
@@ -116,6 +118,7 @@
lang/core/ir/transform/preserve_padding_test.cc
lang/core/ir/transform/robustness_test.cc
lang/core/ir/transform/std140_test.cc
+ lang/core/ir/transform/vectorize_scalar_matrix_constructors_test.cc
lang/core/ir/transform/zero_init_workgroup_memory_test.cc
)
diff --git a/src/tint/lang/core/ir/transform/BUILD.gn b/src/tint/lang/core/ir/transform/BUILD.gn
index 91305e4..f4fb43e 100644
--- a/src/tint/lang/core/ir/transform/BUILD.gn
+++ b/src/tint/lang/core/ir/transform/BUILD.gn
@@ -74,6 +74,8 @@
"shader_io.h",
"std140.cc",
"std140.h",
+ "vectorize_scalar_matrix_constructors.cc",
+ "vectorize_scalar_matrix_constructors.h",
"zero_init_workgroup_memory.cc",
"zero_init_workgroup_memory.h",
]
@@ -118,6 +120,7 @@
"preserve_padding_test.cc",
"robustness_test.cc",
"std140_test.cc",
+ "vectorize_scalar_matrix_constructors_test.cc",
"zero_init_workgroup_memory_test.cc",
]
deps = [
diff --git a/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.cc b/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.cc
new file mode 100644
index 0000000..68e365a
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.cc
@@ -0,0 +1,109 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/ir/builder.h"
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/core/ir/validator.h"
+
+using namespace tint::core::fluent_types; // NOLINT
+using namespace tint::core::number_suffixes; // NOLINT
+
+namespace tint::core::ir::transform {
+
+namespace {
+
+/// PIMPL state for the transform.
+struct State {
+ /// The IR module.
+ Module& ir;
+
+ /// The IR builder.
+ Builder b{ir};
+
+ /// The type manager.
+ core::type::Manager& ty{ir.Types()};
+
+ /// Process the module.
+ void Process() {
+ // Find and replace matrix constructors that take scalar operands.
+ Vector<Construct*, 8> worklist;
+ for (auto inst : ir.instructions.Objects()) {
+ if (auto* construct = inst->As<Construct>(); construct && construct->Alive()) {
+ if (construct->Result()->Type()->As<type::Matrix>()) {
+ if (construct->Operands().Length() > 0 &&
+ construct->Operands()[0]->Type()->Is<type::Scalar>()) {
+ b.InsertBefore(construct, [&] { //
+ ReplaceConstructor(construct);
+ });
+ }
+ }
+ }
+ }
+ }
+
+ /// Replace a matrix construct instruction.
+ /// @param construct the instruction to replace
+ void ReplaceConstructor(Construct* construct) {
+ auto* mat = construct->Result()->Type()->As<type::Matrix>();
+ auto* col = mat->ColumnType();
+ const auto& scalars = construct->Operands();
+
+ // Collect consecutive scalars into column vectors.
+ Vector<Value*, 4> columns;
+ for (uint32_t c = 0; c < mat->columns(); c++) {
+ Vector<Value*, 4> values;
+ for (uint32_t r = 0; r < col->Width(); r++) {
+ values.Push(scalars[c * col->Width() + r]);
+ }
+ columns.Push(b.Construct(col, std::move(values))->Result());
+ }
+
+ // Construct the matrix from the column vectors and replace the original instruction.
+ auto* replacement = b.Construct(mat, std::move(columns))->Result();
+ construct->Result()->ReplaceAllUsesWith(replacement);
+ construct->Destroy();
+ }
+};
+
+} // namespace
+
+Result<SuccessType> VectorizeScalarMatrixConstructors(Module& ir) {
+ auto result = ValidateAndDumpIfNeeded(ir, "VectorizeScalarMatrixConstructors transform");
+ if (!result) {
+ return result;
+ }
+
+ State{ir}.Process();
+
+ return Success;
+}
+
+} // namespace tint::core::ir::transform
diff --git a/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.h b/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.h
new file mode 100644
index 0000000..ff4ef93
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.h
@@ -0,0 +1,49 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_CORE_IR_TRANSFORM_VECTORIZE_SCALAR_MATRIX_CONSTRUCTORS_H_
+#define SRC_TINT_LANG_CORE_IR_TRANSFORM_VECTORIZE_SCALAR_MATRIX_CONSTRUCTORS_H_
+
+#include "src/tint/utils/result/result.h"
+
+// Forward declarations.
+namespace tint::core::ir {
+class Module;
+}
+
+namespace tint::core::ir::transform {
+
+/// VectorizeScalarMatrixConstructors is a transform that replaces construct instructions that
+/// produce matrices from scalar operands to construct individual columns first.
+///
+/// @param module the module to transform
+/// @returns success or failure
+Result<SuccessType> VectorizeScalarMatrixConstructors(Module& module);
+
+} // namespace tint::core::ir::transform
+
+#endif // SRC_TINT_LANG_CORE_IR_TRANSFORM_VECTORIZE_SCALAR_MATRIX_CONSTRUCTORS_H_
diff --git a/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors_test.cc b/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors_test.cc
new file mode 100644
index 0000000..4f42888
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors_test.cc
@@ -0,0 +1,576 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/ir/transform/helper_test.h"
+#include "src/tint/lang/core/type/matrix.h"
+
+namespace tint::core::ir::transform {
+namespace {
+
+using namespace tint::core::fluent_types; // NOLINT
+using namespace tint::core::number_suffixes; // NOLINT
+
+using IR_VectorizeScalarMatrixConstructorsTest = TransformTest;
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, NoModify_NoOperands) {
+ auto* mat = ty.mat3x3<f32>();
+ auto* func = b.Function("foo", mat);
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func():mat3x3<f32> -> %b1 {
+ %b1 = block {
+ %2:mat3x3<f32> = construct
+ ret %2
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, NoModify_Identity) {
+ auto* mat = ty.mat3x3<f32>();
+ auto* value = b.FunctionParam("value", mat);
+ auto* func = b.Function("foo", mat);
+ func->SetParams({value});
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat, value);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%value:mat3x3<f32>):mat3x3<f32> -> %b1 {
+ %b1 = block {
+ %3:mat3x3<f32> = construct %value
+ ret %3
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, NoModify_Vectors) {
+ auto* mat = ty.mat3x3<f32>();
+ auto* v1 = b.FunctionParam("v1", mat->ColumnType());
+ auto* v2 = b.FunctionParam("v2", mat->ColumnType());
+ auto* v3 = b.FunctionParam("v3", mat->ColumnType());
+ auto* func = b.Function("foo", mat);
+ func->SetParams({v1, v2, v3});
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat, v1, v2, v3);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%v1:vec3<f32>, %v2:vec3<f32>, %v3:vec3<f32>):mat3x3<f32> -> %b1 {
+ %b1 = block {
+ %5:mat3x3<f32> = construct %v1, %v2, %v3
+ ret %5
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, Mat2x2) {
+ auto* mat = ty.mat2x2<f32>();
+ auto* v1 = b.FunctionParam("v1", ty.f32());
+ auto* v2 = b.FunctionParam("v2", ty.f32());
+ auto* v3 = b.FunctionParam("v3", ty.f32());
+ auto* v4 = b.FunctionParam("v4", ty.f32());
+ auto* func = b.Function("foo", mat);
+ func->SetParams({v1, v2, v3, v4});
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat, v1, v2, v3, v4);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32):mat2x2<f32> -> %b1 {
+ %b1 = block {
+ %6:mat2x2<f32> = construct %v1, %v2, %v3, %v4
+ ret %6
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32):mat2x2<f32> -> %b1 {
+ %b1 = block {
+ %6:vec2<f32> = construct %v1, %v2
+ %7:vec2<f32> = construct %v3, %v4
+ %8:mat2x2<f32> = construct %6, %7
+ ret %8
+ }
+}
+)";
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, Mat2x3) {
+ auto* mat = ty.mat2x3<f32>();
+ auto* v1 = b.FunctionParam("v1", ty.f32());
+ auto* v2 = b.FunctionParam("v2", ty.f32());
+ auto* v3 = b.FunctionParam("v3", ty.f32());
+ auto* v4 = b.FunctionParam("v4", ty.f32());
+ auto* v5 = b.FunctionParam("v5", ty.f32());
+ auto* v6 = b.FunctionParam("v6", ty.f32());
+ auto* func = b.Function("foo", mat);
+ func->SetParams({v1, v2, v3, v4, v5, v6});
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32):mat2x3<f32> -> %b1 {
+ %b1 = block {
+ %8:mat2x3<f32> = construct %v1, %v2, %v3, %v4, %v5, %v6
+ ret %8
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32):mat2x3<f32> -> %b1 {
+ %b1 = block {
+ %8:vec3<f32> = construct %v1, %v2, %v3
+ %9:vec3<f32> = construct %v4, %v5, %v6
+ %10:mat2x3<f32> = construct %8, %9
+ ret %10
+ }
+}
+)";
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, Mat2x4) {
+ auto* mat = ty.mat2x4<f32>();
+ auto* v1 = b.FunctionParam("v1", ty.f32());
+ auto* v2 = b.FunctionParam("v2", ty.f32());
+ auto* v3 = b.FunctionParam("v3", ty.f32());
+ auto* v4 = b.FunctionParam("v4", ty.f32());
+ auto* v5 = b.FunctionParam("v5", ty.f32());
+ auto* v6 = b.FunctionParam("v6", ty.f32());
+ auto* v7 = b.FunctionParam("v7", ty.f32());
+ auto* v8 = b.FunctionParam("v8", ty.f32());
+ auto* func = b.Function("foo", mat);
+ func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8});
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32):mat2x4<f32> -> %b1 {
+ %b1 = block {
+ %10:mat2x4<f32> = construct %v1, %v2, %v3, %v4, %v5, %v6, %v7, %v8
+ ret %10
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32):mat2x4<f32> -> %b1 {
+ %b1 = block {
+ %10:vec4<f32> = construct %v1, %v2, %v3, %v4
+ %11:vec4<f32> = construct %v5, %v6, %v7, %v8
+ %12:mat2x4<f32> = construct %10, %11
+ ret %12
+ }
+}
+)";
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, Mat3x2) {
+ auto* mat = ty.mat3x2<f32>();
+ auto* v1 = b.FunctionParam("v1", ty.f32());
+ auto* v2 = b.FunctionParam("v2", ty.f32());
+ auto* v3 = b.FunctionParam("v3", ty.f32());
+ auto* v4 = b.FunctionParam("v4", ty.f32());
+ auto* v5 = b.FunctionParam("v5", ty.f32());
+ auto* v6 = b.FunctionParam("v6", ty.f32());
+ auto* func = b.Function("foo", mat);
+ func->SetParams({v1, v2, v3, v4, v5, v6});
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32):mat3x2<f32> -> %b1 {
+ %b1 = block {
+ %8:mat3x2<f32> = construct %v1, %v2, %v3, %v4, %v5, %v6
+ ret %8
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32):mat3x2<f32> -> %b1 {
+ %b1 = block {
+ %8:vec2<f32> = construct %v1, %v2
+ %9:vec2<f32> = construct %v3, %v4
+ %10:vec2<f32> = construct %v5, %v6
+ %11:mat3x2<f32> = construct %8, %9, %10
+ ret %11
+ }
+}
+)";
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, Mat3x3) {
+ auto* mat = ty.mat3x3<f32>();
+ auto* v1 = b.FunctionParam("v1", ty.f32());
+ auto* v2 = b.FunctionParam("v2", ty.f32());
+ auto* v3 = b.FunctionParam("v3", ty.f32());
+ auto* v4 = b.FunctionParam("v4", ty.f32());
+ auto* v5 = b.FunctionParam("v5", ty.f32());
+ auto* v6 = b.FunctionParam("v6", ty.f32());
+ auto* v7 = b.FunctionParam("v7", ty.f32());
+ auto* v8 = b.FunctionParam("v8", ty.f32());
+ auto* v9 = b.FunctionParam("v9", ty.f32());
+ auto* func = b.Function("foo", mat);
+ func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8, v9});
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8, v9);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32, %v9:f32):mat3x3<f32> -> %b1 {
+ %b1 = block {
+ %11:mat3x3<f32> = construct %v1, %v2, %v3, %v4, %v5, %v6, %v7, %v8, %v9
+ ret %11
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32, %v9:f32):mat3x3<f32> -> %b1 {
+ %b1 = block {
+ %11:vec3<f32> = construct %v1, %v2, %v3
+ %12:vec3<f32> = construct %v4, %v5, %v6
+ %13:vec3<f32> = construct %v7, %v8, %v9
+ %14:mat3x3<f32> = construct %11, %12, %13
+ ret %14
+ }
+}
+)";
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, Mat3x4) {
+ auto* mat = ty.mat3x4<f32>();
+ auto* v1 = b.FunctionParam("v1", ty.f32());
+ auto* v2 = b.FunctionParam("v2", ty.f32());
+ auto* v3 = b.FunctionParam("v3", ty.f32());
+ auto* v4 = b.FunctionParam("v4", ty.f32());
+ auto* v5 = b.FunctionParam("v5", ty.f32());
+ auto* v6 = b.FunctionParam("v6", ty.f32());
+ auto* v7 = b.FunctionParam("v7", ty.f32());
+ auto* v8 = b.FunctionParam("v8", ty.f32());
+ auto* v9 = b.FunctionParam("v9", ty.f32());
+ auto* v10 = b.FunctionParam("v10", ty.f32());
+ auto* v11 = b.FunctionParam("v11", ty.f32());
+ auto* v12 = b.FunctionParam("v12", ty.f32());
+ auto* func = b.Function("foo", mat);
+ func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12});
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32, %v9:f32, %v10:f32, %v11:f32, %v12:f32):mat3x4<f32> -> %b1 {
+ %b1 = block {
+ %14:mat3x4<f32> = construct %v1, %v2, %v3, %v4, %v5, %v6, %v7, %v8, %v9, %v10, %v11, %v12
+ ret %14
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32, %v9:f32, %v10:f32, %v11:f32, %v12:f32):mat3x4<f32> -> %b1 {
+ %b1 = block {
+ %14:vec4<f32> = construct %v1, %v2, %v3, %v4
+ %15:vec4<f32> = construct %v5, %v6, %v7, %v8
+ %16:vec4<f32> = construct %v9, %v10, %v11, %v12
+ %17:mat3x4<f32> = construct %14, %15, %16
+ ret %17
+ }
+}
+)";
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, Mat4x2) {
+ auto* mat = ty.mat4x2<f32>();
+ auto* v1 = b.FunctionParam("v1", ty.f32());
+ auto* v2 = b.FunctionParam("v2", ty.f32());
+ auto* v3 = b.FunctionParam("v3", ty.f32());
+ auto* v4 = b.FunctionParam("v4", ty.f32());
+ auto* v5 = b.FunctionParam("v5", ty.f32());
+ auto* v6 = b.FunctionParam("v6", ty.f32());
+ auto* v7 = b.FunctionParam("v7", ty.f32());
+ auto* v8 = b.FunctionParam("v8", ty.f32());
+ auto* func = b.Function("foo", mat);
+ func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8});
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32):mat4x2<f32> -> %b1 {
+ %b1 = block {
+ %10:mat4x2<f32> = construct %v1, %v2, %v3, %v4, %v5, %v6, %v7, %v8
+ ret %10
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32):mat4x2<f32> -> %b1 {
+ %b1 = block {
+ %10:vec2<f32> = construct %v1, %v2
+ %11:vec2<f32> = construct %v3, %v4
+ %12:vec2<f32> = construct %v5, %v6
+ %13:vec2<f32> = construct %v7, %v8
+ %14:mat4x2<f32> = construct %10, %11, %12, %13
+ ret %14
+ }
+}
+)";
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, Mat4x3) {
+ auto* mat = ty.mat4x3<f32>();
+ auto* v1 = b.FunctionParam("v1", ty.f32());
+ auto* v2 = b.FunctionParam("v2", ty.f32());
+ auto* v3 = b.FunctionParam("v3", ty.f32());
+ auto* v4 = b.FunctionParam("v4", ty.f32());
+ auto* v5 = b.FunctionParam("v5", ty.f32());
+ auto* v6 = b.FunctionParam("v6", ty.f32());
+ auto* v7 = b.FunctionParam("v7", ty.f32());
+ auto* v8 = b.FunctionParam("v8", ty.f32());
+ auto* v9 = b.FunctionParam("v9", ty.f32());
+ auto* v10 = b.FunctionParam("v10", ty.f32());
+ auto* v11 = b.FunctionParam("v11", ty.f32());
+ auto* v12 = b.FunctionParam("v12", ty.f32());
+ auto* func = b.Function("foo", mat);
+ func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12});
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32, %v9:f32, %v10:f32, %v11:f32, %v12:f32):mat4x3<f32> -> %b1 {
+ %b1 = block {
+ %14:mat4x3<f32> = construct %v1, %v2, %v3, %v4, %v5, %v6, %v7, %v8, %v9, %v10, %v11, %v12
+ ret %14
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32, %v9:f32, %v10:f32, %v11:f32, %v12:f32):mat4x3<f32> -> %b1 {
+ %b1 = block {
+ %14:vec3<f32> = construct %v1, %v2, %v3
+ %15:vec3<f32> = construct %v4, %v5, %v6
+ %16:vec3<f32> = construct %v7, %v8, %v9
+ %17:vec3<f32> = construct %v10, %v11, %v12
+ %18:mat4x3<f32> = construct %14, %15, %16, %17
+ ret %18
+ }
+}
+)";
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, Mat4x4) {
+ auto* mat = ty.mat4x4<f32>();
+ auto* v1 = b.FunctionParam("v1", ty.f32());
+ auto* v2 = b.FunctionParam("v2", ty.f32());
+ auto* v3 = b.FunctionParam("v3", ty.f32());
+ auto* v4 = b.FunctionParam("v4", ty.f32());
+ auto* v5 = b.FunctionParam("v5", ty.f32());
+ auto* v6 = b.FunctionParam("v6", ty.f32());
+ auto* v7 = b.FunctionParam("v7", ty.f32());
+ auto* v8 = b.FunctionParam("v8", ty.f32());
+ auto* v9 = b.FunctionParam("v9", ty.f32());
+ auto* v10 = b.FunctionParam("v10", ty.f32());
+ auto* v11 = b.FunctionParam("v11", ty.f32());
+ auto* v12 = b.FunctionParam("v12", ty.f32());
+ auto* v13 = b.FunctionParam("v13", ty.f32());
+ auto* v14 = b.FunctionParam("v14", ty.f32());
+ auto* v15 = b.FunctionParam("v15", ty.f32());
+ auto* v16 = b.FunctionParam("v16", ty.f32());
+ auto* func = b.Function("foo", mat);
+ func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16});
+ b.Append(func->Block(), [&] {
+ auto* construct =
+ b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32, %v9:f32, %v10:f32, %v11:f32, %v12:f32, %v13:f32, %v14:f32, %v15:f32, %v16:f32):mat4x4<f32> -> %b1 {
+ %b1 = block {
+ %18:mat4x4<f32> = construct %v1, %v2, %v3, %v4, %v5, %v6, %v7, %v8, %v9, %v10, %v11, %v12, %v13, %v14, %v15, %v16
+ ret %18
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%v1:f32, %v2:f32, %v3:f32, %v4:f32, %v5:f32, %v6:f32, %v7:f32, %v8:f32, %v9:f32, %v10:f32, %v11:f32, %v12:f32, %v13:f32, %v14:f32, %v15:f32, %v16:f32):mat4x4<f32> -> %b1 {
+ %b1 = block {
+ %18:vec4<f32> = construct %v1, %v2, %v3, %v4
+ %19:vec4<f32> = construct %v5, %v6, %v7, %v8
+ %20:vec4<f32> = construct %v9, %v10, %v11, %v12
+ %21:vec4<f32> = construct %v13, %v14, %v15, %v16
+ %22:mat4x4<f32> = construct %18, %19, %20, %21
+ ret %22
+ }
+}
+)";
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_VectorizeScalarMatrixConstructorsTest, Mat3x3_F16) {
+ auto* mat = ty.mat3x3<f16>();
+ auto* v1 = b.FunctionParam("v1", ty.f16());
+ auto* v2 = b.FunctionParam("v2", ty.f16());
+ auto* v3 = b.FunctionParam("v3", ty.f16());
+ auto* v4 = b.FunctionParam("v4", ty.f16());
+ auto* v5 = b.FunctionParam("v5", ty.f16());
+ auto* v6 = b.FunctionParam("v6", ty.f16());
+ auto* v7 = b.FunctionParam("v7", ty.f16());
+ auto* v8 = b.FunctionParam("v8", ty.f16());
+ auto* v9 = b.FunctionParam("v9", ty.f16());
+ auto* func = b.Function("foo", mat);
+ func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8, v9});
+ b.Append(func->Block(), [&] {
+ auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8, v9);
+ b.Return(func, construct->Result());
+ });
+
+ auto* src = R"(
+%foo = func(%v1:f16, %v2:f16, %v3:f16, %v4:f16, %v5:f16, %v6:f16, %v7:f16, %v8:f16, %v9:f16):mat3x3<f16> -> %b1 {
+ %b1 = block {
+ %11:mat3x3<f16> = construct %v1, %v2, %v3, %v4, %v5, %v6, %v7, %v8, %v9
+ ret %11
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%v1:f16, %v2:f16, %v3:f16, %v4:f16, %v5:f16, %v6:f16, %v7:f16, %v8:f16, %v9:f16):mat3x3<f16> -> %b1 {
+ %b1 = block {
+ %11:vec3<f16> = construct %v1, %v2, %v3
+ %12:vec3<f16> = construct %v4, %v5, %v6
+ %13:vec3<f16> = construct %v7, %v8, %v9
+ %14:mat3x3<f16> = construct %11, %12, %13
+ ret %14
+ }
+}
+)";
+
+ Run(VectorizeScalarMatrixConstructors);
+
+ EXPECT_EQ(expect, str());
+}
+
+} // namespace
+} // namespace tint::core::ir::transform
diff --git a/src/tint/lang/spirv/writer/raise/raise.cc b/src/tint/lang/spirv/writer/raise/raise.cc
index 5c6a9d7..a5b0bc4 100644
--- a/src/tint/lang/spirv/writer/raise/raise.cc
+++ b/src/tint/lang/spirv/writer/raise/raise.cc
@@ -43,6 +43,7 @@
#include "src/tint/lang/core/ir/transform/preserve_padding.h"
#include "src/tint/lang/core/ir/transform/robustness.h"
#include "src/tint/lang/core/ir/transform/std140.h"
+#include "src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.h"
#include "src/tint/lang/core/ir/transform/zero_init_workgroup_memory.h"
#include "src/tint/lang/spirv/writer/common/option_builder.h"
#include "src/tint/lang/spirv/writer/raise/builtin_polyfill.h"
@@ -125,6 +126,7 @@
RUN_TRANSFORM(core::ir::transform::AddEmptyEntryPoint, module);
RUN_TRANSFORM(core::ir::transform::Bgra8UnormPolyfill, module);
RUN_TRANSFORM(core::ir::transform::BlockDecoratedStructs, module);
+ RUN_TRANSFORM(core::ir::transform::VectorizeScalarMatrixConstructors, module);
// CombineAccessInstructions must come after DirectVariableAccess and BlockDecoratedStructs.
// We run this transform as some Qualcomm drivers struggle with partial access chains that