| // Copyright 2025 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/spirv/reader/lower/decompose_strided_matrix.h" |
| |
| #include "src/tint/lang/core/ir/transform/helper_test.h" |
| #include "src/tint/lang/spirv/type/explicit_layout_array.h" |
| |
| namespace tint::spirv::reader::lower { |
| namespace { |
| |
| using namespace tint::core::fluent_types; // NOLINT |
| using namespace tint::core::number_suffixes; // NOLINT |
| |
| class SpirvReader_DecomposeStridedMatrixTest : public core::ir::transform::TransformTest { |
| protected: |
| void SetUp() override { capabilities.Add(core::ir::Capability::kAllowNonCoreTypes); } |
| |
| /// Create a struct that has a matrix member sandwiched between two u32 members, optionally |
| /// nested inside one or more arrays. |
| const core::type::Struct* Struct(const core::type::Matrix* matrix_type, |
| uint32_t matrix_stride, |
| std::initializer_list<uint32_t> array_counts = {}) { |
| uint32_t member_size = matrix_stride * matrix_type->Columns(); |
| const core::type::Type* member_type = matrix_type; |
| for (uint32_t count : array_counts) { |
| member_type = ty.array(member_type, count); |
| member_size *= count; |
| } |
| auto* matrix_member = |
| ty.Get<core::type::StructMember>(mod.symbols.New("b"), member_type, 1u, matrix_stride, |
| matrix_stride, member_size, core::IOAttributes{}); |
| matrix_member->SetMatrixStride(matrix_stride); |
| return ty.Struct(mod.symbols.New("S"), |
| Vector{ |
| ty.Get<core::type::StructMember>(mod.symbols.New("a"), ty.u32(), 0u, |
| 0u, 4u, 4u, core::IOAttributes{}), |
| matrix_member, |
| ty.Get<core::type::StructMember>(mod.symbols.New("c"), ty.u32(), 2u, |
| matrix_member->Offset() + member_size, |
| 4u, 4u, core::IOAttributes{}), |
| }); |
| } |
| }; |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, NaturalStride_CreateConstant) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 16); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Let("value", b.Composite(struct_type, 42_u, b.Zero(matrix_type), 42_u)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16), @matrix_stride(16) |
| c:u32 @offset(80) |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B1: { |
| %value:S = let S(42u, mat4x4<f32>(vec4<f32>(0.0f)), 42u) |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16), @matrix_stride(16) |
| c:u32 @offset(80) |
| } |
| |
| S_1 = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16) |
| c:u32 @offset(80) |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B1: { |
| %value:S_1 = let S_1(42u, mat4x4<f32>(vec4<f32>(0.0f)), 42u) |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, NaturalStride_LoadMatrix) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 16); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Let("value", b.Load(b.Access<ptr<private_, mat4x4<f32>>>(var, 1_u))); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16), @matrix_stride(16) |
| c:u32 @offset(80) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, mat4x4<f32>, read_write> = access %var, 1u |
| %4:mat4x4<f32> = load %3 |
| %value:mat4x4<f32> = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16), @matrix_stride(16) |
| c:u32 @offset(80) |
| } |
| |
| S_1 = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16) |
| c:u32 @offset(80) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, mat4x4<f32>, read_write> = access %var, 1u |
| %4:mat4x4<f32> = load %3 |
| %value:mat4x4<f32> = let %4 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, NaturalStride_ExtractMatrix) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 16); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| auto* s = b.Let("s", b.Zero(struct_type)); |
| b.Let("value", b.Access<mat4x4<f32>>(s, 1_u)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16), @matrix_stride(16) |
| c:u32 @offset(80) |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B1: { |
| %s:S = let S(0u, mat4x4<f32>(vec4<f32>(0.0f)), 0u) |
| %3:mat4x4<f32> = access %s, 1u |
| %value:mat4x4<f32> = let %3 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16), @matrix_stride(16) |
| c:u32 @offset(80) |
| } |
| |
| S_1 = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16) |
| c:u32 @offset(80) |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B1: { |
| %s:S_1 = let S_1(0u, mat4x4<f32>(vec4<f32>(0.0f)), 0u) |
| %3:mat4x4<f32> = access %s, 1u |
| %value:mat4x4<f32> = let %3 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, NaturalStride_Construct) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 16); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| auto* m = b.Let("m", b.Zero(matrix_type)); |
| b.Let("value", b.Construct(struct_type, 42_u, m, 42_u)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16), @matrix_stride(16) |
| c:u32 @offset(80) |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B1: { |
| %m:mat4x4<f32> = let mat4x4<f32>(vec4<f32>(0.0f)) |
| %3:S = construct 42u, %m, 42u |
| %value:S = let %3 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16), @matrix_stride(16) |
| c:u32 @offset(80) |
| } |
| |
| S_1 = struct @align(16) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(16) |
| c:u32 @offset(80) |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B1: { |
| %m:mat4x4<f32> = let mat4x4<f32>(vec4<f32>(0.0f)) |
| %3:S_1 = construct 42u, %m, 42u |
| %value:S_1 = let %3 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, LoadMatrixElement) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| auto* access = b.Access<ptr<private_, vec4<f32>>>(var, 1_u, 3_u); |
| b.Let("value", b.LoadVectorElement(access, 2_u)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, vec4<f32>, read_write> = access %var, 1u, 3u |
| %4:f32 = load_vector_element %3, 2u |
| %value:f32 = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, vec4<f32>, read_write> = access %var, 1u, 3u |
| %4:f32 = load_vector_element %3, 2u |
| %value:f32 = let %4 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, LoadMatrixColumn) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Let("value", b.Load(b.Access<ptr<private_, vec4<f32>>>(var, 1_u, 2_u))); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, vec4<f32>, read_write> = access %var, 1u, 2u |
| %4:vec4<f32> = load %3 |
| %value:vec4<f32> = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, vec4<f32>, read_write> = access %var, 1u, 2u |
| %4:vec4<f32> = load %3 |
| %value:vec4<f32> = let %4 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, LoadMatrix) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Let("value", b.Load(b.Access<ptr<private_, mat4x4<f32>>>(var, 1_u))); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, mat4x4<f32>, read_write> = access %var, 1u |
| %4:mat4x4<f32> = load %3 |
| %value:mat4x4<f32> = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, read_write> = access %var, 1u |
| %4:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = load %3 |
| %5:vec4<f32> = access %4, 0u |
| %6:vec4<f32> = access %4, 1u |
| %7:vec4<f32> = access %4, 2u |
| %8:vec4<f32> = access %4, 3u |
| %9:mat4x4<f32> = construct %5, %6, %7, %8 |
| %value:mat4x4<f32> = let %9 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, LoadMatrix_ViaLet) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| auto* let = b.Let("ptr", b.Access<ptr<private_, mat4x4<f32>>>(var, 1_u)); |
| b.Let("value", b.Load(let)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, mat4x4<f32>, read_write> = access %var, 1u |
| %ptr:ptr<private, mat4x4<f32>, read_write> = let %3 |
| %5:mat4x4<f32> = load %ptr |
| %value:mat4x4<f32> = let %5 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, read_write> = access %var, 1u |
| %ptr:ptr<private, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, read_write> = let %3 |
| %5:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = load %ptr |
| %6:vec4<f32> = access %5, 0u |
| %7:vec4<f32> = access %5, 1u |
| %8:vec4<f32> = access %5, 2u |
| %9:vec4<f32> = access %5, 3u |
| %10:mat4x4<f32> = construct %6, %7, %8, %9 |
| %value:mat4x4<f32> = let %10 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, LoadStruct) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Let("value", b.Load(var)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:S = load %var |
| %value:S = let %3 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:S_1 = load %var |
| %value:S_1 = let %3 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, LoadStruct_ViaLet) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| auto* let = b.Let("ptr", var); |
| b.Let("value", b.Load(let)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %ptr:ptr<private, S, read_write> = let %var |
| %4:S = load %ptr |
| %value:S = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %ptr:ptr<private, S_1, read_write> = let %var |
| %4:S_1 = load %ptr |
| %value:S_1 = let %4 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, LoadStruct_ExtractMatrix) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| auto* struct_value = b.Let("struct_value", b.Load(var)); |
| b.Let("matrix_value", b.Access(matrix_type, struct_value, 1_u)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:S = load %var |
| %struct_value:S = let %3 |
| %5:mat4x4<f32> = access %struct_value, 1u |
| %matrix_value:mat4x4<f32> = let %5 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:S_1 = load %var |
| %struct_value:S_1 = let %3 |
| %5:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %struct_value, 1u |
| %6:vec4<f32> = access %5, 0u |
| %7:vec4<f32> = access %5, 1u |
| %8:vec4<f32> = access %5, 2u |
| %9:vec4<f32> = access %5, 3u |
| %10:mat4x4<f32> = construct %6, %7, %8, %9 |
| %matrix_value:mat4x4<f32> = let %10 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, StoreMatrixElement) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| auto* access = b.Access<ptr<private_, vec4<f32>>>(var, 1_u, 3_u); |
| b.StoreVectorElement(access, 2_u, 42_f); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, vec4<f32>, read_write> = access %var, 1u, 3u |
| store_vector_element %3, 2u, 42.0f |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, vec4<f32>, read_write> = access %var, 1u, 3u |
| store_vector_element %3, 2u, 42.0f |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, StoreMatrixColumn) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Store(b.Access<ptr<private_, vec4<f32>>>(var, 1_u, 2_u), b.Zero<vec4<f32>>()); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, vec4<f32>, read_write> = access %var, 1u, 2u |
| store %3, vec4<f32>(0.0f) |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, vec4<f32>, read_write> = access %var, 1u, 2u |
| store %3, vec4<f32>(0.0f) |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, StoreMatrix) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Store(b.Access<ptr<private_, mat4x4<f32>>>(var, 1_u), b.Zero<mat4x4<f32>>()); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, mat4x4<f32>, read_write> = access %var, 1u |
| store %3, mat4x4<f32>(vec4<f32>(0.0f)) |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, read_write> = access %var, 1u |
| %4:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f) |
| store %3, %4 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, StoreStruct) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Store(var, b.Zero(struct_type)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| store %var, S(0u, mat4x4<f32>(vec4<f32>(0.0f)), 0u) |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| store %var, S_1(0u, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>(vec4<f32>(0.0f)), 0u) |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, LoadMatrixFromFuncParam) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* foo = b.Function("foo", ty.void_()); |
| auto* param = b.FunctionParam("param", ty.ptr(function, struct_type)); |
| foo->SetParams({param}); |
| b.Append(foo->Block(), [&] { |
| b.Let("value", b.Load(b.Access<ptr<function, mat4x4<f32>>>(param, 1_u))); |
| b.Return(foo); |
| }); |
| |
| auto* bar = b.Function("bar", ty.void_()); |
| b.Append(bar->Block(), [&] { |
| auto* var = b.Var("var", ty.ptr(function, struct_type)); |
| b.Call(foo, var); |
| b.Return(bar); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| %foo = func(%param:ptr<function, S, read_write>):void { |
| $B1: { |
| %3:ptr<function, mat4x4<f32>, read_write> = access %param, 1u |
| %4:mat4x4<f32> = load %3 |
| %value:mat4x4<f32> = let %4 |
| ret |
| } |
| } |
| %bar = func():void { |
| $B2: { |
| %var:ptr<function, S, read_write> = var undef |
| %8:void = call %foo, %var |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| %foo = func(%param:ptr<function, S_1, read_write>):void { |
| $B1: { |
| %3:ptr<function, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, read_write> = access %param, 1u |
| %4:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = load %3 |
| %5:vec4<f32> = access %4, 0u |
| %6:vec4<f32> = access %4, 1u |
| %7:vec4<f32> = access %4, 2u |
| %8:vec4<f32> = access %4, 3u |
| %9:mat4x4<f32> = construct %5, %6, %7, %8 |
| %value:mat4x4<f32> = let %9 |
| ret |
| } |
| } |
| %bar = func():void { |
| $B2: { |
| %var:ptr<function, S_1, read_write> = var undef |
| %13:void = call %foo, %var |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, ReturnStructFromFunction) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* f = b.Function("foo", struct_type); |
| b.Append(f->Block(), [&] { |
| auto* var = b.Var("var", ty.ptr(function, struct_type)); |
| b.Return(f, b.Load(var)); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| %foo = func():S { |
| $B1: { |
| %var:ptr<function, S, read_write> = var undef |
| %3:S = load %var |
| ret %3 |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| %foo = func():S_1 { |
| $B1: { |
| %var:ptr<function, S_1, read_write> = var undef |
| %3:S_1 = load %var |
| ret %3 |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, LoadMatrix_StructNestedInArray) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| auto* array_type = ty.array(struct_type, 4); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(array_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Let("value", b.Load(b.Access<ptr<private_, mat4x4<f32>>>(var, 2_u, 1_u))); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, array<S, 4>, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, mat4x4<f32>, read_write> = access %var, 2u, 1u |
| %4:mat4x4<f32> = load %3 |
| %value:mat4x4<f32> = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, array<S_1, 4>, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, read_write> = access %var, 2u, 1u |
| %4:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = load %3 |
| %5:vec4<f32> = access %4, 0u |
| %6:vec4<f32> = access %4, 1u |
| %7:vec4<f32> = access %4, 2u |
| %8:vec4<f32> = access %4, 3u |
| %9:mat4x4<f32> = construct %5, %6, %7, %8 |
| %value:mat4x4<f32> = let %9 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, LoadMatrix_StructNestedInStridedArray) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| auto* strided_array = ty.Get<spirv::type::ExplicitLayoutArray>( |
| struct_type, ty.Get<core::type::ConstantArrayCount>(4u), 1024u, 256u); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(strided_array)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Let("value", b.Load(b.Access<ptr<private_, mat4x4<f32>>>(var, 2_u, 1_u))); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, spirv.explicit_layout_array<S, 4, stride=256>, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, mat4x4<f32>, read_write> = access %var, 2u, 1u |
| %4:mat4x4<f32> = load %3 |
| %value:mat4x4<f32> = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, spirv.explicit_layout_array<S_1, 4, stride=256>, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, read_write> = access %var, 2u, 1u |
| %4:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = load %3 |
| %5:vec4<f32> = access %4, 0u |
| %6:vec4<f32> = access %4, 1u |
| %7:vec4<f32> = access %4, 2u |
| %8:vec4<f32> = access %4, 3u |
| %9:mat4x4<f32> = construct %5, %6, %7, %8 |
| %value:mat4x4<f32> = let %9 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, LoadMatrix_StructNestedInStruct) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* inner_struct_type = Struct(matrix_type, 64); |
| auto* outer_struct_type = |
| ty.Struct(mod.symbols.New("Outer"), { |
| {mod.symbols.New("a"), ty.u32()}, |
| {mod.symbols.New("b"), inner_struct_type}, |
| }); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(outer_struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Let("value", b.Load(b.Access<ptr<private_, mat4x4<f32>>>(var, 1_u, 1_u))); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| Outer = struct @align(64) { |
| a_1:u32 @offset(0) |
| b_1:S @offset(64) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, Outer, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, mat4x4<f32>, read_write> = access %var, 1u, 1u |
| %4:mat4x4<f32> = load %3 |
| %value:mat4x4<f32> = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| Outer = struct @align(64) { |
| a_1:u32 @offset(0) |
| b_1:S @offset(64) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| Outer_1 = struct @align(64) { |
| a_1:u32 @offset(0) |
| b_1:S_1 @offset(64) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, Outer_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, read_write> = access %var, 1u, 1u |
| %4:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = load %3 |
| %5:vec4<f32> = access %4, 0u |
| %6:vec4<f32> = access %4, 1u |
| %7:vec4<f32> = access %4, 2u |
| %8:vec4<f32> = access %4, 3u |
| %9:mat4x4<f32> = construct %5, %6, %7, %8 |
| %value:mat4x4<f32> = let %9 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, ConstructAndAccess) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64); |
| |
| auto* f = b.Function("foo", matrix_type); |
| auto* p0 = b.FunctionParam("p0", ty.u32()); |
| auto* p1 = b.FunctionParam("p1", matrix_type); |
| auto* p2 = b.FunctionParam("p2", ty.u32()); |
| f->SetParams({p0, p1, p2}); |
| |
| b.Append(f->Block(), [&] { |
| auto* c = b.Construct(struct_type, p0, p1, p2); |
| auto* a = b.Access(matrix_type, c, 1_u); |
| b.Return(f, a); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| %foo = func(%p0:u32, %p1:mat4x4<f32>, %p2:u32):mat4x4<f32> { |
| $B1: { |
| %5:S = construct %p0, %p1, %p2 |
| %6:mat4x4<f32> = access %5, 1u |
| ret %6 |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| %foo = func(%p0:u32, %p1:mat4x4<f32>, %p2:u32):mat4x4<f32> { |
| $B1: { |
| %5:vec4<f32> = access %p1, 0u |
| %6:vec4<f32> = access %p1, 1u |
| %7:vec4<f32> = access %p1, 2u |
| %8:vec4<f32> = access %p1, 3u |
| %9:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct %5, %6, %7, %8 |
| %10:S_1 = construct %p0, %9, %p2 |
| %11:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %10, 1u |
| %12:vec4<f32> = access %11, 0u |
| %13:vec4<f32> = access %11, 1u |
| %14:vec4<f32> = access %11, 2u |
| %15:vec4<f32> = access %11, 3u |
| %16:mat4x4<f32> = construct %12, %13, %14, %15 |
| ret %16 |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, ExistingStridedArray) { |
| auto* strided_array = ty.Get<spirv::type::ExplicitLayoutArray>( |
| ty.vec4f(), ty.Get<core::type::ConstantArrayCount>(4u), 64u, 16u); |
| auto* struct_ty = |
| ty.Struct(mod.symbols.New("MyStruct"), { |
| {mod.symbols.New("a"), ty.u32()}, |
| {mod.symbols.New("b"), strided_array}, |
| }); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_ty)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| auto* array_ptr = b.Access(ty.ptr(private_, strided_array), var, 1_u); |
| b.Let("value", b.Load(array_ptr)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| MyStruct = struct @align(16) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=16> @offset(16) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, MyStruct, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, spirv.explicit_layout_array<vec4<f32>, 4, stride=16>, read_write> = access %var, 1u |
| %4:spirv.explicit_layout_array<vec4<f32>, 4, stride=16> = load %3 |
| %value:spirv.explicit_layout_array<vec4<f32>, 4, stride=16> = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = before; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, ArrayOfStridedMatrix_LoadMatrix) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64, {2, 3}); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Let("value", b.Load(b.Access<ptr<private_, mat4x4<f32>>>(var, 1_u, 2_u, 1_u))); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, mat4x4<f32>, read_write> = access %var, 1u, 2u, 1u |
| %4:mat4x4<f32> = load %3 |
| %value:mat4x4<f32> = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3> @offset(64) @size(1536) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, read_write> = access %var, 1u, 2u, 1u |
| %4:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = load %3 |
| %5:vec4<f32> = access %4, 0u |
| %6:vec4<f32> = access %4, 1u |
| %7:vec4<f32> = access %4, 2u |
| %8:vec4<f32> = access %4, 3u |
| %9:mat4x4<f32> = construct %5, %6, %7, %8 |
| %value:mat4x4<f32> = let %9 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, ArrayOfStridedMatrix_LoadArray) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64, {2, 3}); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Let("value", b.Load(b.Access<ptr<private_, array<array<mat4x4<f32>, 2>, 3>>>(var, 1_u))); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, array<array<mat4x4<f32>, 2>, 3>, read_write> = access %var, 1u |
| %4:array<array<mat4x4<f32>, 2>, 3> = load %3 |
| %value:array<array<mat4x4<f32>, 2>, 3> = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3> @offset(64) @size(1536) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3>, read_write> = access %var, 1u |
| %4:array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3> = load %3 |
| %5:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = access %4, 0u |
| %6:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %5, 0u |
| %7:vec4<f32> = access %6, 0u |
| %8:vec4<f32> = access %6, 1u |
| %9:vec4<f32> = access %6, 2u |
| %10:vec4<f32> = access %6, 3u |
| %11:mat4x4<f32> = construct %7, %8, %9, %10 |
| %12:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %5, 1u |
| %13:vec4<f32> = access %12, 0u |
| %14:vec4<f32> = access %12, 1u |
| %15:vec4<f32> = access %12, 2u |
| %16:vec4<f32> = access %12, 3u |
| %17:mat4x4<f32> = construct %13, %14, %15, %16 |
| %18:array<mat4x4<f32>, 2> = construct %11, %17 |
| %19:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = access %4, 1u |
| %20:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %19, 0u |
| %21:vec4<f32> = access %20, 0u |
| %22:vec4<f32> = access %20, 1u |
| %23:vec4<f32> = access %20, 2u |
| %24:vec4<f32> = access %20, 3u |
| %25:mat4x4<f32> = construct %21, %22, %23, %24 |
| %26:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %19, 1u |
| %27:vec4<f32> = access %26, 0u |
| %28:vec4<f32> = access %26, 1u |
| %29:vec4<f32> = access %26, 2u |
| %30:vec4<f32> = access %26, 3u |
| %31:mat4x4<f32> = construct %27, %28, %29, %30 |
| %32:array<mat4x4<f32>, 2> = construct %25, %31 |
| %33:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = access %4, 2u |
| %34:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %33, 0u |
| %35:vec4<f32> = access %34, 0u |
| %36:vec4<f32> = access %34, 1u |
| %37:vec4<f32> = access %34, 2u |
| %38:vec4<f32> = access %34, 3u |
| %39:mat4x4<f32> = construct %35, %36, %37, %38 |
| %40:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %33, 1u |
| %41:vec4<f32> = access %40, 0u |
| %42:vec4<f32> = access %40, 1u |
| %43:vec4<f32> = access %40, 2u |
| %44:vec4<f32> = access %40, 3u |
| %45:mat4x4<f32> = construct %41, %42, %43, %44 |
| %46:array<mat4x4<f32>, 2> = construct %39, %45 |
| %47:array<array<mat4x4<f32>, 2>, 3> = construct %18, %32, %46 |
| %value:array<array<mat4x4<f32>, 2>, 3> = let %47 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, ArrayOfStridedMatrix_StoreMatrix) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64, {2, 3}); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Store(b.Access<ptr<private_, mat4x4<f32>>>(var, 1_u, 2_u, 1_u), b.Zero<mat4x4<f32>>()); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, mat4x4<f32>, read_write> = access %var, 1u, 2u, 1u |
| store %3, mat4x4<f32>(vec4<f32>(0.0f)) |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3> @offset(64) @size(1536) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, read_write> = access %var, 1u, 2u, 1u |
| %4:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f) |
| store %3, %4 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, ArrayOfStridedMatrix_StoreArray) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64, {2, 3}); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Store(b.Access<ptr<private_, array<array<mat4x4<f32>, 2>, 3>>>(var, 1_u), |
| b.Zero<array<array<mat4x4<f32>, 2>, 3>>()); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, array<array<mat4x4<f32>, 2>, 3>, read_write> = access %var, 1u |
| store %3, array<array<mat4x4<f32>, 2>, 3>(array<mat4x4<f32>, 2>(mat4x4<f32>(vec4<f32>(0.0f)))) |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3> @offset(64) @size(1536) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3>, read_write> = access %var, 1u |
| %4:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f) |
| %5:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f) |
| %6:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = construct %4, %5 |
| %7:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f) |
| %8:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f) |
| %9:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = construct %7, %8 |
| %10:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f) |
| %11:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f), vec4<f32>(0.0f) |
| %12:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = construct %10, %11 |
| %13:array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3> = construct %6, %9, %12 |
| store %3, %13 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, ArrayOfStridedMatrix_StoreStruct) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64, {2, 3}); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| b.Store(var, b.Zero(struct_type)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| store %var, S(0u, array<array<mat4x4<f32>, 2>, 3>(array<mat4x4<f32>, 2>(mat4x4<f32>(vec4<f32>(0.0f)))), 0u) |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3> @offset(64) @size(1536) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| store %var, S_1(0u, array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3>(array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>(spirv.explicit_layout_array<vec4<f32>, 4, stride=64>(vec4<f32>(0.0f)))), 0u) |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, ArrayOfStridedMatrix_ConstructAndAccess) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* array_type = ty.array(ty.array(matrix_type, 2), 3); |
| auto* struct_type = Struct(matrix_type, 64, {2, 3}); |
| |
| auto* f = b.Function("foo", array_type); |
| auto* p0 = b.FunctionParam("p0", ty.u32()); |
| auto* p1 = b.FunctionParam("p1", array_type); |
| auto* p2 = b.FunctionParam("p2", ty.u32()); |
| f->SetParams({p0, p1, p2}); |
| |
| b.Append(f->Block(), [&] { |
| auto* c = b.Construct(struct_type, p0, p1, p2); |
| auto* a = b.Access(array_type, c, 1_u); |
| b.Return(f, a); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| %foo = func(%p0:u32, %p1:array<array<mat4x4<f32>, 2>, 3>, %p2:u32):array<array<mat4x4<f32>, 2>, 3> { |
| $B1: { |
| %5:S = construct %p0, %p1, %p2 |
| %6:array<array<mat4x4<f32>, 2>, 3> = access %5, 1u |
| ret %6 |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3> @offset(64) @size(1536) |
| c:u32 @offset(1600) |
| } |
| |
| %foo = func(%p0:u32, %p1:array<array<mat4x4<f32>, 2>, 3>, %p2:u32):array<array<mat4x4<f32>, 2>, 3> { |
| $B1: { |
| %5:array<mat4x4<f32>, 2> = access %p1, 0u |
| %6:mat4x4<f32> = access %5, 0u |
| %7:vec4<f32> = access %6, 0u |
| %8:vec4<f32> = access %6, 1u |
| %9:vec4<f32> = access %6, 2u |
| %10:vec4<f32> = access %6, 3u |
| %11:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct %7, %8, %9, %10 |
| %12:mat4x4<f32> = access %5, 1u |
| %13:vec4<f32> = access %12, 0u |
| %14:vec4<f32> = access %12, 1u |
| %15:vec4<f32> = access %12, 2u |
| %16:vec4<f32> = access %12, 3u |
| %17:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct %13, %14, %15, %16 |
| %18:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = construct %11, %17 |
| %19:array<mat4x4<f32>, 2> = access %p1, 1u |
| %20:mat4x4<f32> = access %19, 0u |
| %21:vec4<f32> = access %20, 0u |
| %22:vec4<f32> = access %20, 1u |
| %23:vec4<f32> = access %20, 2u |
| %24:vec4<f32> = access %20, 3u |
| %25:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct %21, %22, %23, %24 |
| %26:mat4x4<f32> = access %19, 1u |
| %27:vec4<f32> = access %26, 0u |
| %28:vec4<f32> = access %26, 1u |
| %29:vec4<f32> = access %26, 2u |
| %30:vec4<f32> = access %26, 3u |
| %31:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct %27, %28, %29, %30 |
| %32:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = construct %25, %31 |
| %33:array<mat4x4<f32>, 2> = access %p1, 2u |
| %34:mat4x4<f32> = access %33, 0u |
| %35:vec4<f32> = access %34, 0u |
| %36:vec4<f32> = access %34, 1u |
| %37:vec4<f32> = access %34, 2u |
| %38:vec4<f32> = access %34, 3u |
| %39:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct %35, %36, %37, %38 |
| %40:mat4x4<f32> = access %33, 1u |
| %41:vec4<f32> = access %40, 0u |
| %42:vec4<f32> = access %40, 1u |
| %43:vec4<f32> = access %40, 2u |
| %44:vec4<f32> = access %40, 3u |
| %45:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = construct %41, %42, %43, %44 |
| %46:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = construct %39, %45 |
| %47:array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3> = construct %18, %32, %46 |
| %48:S_1 = construct %p0, %47, %p2 |
| %49:array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3> = access %48, 1u |
| %50:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = access %49, 0u |
| %51:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %50, 0u |
| %52:vec4<f32> = access %51, 0u |
| %53:vec4<f32> = access %51, 1u |
| %54:vec4<f32> = access %51, 2u |
| %55:vec4<f32> = access %51, 3u |
| %56:mat4x4<f32> = construct %52, %53, %54, %55 |
| %57:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %50, 1u |
| %58:vec4<f32> = access %57, 0u |
| %59:vec4<f32> = access %57, 1u |
| %60:vec4<f32> = access %57, 2u |
| %61:vec4<f32> = access %57, 3u |
| %62:mat4x4<f32> = construct %58, %59, %60, %61 |
| %63:array<mat4x4<f32>, 2> = construct %56, %62 |
| %64:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = access %49, 1u |
| %65:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %64, 0u |
| %66:vec4<f32> = access %65, 0u |
| %67:vec4<f32> = access %65, 1u |
| %68:vec4<f32> = access %65, 2u |
| %69:vec4<f32> = access %65, 3u |
| %70:mat4x4<f32> = construct %66, %67, %68, %69 |
| %71:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %64, 1u |
| %72:vec4<f32> = access %71, 0u |
| %73:vec4<f32> = access %71, 1u |
| %74:vec4<f32> = access %71, 2u |
| %75:vec4<f32> = access %71, 3u |
| %76:mat4x4<f32> = construct %72, %73, %74, %75 |
| %77:array<mat4x4<f32>, 2> = construct %70, %76 |
| %78:array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2> = access %49, 2u |
| %79:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %78, 0u |
| %80:vec4<f32> = access %79, 0u |
| %81:vec4<f32> = access %79, 1u |
| %82:vec4<f32> = access %79, 2u |
| %83:vec4<f32> = access %79, 3u |
| %84:mat4x4<f32> = construct %80, %81, %82, %83 |
| %85:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = access %78, 1u |
| %86:vec4<f32> = access %85, 0u |
| %87:vec4<f32> = access %85, 1u |
| %88:vec4<f32> = access %85, 2u |
| %89:vec4<f32> = access %85, 3u |
| %90:mat4x4<f32> = construct %86, %87, %88, %89 |
| %91:array<mat4x4<f32>, 2> = construct %84, %90 |
| %92:array<array<mat4x4<f32>, 2>, 3> = construct %63, %77, %91 |
| ret %92 |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, ArrayOfStridedMatrix_LoadMatrix_AccessChain) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* struct_type = Struct(matrix_type, 64, {2, 3}); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| auto* outer_array_ptr = |
| b.Access(ty.ptr(private_, ty.array(ty.array(matrix_type, 2), 3)), var, 1_u); |
| auto* inner_array_ptr = |
| b.Access(ty.ptr(private_, ty.array(matrix_type, 2)), outer_array_ptr, 2_u); |
| auto* matrix_ptr = b.Access(ty.ptr(private_, matrix_type), inner_array_ptr, 1_u); |
| b.Let("value", b.Load(matrix_ptr)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, array<array<mat4x4<f32>, 2>, 3>, read_write> = access %var, 1u |
| %4:ptr<private, array<mat4x4<f32>, 2>, read_write> = access %3, 2u |
| %5:ptr<private, mat4x4<f32>, read_write> = access %4, 1u |
| %6:mat4x4<f32> = load %5 |
| %value:mat4x4<f32> = let %6 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<mat4x4<f32>, 2>, 3> @offset(64) @size(1536), @matrix_stride(64) |
| c:u32 @offset(1600) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3> @offset(64) @size(1536) |
| c:u32 @offset(1600) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, S_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, array<array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, 3>, read_write> = access %var, 1u |
| %4:ptr<private, array<spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, 2>, read_write> = access %3, 2u |
| %5:ptr<private, spirv.explicit_layout_array<vec4<f32>, 4, stride=64>, read_write> = access %4, 1u |
| %6:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> = load %5 |
| %7:vec4<f32> = access %6, 0u |
| %8:vec4<f32> = access %6, 1u |
| %9:vec4<f32> = access %6, 2u |
| %10:vec4<f32> = access %6, 3u |
| %11:mat4x4<f32> = construct %7, %8, %9, %10 |
| %value:mat4x4<f32> = let %11 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, AccessNonMatrixPointer) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* inner_struct_type = Struct(matrix_type, 64); |
| auto* outer_struct_type = |
| ty.Struct(mod.symbols.New("Outer"), { |
| {mod.symbols.New("s"), inner_struct_type}, |
| }); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(outer_struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| auto* access = b.Access<ptr<private_, u32>>(var, 0_u, 2_u); |
| b.Let("value", b.Load(access)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| Outer = struct @align(64) { |
| s:S @offset(0) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, Outer, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, u32, read_write> = access %var, 0u, 2u |
| %4:u32 = load %3 |
| %value:u32 = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| Outer = struct @align(64) { |
| s:S @offset(0) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| Outer_1 = struct @align(64) { |
| s:S_1 @offset(0) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, Outer_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:ptr<private, u32, read_write> = access %var, 0u, 2u |
| %4:u32 = load %3 |
| %value:u32 = let %4 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| TEST_F(SpirvReader_DecomposeStridedMatrixTest, AccessNonMatrixValue) { |
| auto* matrix_type = ty.mat4x4<f32>(); |
| auto* inner_struct_type = Struct(matrix_type, 64); |
| auto* outer_struct_type = |
| ty.Struct(mod.symbols.New("Outer"), { |
| {mod.symbols.New("s"), inner_struct_type}, |
| }); |
| |
| auto* var = b.Var("var", ty.ptr<private_>(outer_struct_type)); |
| mod.root_block->Append(var); |
| |
| auto* f = b.ComputeFunction("foo"); |
| b.Append(f->Block(), [&] { |
| auto* struct_value = b.Load(var); |
| b.Let("value", b.Access<u32>(struct_value, 0_u, 2_u)); |
| b.Return(f); |
| }); |
| |
| auto* before = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| Outer = struct @align(64) { |
| s:S @offset(0) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, Outer, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:Outer = load %var |
| %4:u32 = access %3, 0u, 2u |
| %value:u32 = let %4 |
| ret |
| } |
| } |
| )"; |
| auto* after = R"( |
| S = struct @align(64) { |
| a:u32 @offset(0) |
| b:mat4x4<f32> @offset(64) @size(256), @matrix_stride(64) |
| c:u32 @offset(320) |
| } |
| |
| Outer = struct @align(64) { |
| s:S @offset(0) |
| } |
| |
| S_1 = struct @align(64) { |
| a:u32 @offset(0) |
| b:spirv.explicit_layout_array<vec4<f32>, 4, stride=64> @offset(64) |
| c:u32 @offset(320) |
| } |
| |
| Outer_1 = struct @align(64) { |
| s:S_1 @offset(0) |
| } |
| |
| $B1: { # root |
| %var:ptr<private, Outer_1, read_write> = var undef |
| } |
| |
| %foo = @compute @workgroup_size(1u, 1u, 1u) func():void { |
| $B2: { |
| %3:Outer_1 = load %var |
| %4:u32 = access %3, 0u, 2u |
| %value:u32 = let %4 |
| ret |
| } |
| } |
| )"; |
| |
| ASSERT_EQ(before, str()); |
| Run(DecomposeStridedMatrix); |
| ASSERT_EQ(after, str()); |
| } |
| |
| } // namespace |
| } // namespace tint::spirv::reader::lower |