// Copyright 2022 The Tint Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "src/tint/transform/std140.h" #include #include #include #include "src/tint/transform/test_helper.h" #include "src/tint/utils/string.h" namespace tint::transform { namespace { using Std140Test_F32 = TransformTest; TEST_F(Std140Test_F32, StructMatricesUniform) { auto* src = R"( struct S2x2F32 { m : mat2x2, } struct S3x2F32 { m : mat3x2, } struct S4x2F32 { m : mat4x2, } struct S2x3F32 { m : mat2x3, } struct S3x3F32 { m : mat3x3, } struct S4x3F32 { m : mat4x3, } struct S2x4F32 { m : mat2x4, } struct S3x4F32 { m : mat3x4, } struct S4x4F32 { m : mat4x4, } @group(2) @binding(2) var s2x2f32 : S2x2F32; @group(3) @binding(2) var s3x2f32 : S3x2F32; @group(4) @binding(2) var s4x2f32 : S4x2F32; @group(2) @binding(3) var s2x3f32 : S2x3F32; @group(3) @binding(3) var s3x3f32 : S3x3F32; @group(4) @binding(3) var s4x3f32 : S4x3F32; @group(2) @binding(4) var s2x4f32 : S2x4F32; @group(3) @binding(4) var s3x4f32 : S3x4F32; @group(4) @binding(4) var s4x4f32 : S4x4F32; )"; auto* expect = R"( struct S2x2F32 { m : mat2x2, } struct S2x2F32_std140 { m_0 : vec2, m_1 : vec2, } struct S3x2F32 { m : mat3x2, } struct S3x2F32_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, } struct S4x2F32 { m : mat4x2, } struct S4x2F32_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, m_3 : vec2, } struct S2x3F32 { m : mat2x3, } struct S3x3F32 { m : mat3x3, } struct S4x3F32 { m : mat4x3, } struct S2x4F32 { m : mat2x4, } struct S3x4F32 { m : mat3x4, } struct S4x4F32 { m : mat4x4, } @group(2) @binding(2) var s2x2f32 : S2x2F32_std140; @group(3) @binding(2) var s3x2f32 : S3x2F32_std140; @group(4) @binding(2) var s4x2f32 : S4x2F32_std140; @group(2) @binding(3) var s2x3f32 : S2x3F32; @group(3) @binding(3) var s3x3f32 : S3x3F32; @group(4) @binding(3) var s4x3f32 : S4x3F32; @group(2) @binding(4) var s2x4f32 : S2x4F32; @group(3) @binding(4) var s3x4f32 : S3x4F32; @group(4) @binding(4) var s4x4f32 : S4x4F32; )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } // In the following tests we only test `mat2x2` for matrix used as array element type and // `mat3x2` otherwise, and set all constant column index to 1, row index 0, inner array index // 2, and outer array index 3. For exhaustive tests, i.e. tests on all matrix shape and different // valid constant index, please refer to std140_exhaustive_test.cc TEST_F(Std140Test_F32, SingleStructMatUniform_Mat3x2F32) { auto* src = R"( struct S { m : mat3x2, } @group(0) @binding(0) var s : S; )"; auto* expect = R"( struct S { m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, } @group(0) @binding(0) var s : S_std140; )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, CustomAlign_Mat3x2F32) { auto* src = R"( struct S { before : i32, @align(128) m : mat3x2, after : i32, } @group(0) @binding(0) var s : S; )"; auto* expect = R"( struct S { before : i32, @align(128) m : mat3x2, after : i32, } struct S_std140 { before : i32, @align(128i) m_0 : vec2, m_1 : vec2, m_2 : vec2, after : i32, } @group(0) @binding(0) var s : S_std140; )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, CustomSizeMat_Mat3x2F32) { auto* src = R"( struct S { before : i32, @size(128) m : mat3x2, after : i32, } @group(0) @binding(0) var s : S; )"; auto* expect = R"( struct S { before : i32, @size(128) m : mat3x2, after : i32, } struct S_std140 { before : i32, m_0 : vec2, m_1 : vec2, @size(112) m_2 : vec2, after : i32, } @group(0) @binding(0) var s : S_std140; )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, CustomAlignAndSize_Mat3x2F32) { auto* src = R"( struct S { before : i32, @align(128) @size(128) m : mat3x2, after : i32, } @group(0) @binding(0) var s : S; )"; auto* expect = R"( struct S { before : i32, @align(128) @size(128) m : mat3x2, after : i32, } struct S_std140 { before : i32, @align(128i) m_0 : vec2, m_1 : vec2, @size(112) m_2 : vec2, after : i32, } @group(0) @binding(0) var s : S_std140; )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, MatrixUsageInForLoop_Mat3x2F32) { auto* src = R"( struct S { m : mat3x2, } @group(0) @binding(0) var s : S; fn f() { for(var i = u32(s.m[0][0]); (i < u32(s.m[i][1])); i += u32(s.m[1][i])) { } } )"; auto* expect = R"( struct S { m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, } @group(0) @binding(0) var s : S_std140; fn load_s_m_p0_1(p0 : u32) -> f32 { switch(p0) { case 0u: { return s.m_0[1u]; } case 1u: { return s.m_1[1u]; } case 2u: { return s.m_2[1u]; } default: { return f32(); } } } fn f() { for(var i = u32(s.m_0[0u]); (i < u32(load_s_m_p0_1(u32(i)))); i += u32(s.m_1[i])) { } } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, MatUniform_LoadMatrix_Mat3x2F32) { auto* src = R"( @group(0) @binding(0) var m : mat3x2; fn f() { let l = m; } )"; auto* expect = R"( struct mat3x2_f32 { col0 : vec2, col1 : vec2, col2 : vec2, } @group(0) @binding(0) var m : mat3x2_f32; fn conv_mat3x2_f32(val : mat3x2_f32) -> mat3x2 { return mat3x2(val.col0, val.col1, val.col2); } fn f() { let l = conv_mat3x2_f32(m); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, MatUniform_LoadColumn_ConstIndex_Mat3x2F32) { auto* src = R"( @group(0) @binding(0) var a : mat3x2; fn f() { let l = a[1]; } )"; auto* expect = R"( struct mat3x2_f32 { col0 : vec2, col1 : vec2, col2 : vec2, } @group(0) @binding(0) var a : mat3x2_f32; fn f() { let l = a.col1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, MatUniform_LoadColumn_VariableIndex_Mat3x2F32) { auto* src = R"( @group(0) @binding(0) var a : mat3x2; fn f() { let I = 1; let l = a[I]; } )"; auto* expect = R"( struct mat3x2_f32 { col0 : vec2, col1 : vec2, col2 : vec2, } @group(0) @binding(0) var a : mat3x2_f32; fn load_a_p0(p0 : u32) -> vec2 { switch(p0) { case 0u: { return a.col0; } case 1u: { return a.col1; } case 2u: { return a.col2; } default: { return vec2(); } } } fn f() { let I = 1; let l = load_a_p0(u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, MatUniform_LoadColumnSwizzle_ConstIndex_Mat3x2F32) { auto* src = R"( @group(0) @binding(0) var a : mat3x2; fn f() { let l = a[1].yx; } )"; auto* expect = R"( struct mat3x2_f32 { col0 : vec2, col1 : vec2, col2 : vec2, } @group(0) @binding(0) var a : mat3x2_f32; fn f() { let l = a.col1.yx; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, MatUniform_LoadColumnSwizzle_VariableIndex_Mat3x2F32) { auto* src = R"( @group(0) @binding(0) var a : mat3x2; fn f() { let I = 1; let l = a[I].yx; } )"; auto* expect = R"( struct mat3x2_f32 { col0 : vec2, col1 : vec2, col2 : vec2, } @group(0) @binding(0) var a : mat3x2_f32; fn load_a_p0_yx(p0 : u32) -> vec2 { switch(p0) { case 0u: { return a.col0.yx; } case 1u: { return a.col1.yx; } case 2u: { return a.col2.yx; } default: { return vec2(); } } } fn f() { let I = 1; let l = load_a_p0_yx(u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, MatUniform_LoadScalar_ConstColumnIndex_ConstRowIndex_Mat3x2F32) { auto* src = R"( @group(0) @binding(0) var a : mat3x2; fn f() { let l = a[1][0]; } )"; auto* expect = R"( struct mat3x2_f32 { col0 : vec2, col1 : vec2, col2 : vec2, } @group(0) @binding(0) var a : mat3x2_f32; fn f() { let l = a.col1[0u]; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, MatUniform_LoadScalar_VariableColumnIndex_ConstRowIndex_Mat3x2F32) { auto* src = R"( @group(0) @binding(0) var a : mat3x2; fn f() { let I = 0; let l = a[I][0]; } )"; auto* expect = R"( struct mat3x2_f32 { col0 : vec2, col1 : vec2, col2 : vec2, } @group(0) @binding(0) var a : mat3x2_f32; fn load_a_p0_0(p0 : u32) -> f32 { switch(p0) { case 0u: { return a.col0[0u]; } case 1u: { return a.col1[0u]; } case 2u: { return a.col2[0u]; } default: { return f32(); } } } fn f() { let I = 0; let l = load_a_p0_0(u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, MatUniform_LoadScalar_ConstColumnIndex_VariableRowIndex_Mat3x2F32) { auto* src = R"( @group(0) @binding(0) var a : mat3x2; fn f() { let I = 0; let l = a[1][I]; } )"; auto* expect = R"( struct mat3x2_f32 { col0 : vec2, col1 : vec2, col2 : vec2, } @group(0) @binding(0) var a : mat3x2_f32; fn f() { let I = 0; let l = a.col1[I]; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, MatUniform_LoadScalar_VariableColumnIndex_VariableRowIndex_Mat3x2F32) { auto* src = R"( @group(0) @binding(0) var a : mat3x2; fn f() { let I = 0; let l = a[I][I]; } )"; auto* expect = R"( struct mat3x2_f32 { col0 : vec2, col1 : vec2, col2 : vec2, } @group(0) @binding(0) var a : mat3x2_f32; fn load_a_p0_p1(p0 : u32, p1 : u32) -> f32 { switch(p0) { case 0u: { return a.col0[p1]; } case 1u: { return a.col1[p1]; } case 2u: { return a.col2[p1]; } default: { return f32(); } } } fn f() { let I = 0; let l = load_a_p0_p1(u32(I), u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructMatUniform_NameCollision_Mat3x2F32) { auto* src = R"( struct S { m_1 : i32, m : mat3x2, } @group(0) @binding(0) var s : S; )"; auto* expect = R"( struct S { m_1 : i32, m : mat3x2, } struct S_std140 { m_1 : i32, m__0 : vec2, m__1 : vec2, m__2 : vec2, } @group(0) @binding(0) var s : S_std140; )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructMatUniform_LoadStruct_Mat3x2F32) { auto* src = R"( struct S { m : mat3x2, } @group(0) @binding(0) var s : S; fn f() { let l = s; } )"; auto* expect = R"( struct S { m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, } @group(0) @binding(0) var s : S_std140; fn conv_S(val : S_std140) -> S { return S(mat3x2(val.m_0, val.m_1, val.m_2)); } fn f() { let l = conv_S(s); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructMatUniform_LoadMatrix_Mat3x2F32) { auto* src = R"( struct S { m : mat3x2, } @group(0) @binding(0) var s : S; fn f() { let l = s.m; } )"; auto* expect = R"( struct S { m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, } @group(0) @binding(0) var s : S_std140; fn load_s_m() -> mat3x2 { let s = &(s); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn f() { let l = load_s_m(); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructMatUniform_LoadColumn_ConstIndex_Mat3x2F32) { auto* src = R"( struct S { m : mat3x2, } @group(0) @binding(0) var s : S; fn f() { let l = s.m[1]; } )"; auto* expect = R"( struct S { m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, } @group(0) @binding(0) var s : S_std140; fn f() { let l = s.m_1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructMatUniform_LoadColumn_VariableIndex_Mat3x2F32) { auto* src = R"( struct S { m : mat3x2, } @group(0) @binding(0) var s : S; fn f() { let I = 0; let l = s.m[I]; } )"; auto* expect = R"( struct S { m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, } @group(0) @binding(0) var s : S_std140; fn load_s_m_p0(p0 : u32) -> vec2 { switch(p0) { case 0u: { return s.m_0; } case 1u: { return s.m_1; } case 2u: { return s.m_2; } default: { return vec2(); } } } fn f() { let I = 0; let l = load_s_m_p0(u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructMatUniform_LoadScalar_ConstColumnIndex_ConstRowIndex_Mat3x2F32) { auto* src = R"( struct S { m : mat3x2, } @group(0) @binding(0) var s : S; fn f() { let l = s.m[1][0]; } )"; auto* expect = R"( struct S { m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, } @group(0) @binding(0) var s : S_std140; fn f() { let l = s.m_1[0u]; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructMatUniform_LoadScalar_VariableColumnIndex_ConstRowIndex_Mat3x2F32) { auto* src = R"( struct S { m : mat3x2, } @group(0) @binding(0) var s : S; fn f() { let I = 0; let l = s.m[I][0]; } )"; auto* expect = R"( struct S { m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, } @group(0) @binding(0) var s : S_std140; fn load_s_m_p0_0(p0 : u32) -> f32 { switch(p0) { case 0u: { return s.m_0[0u]; } case 1u: { return s.m_1[0u]; } case 2u: { return s.m_2[0u]; } default: { return f32(); } } } fn f() { let I = 0; let l = load_s_m_p0_0(u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructMatUniform_LoadScalar_ConstColumnIndex_VariableRowIndex_Mat3x2F32) { auto* src = R"( struct S { m : mat3x2, } @group(0) @binding(0) var s : S; fn f() { let I = 0; let l = s.m[1][I]; } )"; auto* expect = R"( struct S { m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, } @group(0) @binding(0) var s : S_std140; fn f() { let I = 0; let l = s.m_1[I]; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructMatUniform_LoadScalar_VariableColumnIndex_VariableRowIndex_Mat3x2F32) { auto* src = R"( struct S { m : mat3x2, } @group(0) @binding(0) var s : S; fn f() { let I = 0; let l = s.m[I][I]; } )"; auto* expect = R"( struct S { m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, m_2 : vec2, } @group(0) @binding(0) var s : S_std140; fn load_s_m_p0_p1(p0 : u32, p1 : u32) -> f32 { switch(p0) { case 0u: { return s.m_0[p1]; } case 1u: { return s.m_1[p1]; } case 2u: { return s.m_2[p1]; } default: { return f32(); } } } fn f() { let I = 0; let l = load_s_m_p0_p1(u32(I), u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_LoadArray_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var a : array; fn f() { let l = a; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var a : array; fn conv_S(val : S_std140) -> S { return S(mat3x2(val.m_0, val.m_1, val.m_2)); } fn conv_arr3_S(val : array) -> array { var arr : array; for(var i : u32; (i < 3u); i = (i + 1)) { arr[i] = conv_S(val[i]); } return arr; } fn f() { let l = conv_arr3_S(a); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_LoadStruct_ConstIndex_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var a : array; fn f() { let l = a[2]; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var a : array; fn conv_S(val : S_std140) -> S { return S(mat3x2(val.m_0, val.m_1, val.m_2)); } fn f() { let l = conv_S(a[2u]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_LoadStruct_VariableIndex_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var a : array; fn f() { let I = 1; let l = a[I]; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var a : array; fn conv_S(val : S_std140) -> S { return S(mat3x2(val.m_0, val.m_1, val.m_2)); } fn f() { let I = 1; let l = conv_S(a[I]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_LoadMatrix_ConstArrayIndex_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var a : array; fn f() { let l = a[2].m; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var a : array; fn load_a_2_m() -> mat3x2 { let s = &(a[2u]); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn f() { let l = load_a_2_m(); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_LoadMatrix_VariableArrayIndex_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var a : array; fn f() { let I = 1; let l = a[I].m; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var a : array; fn load_a_p0_m(p0 : u32) -> mat3x2 { let s = &(a[p0]); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn f() { let I = 1; let l = load_a_p0_m(u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_LoadColumn_ConstArrayIndex_ConstColumnIndex_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var a : array; fn f() { let l = a[2].m[1]; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var a : array; fn f() { let l = a[2u].m_1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_LoadColumn_VariableArrayIndex_ConstColumnIndex_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var a : array; fn f() { let I = 1; let l = a[I].m[1]; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var a : array; fn f() { let I = 1; let l = a[I].m_1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_LoadColumn_ConstArrayIndex_VariableColumnIndex_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var a : array; fn f() { let I = 1; let l = a[2].m[I]; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var a : array; fn load_a_2_m_p0(p0 : u32) -> vec2 { switch(p0) { case 0u: { return a[2u].m_0; } case 1u: { return a[2u].m_1; } case 2u: { return a[2u].m_2; } default: { return vec2(); } } } fn f() { let I = 1; let l = load_a_2_m_p0(u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_LoadColumn_VariableArrayIndex_VariableColumnIndex_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var a : array; fn f() { let I = 1; let l = a[I].m[I]; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var a : array; fn load_a_p0_m_p1(p0 : u32, p1 : u32) -> vec2 { switch(p1) { case 0u: { return a[p0].m_0; } case 1u: { return a[p0].m_1; } case 2u: { return a[p0].m_2; } default: { return vec2(); } } } fn f() { let I = 1; let l = load_a_p0_m_p1(u32(I), u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructArrayStructMatUniform_Loads_Mat3x2F32) { auto* src = R"( struct Inner { @size(64) m : mat3x2, } struct Outer { a : array, } @group(0) @binding(0) var a : array; fn f() { let I = 1; let J = 2; let K = 0; let l_a : array = a; let l_a_1 : Outer = a[1]; let l_a_I : Outer = a[I]; let l_a_2_a : array = a[2].a; let l_a_I_a : array = a[I].a; let l_a_3_a_1 : Inner = a[3].a[1]; let l_a_3_a_I : Inner = a[3].a[I]; let l_a_I_a_1 : Inner = a[I].a[1]; let l_a_I_a_J : Inner = a[I].a[J]; let l_a_0_a_2_m : mat3x2 = a[0].a[2].m; let l_a_0_a_I_m : mat3x2 = a[0].a[I].m; let l_a_I_a_2_m : mat3x2 = a[I].a[2].m; let l_a_I_a_J_m : mat3x2 = a[I].a[J].m; let l_a_1_a_3_m_0 : vec2 = a[1].a[3].m[0]; let l_a_I_a_J_m_K : vec2 = a[I].a[J].m[K]; let l_a_2_a_0_m_1_0 : f32 = a[2].a[0].m[1][0]; let l_a_I_a_J_m_K_I : f32 = a[I].a[J].m[K][I]; } )"; auto* expect = R"( struct Inner { @size(64) m : mat3x2, } struct Inner_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } struct Outer { a : array, } struct Outer_std140 { a : array, } @group(0) @binding(0) var a : array; fn conv_Inner(val : Inner_std140) -> Inner { return Inner(mat3x2(val.m_0, val.m_1, val.m_2)); } fn conv_arr4_Inner(val : array) -> array { var arr : array; for(var i : u32; (i < 4u); i = (i + 1)) { arr[i] = conv_Inner(val[i]); } return arr; } fn conv_Outer(val : Outer_std140) -> Outer { return Outer(conv_arr4_Inner(val.a)); } fn conv_arr4_Outer(val : array) -> array { var arr : array; for(var i : u32; (i < 4u); i = (i + 1)) { arr[i] = conv_Outer(val[i]); } return arr; } fn load_a_0_a_2_m() -> mat3x2 { let s = &(a[0u].a[2u]); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn load_a_0_a_p0_m(p0 : u32) -> mat3x2 { let s = &(a[0u].a[p0]); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn load_a_p0_a_2_m(p0 : u32) -> mat3x2 { let s = &(a[p0].a[2u]); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn load_a_p0_a_p1_m(p0 : u32, p1 : u32) -> mat3x2 { let s = &(a[p0].a[p1]); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn load_a_p0_a_p1_m_p2(p0 : u32, p1 : u32, p2 : u32) -> vec2 { switch(p2) { case 0u: { return a[p0].a[p1].m_0; } case 1u: { return a[p0].a[p1].m_1; } case 2u: { return a[p0].a[p1].m_2; } default: { return vec2(); } } } fn load_a_p0_a_p1_m_p2_p3(p0 : u32, p1 : u32, p2 : u32, p3 : u32) -> f32 { switch(p2) { case 0u: { return a[p0].a[p1].m_0[p3]; } case 1u: { return a[p0].a[p1].m_1[p3]; } case 2u: { return a[p0].a[p1].m_2[p3]; } default: { return f32(); } } } fn f() { let I = 1; let J = 2; let K = 0; let l_a : array = conv_arr4_Outer(a); let l_a_1 : Outer = conv_Outer(a[1u]); let l_a_I : Outer = conv_Outer(a[I]); let l_a_2_a : array = conv_arr4_Inner(a[2u].a); let l_a_I_a : array = conv_arr4_Inner(a[I].a); let l_a_3_a_1 : Inner = conv_Inner(a[3u].a[1u]); let l_a_3_a_I : Inner = conv_Inner(a[3u].a[I]); let l_a_I_a_1 : Inner = conv_Inner(a[I].a[1u]); let l_a_I_a_J : Inner = conv_Inner(a[I].a[J]); let l_a_0_a_2_m : mat3x2 = load_a_0_a_2_m(); let l_a_0_a_I_m : mat3x2 = load_a_0_a_p0_m(u32(I)); let l_a_I_a_2_m : mat3x2 = load_a_p0_a_2_m(u32(I)); let l_a_I_a_J_m : mat3x2 = load_a_p0_a_p1_m(u32(I), u32(J)); let l_a_1_a_3_m_0 : vec2 = a[1u].a[3u].m_0; let l_a_I_a_J_m_K : vec2 = load_a_p0_a_p1_m_p2(u32(I), u32(J), u32(K)); let l_a_2_a_0_m_1_0 : f32 = a[2u].a[0u].m_1[0u]; let l_a_I_a_J_m_K_I : f32 = load_a_p0_a_p1_m_p2_p3(u32(I), u32(J), u32(K), u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructArrayStructMatUniform_LoadsViaPtrs_Mat3x2F32) { auto* src = R"( struct Inner { @size(64) m : mat3x2, } struct Outer { a : array, } @group(0) @binding(0) var a : array; fn f() { let I = 1; let J = 2; let K = 0; let p_a = &(a); let p_a_3 = &((*(p_a))[3]); let p_a_I = &((*(p_a))[I]); let p_a_3_a = &((*(p_a_3)).a); let p_a_I_a = &((*(p_a_I)).a); let p_a_3_a_2 = &((*(p_a_3_a))[2]); let p_a_3_a_I = &((*(p_a_3_a))[I]); let p_a_I_a_2 = &((*(p_a_I_a))[2]); let p_a_I_a_J = &((*(p_a_I_a))[J]); let p_a_3_a_2_m = &((*(p_a_3_a_2)).m); let p_a_3_a_I_m = &((*(p_a_3_a_I)).m); let p_a_I_a_2_m = &((*(p_a_I_a_2)).m); let p_a_I_a_J_m = &((*(p_a_I_a_J)).m); let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]); let p_a_I_a_J_m_K = &((*(p_a_I_a_J_m))[K]); let l_a : array = *(p_a); let l_a_3 : Outer = *(p_a_3); let l_a_I : Outer = *(p_a_I); let l_a_3_a : array = *(p_a_3_a); let l_a_I_a : array = *(p_a_I_a); let l_a_3_a_2 : Inner = *(p_a_3_a_2); let l_a_3_a_I : Inner = *(p_a_3_a_I); let l_a_I_a_2 : Inner = *(p_a_I_a_2); let l_a_I_a_J : Inner = *(p_a_I_a_J); let l_a_3_a_2_m : mat3x2 = *(p_a_3_a_2_m); let l_a_3_a_I_m : mat3x2 = *(p_a_3_a_I_m); let l_a_I_a_2_m : mat3x2 = *(p_a_I_a_2_m); let l_a_I_a_J_m : mat3x2 = *(p_a_I_a_J_m); let l_a_3_a_2_m_1 : vec2 = *(p_a_3_a_2_m_1); let l_a_I_a_J_m_K : vec2 = *(p_a_I_a_J_m_K); let l_a_2_a_0_m_1_0 : f32 = (*(p_a_3_a_2_m_1))[0]; let l_a_I_a_J_m_K_I : f32 = (*(p_a_I_a_J_m_K))[I]; } )"; auto* expect = R"( struct Inner { @size(64) m : mat3x2, } struct Inner_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } struct Outer { a : array, } struct Outer_std140 { a : array, } @group(0) @binding(0) var a : array; fn conv_Inner(val : Inner_std140) -> Inner { return Inner(mat3x2(val.m_0, val.m_1, val.m_2)); } fn conv_arr4_Inner(val : array) -> array { var arr : array; for(var i : u32; (i < 4u); i = (i + 1)) { arr[i] = conv_Inner(val[i]); } return arr; } fn conv_Outer(val : Outer_std140) -> Outer { return Outer(conv_arr4_Inner(val.a)); } fn conv_arr4_Outer(val : array) -> array { var arr : array; for(var i : u32; (i < 4u); i = (i + 1)) { arr[i] = conv_Outer(val[i]); } return arr; } fn load_a_3_a_2_m() -> mat3x2 { let s = &(a[3u].a[2u]); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn load_a_3_a_p0_m(p0 : u32) -> mat3x2 { let s = &(a[3u].a[p0]); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn load_a_p0_a_2_m(p0 : u32) -> mat3x2 { let s = &(a[p0].a[2u]); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn load_a_p0_a_p1_m(p0 : u32, p1 : u32) -> mat3x2 { let s = &(a[p0].a[p1]); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn load_a_p0_a_p1_m_p2(p0 : u32, p1 : u32, p2 : u32) -> vec2 { switch(p2) { case 0u: { return a[p0].a[p1].m_0; } case 1u: { return a[p0].a[p1].m_1; } case 2u: { return a[p0].a[p1].m_2; } default: { return vec2(); } } } fn load_a_p0_a_p1_m_p2_p3(p0 : u32, p1 : u32, p2 : u32, p3 : u32) -> f32 { switch(p2) { case 0u: { return a[p0].a[p1].m_0[p3]; } case 1u: { return a[p0].a[p1].m_1[p3]; } case 2u: { return a[p0].a[p1].m_2[p3]; } default: { return f32(); } } } fn f() { let I = 1; let J = 2; let K = 0; let p_a = conv_arr4_Outer(a); let p_a_3 = conv_Outer(a[3u]); let p_a_I = conv_Outer(a[I]); let p_a_3_a = conv_arr4_Inner(a[3u].a); let p_a_I_a = conv_arr4_Inner(a[I].a); let p_a_3_a_2 = conv_Inner(a[3u].a[2u]); let p_a_3_a_I = conv_Inner(a[3u].a[I]); let p_a_I_a_2 = conv_Inner(a[I].a[2u]); let p_a_I_a_J = conv_Inner(a[I].a[J]); let p_a_3_a_2_m = load_a_3_a_2_m(); let p_a_3_a_I_m = load_a_3_a_p0_m(u32(I)); let p_a_I_a_2_m = load_a_p0_a_2_m(u32(I)); let p_a_I_a_J_m = load_a_p0_a_p1_m(u32(I), u32(J)); let p_a_3_a_2_m_1 = a[3u].a[2u].m_1; let p_a_I_a_J_m_K = load_a_p0_a_p1_m_p2(u32(I), u32(J), u32(K)); let l_a : array = conv_arr4_Outer(a); let l_a_3 : Outer = conv_Outer(a[3u]); let l_a_I : Outer = conv_Outer(a[I]); let l_a_3_a : array = conv_arr4_Inner(a[3u].a); let l_a_I_a : array = conv_arr4_Inner(a[I].a); let l_a_3_a_2 : Inner = conv_Inner(a[3u].a[2u]); let l_a_3_a_I : Inner = conv_Inner(a[3u].a[I]); let l_a_I_a_2 : Inner = conv_Inner(a[I].a[2u]); let l_a_I_a_J : Inner = conv_Inner(a[I].a[J]); let l_a_3_a_2_m : mat3x2 = load_a_3_a_2_m(); let l_a_3_a_I_m : mat3x2 = load_a_3_a_p0_m(u32(I)); let l_a_I_a_2_m : mat3x2 = load_a_p0_a_2_m(u32(I)); let l_a_I_a_J_m : mat3x2 = load_a_p0_a_p1_m(u32(I), u32(J)); let l_a_3_a_2_m_1 : vec2 = a[3u].a[2u].m_1; let l_a_I_a_J_m_K : vec2 = load_a_p0_a_p1_m_p2(u32(I), u32(J), u32(K)); let l_a_2_a_0_m_1_0 : f32 = a[3u].a[2u].m_1[0u]; let l_a_I_a_J_m_K_I : f32 = load_a_p0_a_p1_m_p2_p3(u32(I), u32(J), u32(K), u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_CopyArray_UniformToStorage_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var u : array; @group(0) @binding(1) var s : array; fn f() { s = u; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var u : array; @group(0) @binding(1) var s : array; fn conv_S(val : S_std140) -> S { return S(mat3x2(val.m_0, val.m_1, val.m_2)); } fn conv_arr4_S(val : array) -> array { var arr : array; for(var i : u32; (i < 4u); i = (i + 1)) { arr[i] = conv_S(val[i]); } return arr; } fn f() { s = conv_arr4_S(u); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_CopyStruct_UniformToWorkgroup_Mat3x2F32) { auto* src = R"( struct S { v : vec4, @size(64) m : mat3x2, } @group(0) @binding(0) var u : array; var w : array; fn f() { w[0] = u[1]; } )"; auto* expect = R"( struct S { v : vec4, @size(64) m : mat3x2, } struct S_std140 { v : vec4, m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var u : array; var w : array; fn conv_S(val : S_std140) -> S { return S(val.v, mat3x2(val.m_0, val.m_1, val.m_2)); } fn f() { w[0] = conv_S(u[1u]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_CopyMatrix_UniformToPrivate_Mat3x2F32) { auto* src = R"( struct S { v : vec4, @size(64) m : mat3x2, } @group(0) @binding(0) var u : array; var p : array; fn f() { p[2].m = u[1].m; } )"; auto* expect = R"( struct S { v : vec4, @size(64) m : mat3x2, } struct S_std140 { v : vec4, m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var u : array; var p : array; fn load_u_1_m() -> mat3x2 { let s = &(u[1u]); return mat3x2((*(s)).m_0, (*(s)).m_1, (*(s)).m_2); } fn f() { p[2].m = load_u_1_m(); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_CopyColumn_UniformToStorage_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var u : array; @group(0) @binding(1) var s : array; fn f() { s[3].m[1] = u[2].m[0]; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var u : array; @group(0) @binding(1) var s : array; fn f() { s[3].m[1] = u[2u].m_0; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_CopyColumnSwizzle_UniformToWorkgroup_Mat3x2F32) { auto* src = R"( struct S { @size(64) m : mat3x2, } @group(0) @binding(0) var u : array; var w : array; fn f() { w[3].m[1] = u[2].m[0].yx.yx; } )"; auto* expect = R"( struct S { @size(64) m : mat3x2, } struct S_std140 { m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var u : array; var w : array; fn f() { w[3].m[1] = u[2u].m_0.yx.yx; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayStructMatUniform_CopyScalar_UniformToPrivate_Mat3x2F32) { auto* src = R"( struct S { v : vec4, @size(64) m : mat3x2, } @group(0) @binding(0) var u : array; var p : array; fn f() { p[3].m[1].x = u[2].m[0].y; } )"; auto* expect = R"( struct S { v : vec4, @size(64) m : mat3x2, } struct S_std140 { v : vec4, m_0 : vec2, m_1 : vec2, @size(48) m_2 : vec2, } @group(0) @binding(0) var u : array; var p : array; fn f() { p[3].m[1].x = u[2u].m_0[1u]; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayMatUniform_LoadArray_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>; fn f() { let l = a; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn conv_arr3_mat2x2_f32(val : array) -> array, 3u> { var arr : array, 3u>; for(var i : u32; (i < 3u); i = (i + 1)) { arr[i] = conv_mat2x2_f32(val[i]); } return arr; } fn f() { let l = conv_arr3_mat2x2_f32(a); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayMatUniform_LoadMatrix_ConstArrayIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>; fn f() { let l = a[2]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn f() { let l = conv_mat2x2_f32(a[2u]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayMatUniform_LoadMatrix_VariableArrayIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>; fn f() { let I = 1; let l = a[I]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn f() { let I = 1; let l = conv_mat2x2_f32(a[I]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayMatUniform_LoadColumn_ConstArrayIndex_ConstColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>; fn f() { let l = a[2][1]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array; fn f() { let l = a[2u].col1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayMatUniform_LoadColumn_VariableArrayIndex_ConstColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>; fn f() { let I = 1; let l = a[I][1]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array; fn f() { let I = 1; let l = a[I].col1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayMatUniform_LoadColumn_ConstArrayIndex_VariableColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>; fn f() { let I = 1; let l = a[2][I]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array; fn load_a_2_p0(p0 : u32) -> vec2 { switch(p0) { case 0u: { return a[2u].col0; } case 1u: { return a[2u].col1; } default: { return vec2(); } } } fn f() { let I = 1; let l = load_a_2_p0(u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayMatUniform_LoadColumn_VariableArrayIndex_VariableColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>; fn f() { let I = 1; let l = a[I][I]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array; fn load_a_p0_p1(p0 : u32, p1 : u32) -> vec2 { switch(p1) { case 0u: { return a[p0].col0; } case 1u: { return a[p0].col1; } default: { return vec2(); } } } fn f() { let I = 1; let l = load_a_p0_p1(u32(I), u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructArrayMatUniform_LoadStruct_Mat2x2F32) { auto* src = R"( struct S { a : array, 3>, } @group(0) @binding(0) var s : S; fn f() { let l = s; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } struct S { a : array, 3>, } struct S_std140 { a : array, } @group(0) @binding(0) var s : S_std140; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn conv_arr3_mat2x2_f32(val : array) -> array, 3u> { var arr : array, 3u>; for(var i : u32; (i < 3u); i = (i + 1)) { arr[i] = conv_mat2x2_f32(val[i]); } return arr; } fn conv_S(val : S_std140) -> S { return S(conv_arr3_mat2x2_f32(val.a)); } fn f() { let l = conv_S(s); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructArrayMatUniform_LoadArray_Mat2x2F32) { auto* src = R"( struct S { a : array, 3>, } @group(0) @binding(0) var s : S; fn f() { let l = s.a; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } struct S { a : array, 3>, } struct S_std140 { a : array, } @group(0) @binding(0) var s : S_std140; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn conv_arr3_mat2x2_f32(val : array) -> array, 3u> { var arr : array, 3u>; for(var i : u32; (i < 3u); i = (i + 1)) { arr[i] = conv_mat2x2_f32(val[i]); } return arr; } fn f() { let l = conv_arr3_mat2x2_f32(s.a); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructArrayMatUniform_LoadMatrix_ConstArrayIndex_Mat2x2F32) { auto* src = R"( struct S { a : array, 3>, } @group(0) @binding(0) var s : S; fn f() { let l = s.a[2]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } struct S { a : array, 3>, } struct S_std140 { a : array, } @group(0) @binding(0) var s : S_std140; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn f() { let l = conv_mat2x2_f32(s.a[2u]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructArrayMatUniform_LoadMatrix_VariableArrayIndex_Mat2x2F32) { auto* src = R"( struct S { a : array, 3>, } @group(0) @binding(0) var s : S; fn f() { let I = 1; let l = s.a[I]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } struct S { a : array, 3>, } struct S_std140 { a : array, } @group(0) @binding(0) var s : S_std140; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn f() { let I = 1; let l = conv_mat2x2_f32(s.a[I]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructArrayMatUniform_LoadColumn_ConstArrayIndex_ConstColumnIndex_Mat2x2F32) { auto* src = R"( struct S { a : array, 3>, } @group(0) @binding(0) var s : S; fn f() { let l = s.a[2][1]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } struct S { a : array, 3>, } struct S_std140 { a : array, } @group(0) @binding(0) var s : S_std140; fn f() { let l = s.a[2u].col1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructArrayMatUniform_LoadColumn_VariableArrayIndex_ConstColumnIndex_Mat2x2F32) { auto* src = R"( struct S { a : array, 3>, } @group(0) @binding(0) var s : S; fn f() { let I = 1; let l = s.a[I][1]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } struct S { a : array, 3>, } struct S_std140 { a : array, } @group(0) @binding(0) var s : S_std140; fn f() { let I = 1; let l = s.a[I].col1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructArrayMatUniform_LoadColumn_ConstArrayIndex_VariableColumnIndex_Mat2x2F32) { auto* src = R"( struct S { a : array, 3>, } @group(0) @binding(0) var s : S; fn f() { let I = 1; let l = s.a[2][I]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } struct S { a : array, 3>, } struct S_std140 { a : array, } @group(0) @binding(0) var s : S_std140; fn load_s_a_2_p0(p0 : u32) -> vec2 { switch(p0) { case 0u: { return s.a[2u].col0; } case 1u: { return s.a[2u].col1; } default: { return vec2(); } } } fn f() { let I = 1; let l = load_s_a_2_p0(u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, StructArrayMatUniform_LoadColumn_VariableArrayIndex_VariableColumnIndex_Mat2x2F32) { auto* src = R"( struct S { a : array, 3>, } @group(0) @binding(0) var s : S; fn f() { let I = 1; let l = s.a[I][I]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } struct S { a : array, 3>, } struct S_std140 { a : array, } @group(0) @binding(0) var s : S_std140; fn load_s_a_p0_p1(p0 : u32, p1 : u32) -> vec2 { switch(p1) { case 0u: { return s.a[p0].col0; } case 1u: { return s.a[p0].col1; } default: { return vec2(); } } } fn f() { let I = 1; let l = load_s_a_p0_p1(u32(I), u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayArrayMatUniform_LoadArrays_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let l = a; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn conv_arr3_mat2x2_f32(val : array) -> array, 3u> { var arr : array, 3u>; for(var i : u32; (i < 3u); i = (i + 1)) { arr[i] = conv_mat2x2_f32(val[i]); } return arr; } fn conv_arr4_arr3_mat2x2_f32(val : array, 4u>) -> array, 3u>, 4u> { var arr : array, 3u>, 4u>; for(var i : u32; (i < 4u); i = (i + 1)) { arr[i] = conv_arr3_mat2x2_f32(val[i]); } return arr; } fn f() { let l = conv_arr4_arr3_mat2x2_f32(a); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayArrayMatUniform_LoadArray_ConstOuterArrayIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let l = a[3]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn conv_arr3_mat2x2_f32(val : array) -> array, 3u> { var arr : array, 3u>; for(var i : u32; (i < 3u); i = (i + 1)) { arr[i] = conv_mat2x2_f32(val[i]); } return arr; } fn f() { let l = conv_arr3_mat2x2_f32(a[3u]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayArrayMatUniform_LoadArray_VariableOuterArrayIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let I = 1; let l = a[I]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn conv_arr3_mat2x2_f32(val : array) -> array, 3u> { var arr : array, 3u>; for(var i : u32; (i < 3u); i = (i + 1)) { arr[i] = conv_mat2x2_f32(val[i]); } return arr; } fn f() { let I = 1; let l = conv_arr3_mat2x2_f32(a[I]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayArrayMatUniform_LoadMatrix_ConstOuterArrayIndex_ConstInnerArrayIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let l = a[3][2]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn f() { let l = conv_mat2x2_f32(a[3u][2u]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayArrayMatUniform_LoadMatrix_ConstOuterArrayIndex_VariableInnerArrayIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let I = 1; let l = a[3][I]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn f() { let I = 1; let l = conv_mat2x2_f32(a[3u][I]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayArrayMatUniform_LoadMatrix_VariableOuterArrayIndex_ConstInnerArrayIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let I = 1; let l = a[I][2]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn f() { let I = 1; let l = conv_mat2x2_f32(a[I][2u]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(Std140Test_F32, ArrayArrayMatUniform_LoadMatrix_VariableOuterArrayIndex_VariableInnerArrayIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let I = 1; let l = a[I][I]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2 { return mat2x2(val.col0, val.col1); } fn f() { let I = 1; let l = conv_mat2x2_f32(a[I][I]); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F( Std140Test_F32, ArrayArrayMatUniform_LoadColumn_ConstOuterArrayIndex_ConstInnerArrayIndex_ConstColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let l = a[3][2][1]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn f() { let l = a[3u][2u].col1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F( Std140Test_F32, ArrayArrayMatUniform_LoadColumn_ConstOuterArrayIndex_ConstInnerArrayIndex_VariableColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let I = 1; let l = a[3][2][I]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn load_a_3_2_p0(p0 : u32) -> vec2 { switch(p0) { case 0u: { return a[3u][2u].col0; } case 1u: { return a[3u][2u].col1; } default: { return vec2(); } } } fn f() { let I = 1; let l = load_a_3_2_p0(u32(I)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F( Std140Test_F32, ArrayArrayMatUniform_LoadColumn_ConstOuterArrayIndex_VariableInnerArrayIndex_ConstColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let I = 1; let l = a[3][I][1]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn f() { let I = 1; let l = a[3u][I].col1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F( Std140Test_F32, ArrayArrayMatUniform_LoadColumn_ConstOuterArrayIndex_VariableInnerArrayIndex_VariableColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let I = 1; let J = 2; let l = a[3][I][J]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn load_a_3_p0_p1(p0 : u32, p1 : u32) -> vec2 { switch(p1) { case 0u: { return a[3u][p0].col0; } case 1u: { return a[3u][p0].col1; } default: { return vec2(); } } } fn f() { let I = 1; let J = 2; let l = load_a_3_p0_p1(u32(I), u32(J)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F( Std140Test_F32, ArrayArrayMatUniform_LoadColumn_VariableOuterArrayIndex_ConstInnerArrayIndex_ConstColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let I = 1; let l = a[I][2][1]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn f() { let I = 1; let l = a[I][2u].col1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F( Std140Test_F32, ArrayArrayMatUniform_LoadColumn_VariableOuterArrayIndex_ConstInnerArrayIndex_VariableColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let I = 1; let J = 2; let l = a[I][2][J]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn load_a_p0_2_p1(p0 : u32, p1 : u32) -> vec2 { switch(p1) { case 0u: { return a[p0][2u].col0; } case 1u: { return a[p0][2u].col1; } default: { return vec2(); } } } fn f() { let I = 1; let J = 2; let l = load_a_p0_2_p1(u32(I), u32(J)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F( Std140Test_F32, ArrayArrayMatUniform_LoadColumn_VariableOuterArrayIndex_VariableInnerArrayIndex_ConstColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let I = 1; let J = 2; let l = a[I][J][1]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn f() { let I = 1; let J = 2; let l = a[I][J].col1; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F( Std140Test_F32, ArrayArrayMatUniform_LoadColumn_VariableOuterArrayIndex_VariableInnerArrayIndex_VariableColumnIndex_Mat2x2F32) { auto* src = R"( @group(0) @binding(0) var a : array, 3>, 4>; fn f() { let I = 0; let J = 1; let K = 2; let l = a[I][J][K]; } )"; auto* expect = R"( struct mat2x2_f32 { col0 : vec2, col1 : vec2, } @group(0) @binding(0) var a : array, 4u>; fn load_a_p0_p1_p2(p0 : u32, p1 : u32, p2 : u32) -> vec2 { switch(p2) { case 0u: { return a[p0][p1].col0; } case 1u: { return a[p0][p1].col1; } default: { return vec2(); } } } fn f() { let I = 0; let J = 1; let K = 2; let l = load_a_p0_p1_p2(u32(I), u32(J), u32(K)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } } // namespace } // namespace tint::transform