| // Copyright 2024 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/wgsl/writer/raise/value_to_let.h" |
| |
| #include <utility> |
| |
| #include "src/tint/lang/core/ir/transform/helper_test.h" |
| |
| namespace tint::wgsl::writer::raise { |
| namespace { |
| |
| using namespace tint::core::fluent_types; // NOLINT |
| using namespace tint::core::number_suffixes; // NOLINT |
| |
| using WgslWriter_ValueToLetTest = tint::core::ir::transform::TransformTest; |
| |
| TEST_F(WgslWriter_ValueToLetTest, Empty) { |
| auto* expect = R"( |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Load / Store |
| //////////////////////////////////////////////////////////////////////////////// |
| TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenStoreVar_ThenUseLoad) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* load = b.Load(var); |
| b.Store(var, 2_i); |
| b.Return(fn, load); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| store %2, 2i |
| ret %3 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| %4:i32 = let %3 |
| store %2, 2i |
| ret %4 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Binary op |
| //////////////////////////////////////////////////////////////////////////////// |
| TEST_F(WgslWriter_ValueToLetTest, BinaryOpUnsequencedLHSThenUnsequencedRHS) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { |
| auto* lhs = b.Add(ty.i32(), 1_i, 2_i); |
| auto* rhs = b.Add(ty.i32(), 3_i, 4_i); |
| auto* bin = b.Add(ty.i32(), lhs, rhs); |
| b.Return(fn_b, bin); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func():i32 -> %b2 { |
| %b2 = block { |
| %4:i32 = add 1i, 2i |
| %5:i32 = add 3i, 4i |
| %6:i32 = add %4, %5 |
| ret %6 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, BinaryOpSequencedLHSThenUnsequencedRHS) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { |
| auto* lhs = b.Call(ty.i32(), fn_a, 1_i); |
| auto* rhs = b.Add(ty.i32(), 2_i, 3_i); |
| auto* bin = b.Add(ty.i32(), lhs, rhs); |
| b.Return(fn_b, bin); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func():i32 -> %b2 { |
| %b2 = block { |
| %4:i32 = call %a, 1i |
| %5:i32 = add 2i, 3i |
| %6:i32 = add %4, %5 |
| ret %6 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, BinaryOpUnsequencedLHSThenSequencedRHS) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { |
| auto* lhs = b.Add(ty.i32(), 1_i, 2_i); |
| auto* rhs = b.Call(ty.i32(), fn_a, 3_i); |
| auto* bin = b.Add(ty.i32(), lhs, rhs); |
| b.Return(fn_b, bin); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func():i32 -> %b2 { |
| %b2 = block { |
| %4:i32 = add 1i, 2i |
| %5:i32 = call %a, 3i |
| %6:i32 = add %4, %5 |
| ret %6 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, BinaryOpSequencedLHSThenSequencedRHS) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { |
| auto* lhs = b.Call(ty.i32(), fn_a, 1_i); |
| auto* rhs = b.Call(ty.i32(), fn_a, 2_i); |
| auto* bin = b.Add(ty.i32(), lhs, rhs); |
| b.Return(fn_b, bin); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func():i32 -> %b2 { |
| %b2 = block { |
| %4:i32 = call %a, 1i |
| %5:i32 = call %a, 2i |
| %6:i32 = add %4, %5 |
| ret %6 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, BinaryOpUnsequencedRHSThenUnsequencedLHS) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { |
| auto* rhs = b.Add(ty.i32(), 3_i, 4_i); |
| auto* lhs = b.Add(ty.i32(), 1_i, 2_i); |
| auto* bin = b.Add(ty.i32(), lhs, rhs); |
| b.Return(fn_b, bin); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func():i32 -> %b2 { |
| %b2 = block { |
| %4:i32 = add 3i, 4i |
| %5:i32 = add 1i, 2i |
| %6:i32 = add %5, %4 |
| ret %6 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, BinaryOpUnsequencedRHSThenSequencedLHS) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { |
| auto* rhs = b.Add(ty.i32(), 2_i, 3_i); |
| auto* lhs = b.Call(ty.i32(), fn_a, 1_i); |
| auto* bin = b.Add(ty.i32(), lhs, rhs); |
| b.Return(fn_b, bin); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func():i32 -> %b2 { |
| %b2 = block { |
| %4:i32 = add 2i, 3i |
| %5:i32 = call %a, 1i |
| %6:i32 = add %5, %4 |
| ret %6 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, BinaryOpSequencedRHSThenUnsequencedLHS) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { |
| auto* rhs = b.Call(ty.i32(), fn_a, 3_i); |
| auto* lhs = b.Add(ty.i32(), 1_i, 2_i); |
| auto* bin = b.Add(ty.i32(), lhs, rhs); |
| b.Return(fn_b, bin); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func():i32 -> %b2 { |
| %b2 = block { |
| %4:i32 = call %a, 3i |
| %5:i32 = add 1i, 2i |
| %6:i32 = add %5, %4 |
| ret %6 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, BinaryOpSequencedRHSThenSequencedLHS) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { |
| auto* rhs = b.Call(ty.i32(), fn_a, 2_i); |
| auto* lhs = b.Call(ty.i32(), fn_a, 1_i); |
| auto* bin = b.Add(ty.i32(), lhs, rhs); |
| b.Return(fn_b, bin); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func():i32 -> %b2 { |
| %b2 = block { |
| %4:i32 = call %a, 2i |
| %5:i32 = call %a, 1i |
| %6:i32 = add %5, %4 |
| ret %6 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func():i32 -> %b2 { |
| %b2 = block { |
| %4:i32 = call %a, 2i |
| %5:i32 = let %4 |
| %6:i32 = call %a, 1i |
| %7:i32 = add %6, %5 |
| ret %7 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Call |
| //////////////////////////////////////////////////////////////////////////////// |
| TEST_F(WgslWriter_ValueToLetTest, CallSequencedXYZ) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); }); |
| fn_b->SetParams( |
| {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())}); |
| |
| auto* fn_c = b.Function("c", ty.i32()); |
| b.Append(fn_c->Block(), [&] { |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* call = b.Call(ty.i32(), fn_b, x, y, z); |
| b.Return(fn_c, call); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 { |
| %b2 = block { |
| ret 0i |
| } |
| } |
| %c = func():i32 -> %b3 { |
| %b3 = block { |
| %8:i32 = call %a, 1i |
| %9:i32 = call %a, 2i |
| %10:i32 = call %a, 3i |
| %11:i32 = call %b, %8, %9, %10 |
| ret %11 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, CallSequencedYXZ) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); }); |
| fn_b->SetParams( |
| {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())}); |
| |
| auto* fn_c = b.Function("c", ty.i32()); |
| b.Append(fn_c->Block(), [&] { |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* call = b.Call(ty.i32(), fn_b, x, y, z); |
| b.Return(fn_c, call); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 { |
| %b2 = block { |
| ret 0i |
| } |
| } |
| %c = func():i32 -> %b3 { |
| %b3 = block { |
| %8:i32 = call %a, 2i |
| %9:i32 = call %a, 1i |
| %10:i32 = call %a, 3i |
| %11:i32 = call %b, %9, %8, %10 |
| ret %11 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 { |
| %b2 = block { |
| ret 0i |
| } |
| } |
| %c = func():i32 -> %b3 { |
| %b3 = block { |
| %8:i32 = call %a, 2i |
| %9:i32 = let %8 |
| %10:i32 = call %a, 1i |
| %11:i32 = call %a, 3i |
| %12:i32 = call %b, %10, %9, %11 |
| ret %12 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, CallSequencedXZY) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); }); |
| fn_b->SetParams( |
| {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())}); |
| |
| auto* fn_c = b.Function("c", ty.i32()); |
| b.Append(fn_c->Block(), [&] { |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* call = b.Call(ty.i32(), fn_b, x, y, z); |
| b.Return(fn_c, call); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 { |
| %b2 = block { |
| ret 0i |
| } |
| } |
| %c = func():i32 -> %b3 { |
| %b3 = block { |
| %8:i32 = call %a, 1i |
| %9:i32 = call %a, 3i |
| %10:i32 = call %a, 2i |
| %11:i32 = call %b, %8, %10, %9 |
| ret %11 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 { |
| %b2 = block { |
| ret 0i |
| } |
| } |
| %c = func():i32 -> %b3 { |
| %b3 = block { |
| %8:i32 = call %a, 1i |
| %9:i32 = let %8 |
| %10:i32 = call %a, 3i |
| %11:i32 = let %10 |
| %12:i32 = call %a, 2i |
| %13:i32 = call %b, %9, %12, %11 |
| ret %13 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, CallSequencedZXY) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); }); |
| fn_b->SetParams( |
| {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())}); |
| |
| auto* fn_c = b.Function("c", ty.i32()); |
| b.Append(fn_c->Block(), [&] { |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* call = b.Call(ty.i32(), fn_b, x, y, z); |
| b.Return(fn_c, call); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 { |
| %b2 = block { |
| ret 0i |
| } |
| } |
| %c = func():i32 -> %b3 { |
| %b3 = block { |
| %8:i32 = call %a, 3i |
| %9:i32 = call %a, 1i |
| %10:i32 = call %a, 2i |
| %11:i32 = call %b, %9, %10, %8 |
| ret %11 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 { |
| %b2 = block { |
| ret 0i |
| } |
| } |
| %c = func():i32 -> %b3 { |
| %b3 = block { |
| %8:i32 = call %a, 3i |
| %9:i32 = let %8 |
| %10:i32 = call %a, 1i |
| %11:i32 = call %a, 2i |
| %12:i32 = call %b, %10, %11, %9 |
| ret %12 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, CallSequencedYZX) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); }); |
| fn_b->SetParams( |
| {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())}); |
| |
| auto* fn_c = b.Function("c", ty.i32()); |
| b.Append(fn_c->Block(), [&] { |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* call = b.Call(ty.i32(), fn_b, x, y, z); |
| b.Return(fn_c, call); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 { |
| %b2 = block { |
| ret 0i |
| } |
| } |
| %c = func():i32 -> %b3 { |
| %b3 = block { |
| %8:i32 = call %a, 2i |
| %9:i32 = call %a, 3i |
| %10:i32 = call %a, 1i |
| %11:i32 = call %b, %10, %8, %9 |
| ret %11 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 { |
| %b2 = block { |
| ret 0i |
| } |
| } |
| %c = func():i32 -> %b3 { |
| %b3 = block { |
| %8:i32 = call %a, 2i |
| %9:i32 = let %8 |
| %10:i32 = call %a, 3i |
| %11:i32 = let %10 |
| %12:i32 = call %a, 1i |
| %13:i32 = call %b, %12, %9, %11 |
| ret %13 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, CallSequencedZYX) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn_b = b.Function("b", ty.i32()); |
| b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); }); |
| fn_b->SetParams( |
| {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())}); |
| |
| auto* fn_c = b.Function("c", ty.i32()); |
| b.Append(fn_c->Block(), [&] { |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* call = b.Call(ty.i32(), fn_b, x, y, z); |
| b.Return(fn_c, call); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 { |
| %b2 = block { |
| ret 0i |
| } |
| } |
| %c = func():i32 -> %b3 { |
| %b3 = block { |
| %8:i32 = call %a, 3i |
| %9:i32 = call %a, 2i |
| %10:i32 = call %a, 1i |
| %11:i32 = call %b, %10, %9, %8 |
| ret %11 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 0i |
| } |
| } |
| %b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 { |
| %b2 = block { |
| ret 0i |
| } |
| } |
| %c = func():i32 -> %b3 { |
| %b3 = block { |
| %8:i32 = call %a, 3i |
| %9:i32 = let %8 |
| %10:i32 = call %a, 2i |
| %11:i32 = let %10 |
| %12:i32 = call %a, 1i |
| %13:i32 = call %b, %12, %11, %9 |
| ret %13 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenCallVoidFn_ThenUseLoad) { |
| auto* fn_a = b.Function("a", ty.void_()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a); }); |
| |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* load = b.Load(var); |
| b.Call(ty.void_(), fn_a); |
| b.Return(fn, load); |
| }); |
| |
| auto* src = R"( |
| %a = func():void -> %b1 { |
| %b1 = block { |
| ret |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %3:ptr<function, i32, read_write> = var |
| store %3, 1i |
| %4:i32 = load %3 |
| %5:void = call %a |
| ret %4 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func():void -> %b1 { |
| %b1 = block { |
| ret |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %3:ptr<function, i32, read_write> = var |
| store %3, 1i |
| %4:i32 = load %3 |
| %5:i32 = let %4 |
| %6:void = call %a |
| ret %5 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenCallUnusedi32Fn_ThenUseLoad) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); }); |
| |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* load = b.Load(var); |
| b.Call(ty.i32(), fn_a); |
| b.Return(fn, load); |
| }); |
| |
| auto* src = R"( |
| %a = func():i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %3:ptr<function, i32, read_write> = var |
| store %3, 1i |
| %4:i32 = load %3 |
| %5:i32 = call %a |
| ret %4 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func():i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %3:ptr<function, i32, read_write> = var |
| store %3, 1i |
| %4:i32 = load %3 |
| %5:i32 = let %4 |
| %6:i32 = call %a |
| ret %5 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenCalli32Fn_ThenUseLoadBeforeCall) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); }); |
| |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* load = b.Load(var); |
| auto* call = b.Call(ty.i32(), fn_a); |
| b.Return(fn, b.Add(ty.i32(), load, call)); |
| }); |
| |
| auto* src = R"( |
| %a = func():i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %3:ptr<function, i32, read_write> = var |
| store %3, 1i |
| %4:i32 = load %3 |
| %5:i32 = call %a |
| %6:i32 = add %4, %5 |
| ret %6 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func():i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %3:ptr<function, i32, read_write> = var |
| store %3, 1i |
| %4:i32 = load %3 |
| %5:i32 = call %a |
| %6:i32 = add %4, %5 |
| ret %6 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenCalli32Fn_ThenUseCallBeforeLoad) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); }); |
| |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* load = b.Load(var); |
| auto* call = b.Call(ty.i32(), fn_a); |
| b.Return(fn, b.Add(ty.i32(), call, load)); |
| }); |
| |
| auto* src = R"( |
| %a = func():i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %3:ptr<function, i32, read_write> = var |
| store %3, 1i |
| %4:i32 = load %3 |
| %5:i32 = call %a |
| %6:i32 = add %5, %4 |
| ret %6 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func():i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %3:ptr<function, i32, read_write> = var |
| store %3, 1i |
| %4:i32 = load %3 |
| %5:i32 = let %4 |
| %6:i32 = call %a |
| %7:i32 = add %6, %5 |
| ret %7 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Access |
| //////////////////////////////////////////////////////////////////////////////// |
| TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfArrayOfArray_XYZ) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* arr = b.Var<function, array<array<array<i32, 3>, 4>, 5>>(); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z); |
| b.Return(fn, b.Load(access)); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var |
| %5:i32 = call %a, 1i |
| %6:i32 = call %a, 2i |
| %7:i32 = call %a, 3i |
| %8:ptr<function, i32, read_write> = access %4, %5, %6, %7 |
| %9:i32 = load %8 |
| ret %9 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var |
| %5:i32 = call %a, 1i |
| %6:i32 = call %a, 2i |
| %7:i32 = call %a, 3i |
| %8:ptr<function, i32, read_write> = access %4, %5, %6, %7 |
| %9:i32 = load %8 |
| ret %9 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfArrayOfArray_YXZ) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* arr = b.Var<function, array<array<array<i32, 3>, 4>, 5>>(); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z); |
| b.Return(fn, b.Load(access)); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var |
| %5:i32 = call %a, 2i |
| %6:i32 = call %a, 1i |
| %7:i32 = call %a, 3i |
| %8:ptr<function, i32, read_write> = access %4, %6, %5, %7 |
| %9:i32 = load %8 |
| ret %9 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var |
| %5:i32 = call %a, 2i |
| %6:i32 = let %5 |
| %7:i32 = call %a, 1i |
| %8:i32 = call %a, 3i |
| %9:ptr<function, i32, read_write> = access %4, %7, %6, %8 |
| %10:i32 = load %9 |
| ret %10 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfArrayOfArray_ZXY) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* arr = b.Var<function, array<array<array<i32, 3>, 4>, 5>>(); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z); |
| b.Return(fn, b.Load(access)); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var |
| %5:i32 = call %a, 3i |
| %6:i32 = call %a, 1i |
| %7:i32 = call %a, 2i |
| %8:ptr<function, i32, read_write> = access %4, %6, %7, %5 |
| %9:i32 = load %8 |
| ret %9 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var |
| %5:i32 = call %a, 3i |
| %6:i32 = let %5 |
| %7:i32 = call %a, 1i |
| %8:i32 = call %a, 2i |
| %9:ptr<function, i32, read_write> = access %4, %7, %8, %6 |
| %10:i32 = load %9 |
| ret %10 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfArrayOfArray_ZYX) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* arr = b.Var<function, array<array<array<i32, 3>, 4>, 5>>(); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z); |
| b.Return(fn, b.Load(access)); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var |
| %5:i32 = call %a, 3i |
| %6:i32 = call %a, 2i |
| %7:i32 = call %a, 1i |
| %8:ptr<function, i32, read_write> = access %4, %7, %6, %5 |
| %9:i32 = load %8 |
| ret %9 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():i32 -> %b2 { |
| %b2 = block { |
| %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var |
| %5:i32 = call %a, 3i |
| %6:i32 = let %5 |
| %7:i32 = call %a, 2i |
| %8:i32 = let %7 |
| %9:i32 = call %a, 1i |
| %10:ptr<function, i32, read_write> = access %4, %9, %8, %6 |
| %11:i32 = load %10 |
| ret %11 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfMat3x4f_XYZ) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn = b.Function("f", ty.f32()); |
| b.Append(fn->Block(), [&] { |
| auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>()); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* access = b.Access(ty.f32(), arr, x, y, z); |
| b.Return(fn, access); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():f32 -> %b2 { |
| %b2 = block { |
| %4:array<mat3x4<f32>, 5> = construct |
| %5:i32 = call %a, 1i |
| %6:i32 = call %a, 2i |
| %7:i32 = call %a, 3i |
| %8:f32 = access %4, %5, %6, %7 |
| ret %8 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():f32 -> %b2 { |
| %b2 = block { |
| %4:array<mat3x4<f32>, 5> = construct |
| %5:i32 = call %a, 1i |
| %6:i32 = call %a, 2i |
| %7:i32 = call %a, 3i |
| %8:f32 = access %4, %5, %6, %7 |
| ret %8 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfMat3x4f_YXZ) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn = b.Function("f", ty.f32()); |
| b.Append(fn->Block(), [&] { |
| auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>()); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* access = b.Access(ty.f32(), arr, x, y, z); |
| b.Return(fn, access); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():f32 -> %b2 { |
| %b2 = block { |
| %4:array<mat3x4<f32>, 5> = construct |
| %5:i32 = call %a, 2i |
| %6:i32 = call %a, 1i |
| %7:i32 = call %a, 3i |
| %8:f32 = access %4, %6, %5, %7 |
| ret %8 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():f32 -> %b2 { |
| %b2 = block { |
| %4:array<mat3x4<f32>, 5> = construct |
| %5:i32 = call %a, 2i |
| %6:i32 = let %5 |
| %7:i32 = call %a, 1i |
| %8:i32 = call %a, 3i |
| %9:f32 = access %4, %7, %6, %8 |
| ret %9 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfMat3x4f_ZXY) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn = b.Function("f", ty.f32()); |
| b.Append(fn->Block(), [&] { |
| auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>()); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* access = b.Access(ty.f32(), arr, x, y, z); |
| b.Return(fn, access); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():f32 -> %b2 { |
| %b2 = block { |
| %4:array<mat3x4<f32>, 5> = construct |
| %5:i32 = call %a, 3i |
| %6:i32 = call %a, 1i |
| %7:i32 = call %a, 2i |
| %8:f32 = access %4, %6, %7, %5 |
| ret %8 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():f32 -> %b2 { |
| %b2 = block { |
| %4:array<mat3x4<f32>, 5> = construct |
| %5:i32 = call %a, 3i |
| %6:i32 = let %5 |
| %7:i32 = call %a, 1i |
| %8:i32 = call %a, 2i |
| %9:f32 = access %4, %7, %8, %6 |
| ret %9 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfMat3x4f_ZYX) { |
| auto* fn_a = b.Function("a", ty.i32()); |
| b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); }); |
| fn_a->SetParams({b.FunctionParam(ty.i32())}); |
| |
| auto* fn = b.Function("f", ty.f32()); |
| b.Append(fn->Block(), [&] { |
| auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>()); |
| auto* z = b.Call(ty.i32(), fn_a, 3_i); |
| auto* y = b.Call(ty.i32(), fn_a, 2_i); |
| auto* x = b.Call(ty.i32(), fn_a, 1_i); |
| auto* access = b.Access(ty.f32(), arr, x, y, z); |
| b.Return(fn, access); |
| }); |
| |
| auto* src = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():f32 -> %b2 { |
| %b2 = block { |
| %4:array<mat3x4<f32>, 5> = construct |
| %5:i32 = call %a, 3i |
| %6:i32 = call %a, 2i |
| %7:i32 = call %a, 1i |
| %8:f32 = access %4, %7, %6, %5 |
| ret %8 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %a = func(%2:i32):i32 -> %b1 { |
| %b1 = block { |
| ret 1i |
| } |
| } |
| %f = func():f32 -> %b2 { |
| %b2 = block { |
| %4:array<mat3x4<f32>, 5> = construct |
| %5:i32 = call %a, 3i |
| %6:i32 = let %5 |
| %7:i32 = call %a, 2i |
| %8:i32 = let %7 |
| %9:i32 = call %a, 1i |
| %10:f32 = access %4, %9, %8, %6 |
| ret %10 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // If |
| //////////////////////////////////////////////////////////////////////////////// |
| TEST_F(WgslWriter_ValueToLetTest, UnsequencedOutsideIf) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* v = b.Add(ty.i32(), 1_i, 2_i); |
| auto* if_ = b.If(true); |
| b.Append(if_->True(), [&] { b.Return(fn, v); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:i32 = add 1i, 2i |
| if true [t: %b2] { # if_1 |
| %b2 = block { # true |
| ret %2 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, SequencedOutsideIf) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| var->SetInitializer(b.Constant(1_i)); |
| auto* v_1 = b.Load(var); |
| auto* v_2 = b.Add(ty.i32(), v_1, 2_i); |
| auto* if_ = b.If(true); |
| b.Append(if_->True(), [&] { b.Return(fn, v_2); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var, 1i |
| %3:i32 = load %2 |
| %4:i32 = add %3, 2i |
| if true [t: %b2] { # if_1 |
| %b2 = block { # true |
| ret %4 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var, 1i |
| %3:i32 = load %2 |
| %4:i32 = add %3, 2i |
| %5:i32 = let %4 |
| if true [t: %b2] { # if_1 |
| %b2 = block { # true |
| ret %5 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, UnsequencedUsedByIfCondition) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* v = b.Equal(ty.bool_(), 1_i, 2_i); |
| auto* if_ = b.If(v); |
| b.Append(if_->True(), [&] { b.Return(fn, 3_i); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:bool = eq 1i, 2i |
| if %2 [t: %b2] { # if_1 |
| %b2 = block { # true |
| ret 3i |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:bool = eq 1i, 2i |
| if %2 [t: %b2] { # if_1 |
| %b2 = block { # true |
| ret 3i |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, SequencedUsedByIfCondition) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| var->SetInitializer(b.Constant(1_i)); |
| auto* v_1 = b.Load(var); |
| auto* v_2 = b.Equal(ty.bool_(), v_1, 2_i); |
| auto* if_ = b.If(v_2); |
| b.Append(if_->True(), [&] { b.Return(fn, 3_i); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var, 1i |
| %3:i32 = load %2 |
| %4:bool = eq %3, 2i |
| if %4 [t: %b2] { # if_1 |
| %b2 = block { # true |
| ret 3i |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var, 1i |
| %3:i32 = load %2 |
| %4:bool = eq %3, 2i |
| if %4 [t: %b2] { # if_1 |
| %b2 = block { # true |
| ret 3i |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenWriteToVarInIf_ThenUseLoad) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* load = b.Load(var); |
| auto* if_ = b.If(true); |
| b.Append(if_->True(), [&] { |
| b.Store(var, 2_i); |
| b.ExitIf(if_); |
| }); |
| b.Return(fn, load); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| if true [t: %b2] { # if_1 |
| %b2 = block { # true |
| store %2, 2i |
| exit_if # if_1 |
| } |
| } |
| ret %3 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| %4:i32 = let %3 |
| if true [t: %b2] { # if_1 |
| %b2 = block { # true |
| store %2, 2i |
| exit_if # if_1 |
| } |
| } |
| ret %4 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Switch |
| //////////////////////////////////////////////////////////////////////////////// |
| TEST_F(WgslWriter_ValueToLetTest, UnsequencedOutsideSwitch) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* v = b.Add(ty.i32(), 1_i, 2_i); |
| auto* switch_ = b.Switch(3_i); |
| auto* case_ = b.DefaultCase(switch_); |
| b.Append(case_, [&] { b.Return(fn, v); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:i32 = add 1i, 2i |
| switch 3i [c: (default, %b2)] { # switch_1 |
| %b2 = block { # case |
| ret %2 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, SequencedOutsideSwitch) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| var->SetInitializer(b.Constant(1_i)); |
| auto* v_1 = b.Load(var); |
| auto* v_2 = b.Add(ty.i32(), v_1, 2_i); |
| auto* switch_ = b.Switch(3_i); |
| auto* case_ = b.DefaultCase(switch_); |
| b.Append(case_, [&] { b.Return(fn, v_2); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var, 1i |
| %3:i32 = load %2 |
| %4:i32 = add %3, 2i |
| switch 3i [c: (default, %b2)] { # switch_1 |
| %b2 = block { # case |
| ret %4 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var, 1i |
| %3:i32 = load %2 |
| %4:i32 = add %3, 2i |
| %5:i32 = let %4 |
| switch 3i [c: (default, %b2)] { # switch_1 |
| %b2 = block { # case |
| ret %5 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, UnsequencedUsedBySwitchCondition) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* v = b.Add(ty.i32(), 1_i, 2_i); |
| auto* switch_ = b.Switch(v); |
| auto* case_ = b.DefaultCase(switch_); |
| b.Append(case_, [&] { b.Return(fn, 3_i); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:i32 = add 1i, 2i |
| switch %2 [c: (default, %b2)] { # switch_1 |
| %b2 = block { # case |
| ret 3i |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:i32 = add 1i, 2i |
| switch %2 [c: (default, %b2)] { # switch_1 |
| %b2 = block { # case |
| ret 3i |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, SequencedUsedBySwitchCondition) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| var->SetInitializer(b.Constant(1_i)); |
| auto* v_1 = b.Load(var); |
| auto* switch_ = b.Switch(v_1); |
| auto* case_ = b.DefaultCase(switch_); |
| b.Append(case_, [&] { b.Return(fn, 3_i); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var, 1i |
| %3:i32 = load %2 |
| switch %3 [c: (default, %b2)] { # switch_1 |
| %b2 = block { # case |
| ret 3i |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var, 1i |
| %3:i32 = load %2 |
| switch %3 [c: (default, %b2)] { # switch_1 |
| %b2 = block { # case |
| ret 3i |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenWriteToVarInSwitch_ThenUseLoad) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* load = b.Load(var); |
| auto* switch_ = b.Switch(1_i); |
| auto* case_ = b.DefaultCase(switch_); |
| b.Append(case_, [&] { |
| b.Store(var, 2_i); |
| b.ExitSwitch(switch_); |
| }); |
| b.Return(fn, load); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| switch 1i [c: (default, %b2)] { # switch_1 |
| %b2 = block { # case |
| store %2, 2i |
| exit_switch # switch_1 |
| } |
| } |
| ret %3 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| %4:i32 = let %3 |
| switch 1i [c: (default, %b2)] { # switch_1 |
| %b2 = block { # case |
| store %2, 2i |
| exit_switch # switch_1 |
| } |
| } |
| ret %4 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Loop |
| //////////////////////////////////////////////////////////////////////////////// |
| TEST_F(WgslWriter_ValueToLetTest, UnsequencedOutsideLoopInitializer) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| auto* v = b.Add(ty.i32(), 1_i, 2_i); |
| auto* loop = b.Loop(); |
| b.Append(loop->Initializer(), [&] { |
| b.Store(var, v); |
| b.NextIteration(loop); |
| }); |
| b.Append(loop->Body(), [&] { b.ExitLoop(loop); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| %3:i32 = add 1i, 2i |
| loop [i: %b2, b: %b3] { # loop_1 |
| %b2 = block { # initializer |
| store %2, %3 |
| next_iteration %b3 |
| } |
| %b3 = block { # body |
| exit_loop # loop_1 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, SequencedOutsideLoopInitializer) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| auto* v_1 = b.Load(var); |
| auto* v_2 = b.Add(ty.i32(), v_1, 2_i); |
| auto* loop = b.Loop(); |
| b.Append(loop->Initializer(), [&] { |
| b.Store(var, v_2); |
| b.NextIteration(loop); |
| }); |
| b.Append(loop->Body(), [&] { b.ExitLoop(loop); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| %3:i32 = load %2 |
| %4:i32 = add %3, 2i |
| loop [i: %b2, b: %b3] { # loop_1 |
| %b2 = block { # initializer |
| store %2, %4 |
| next_iteration %b3 |
| } |
| %b3 = block { # body |
| exit_loop # loop_1 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| %3:i32 = load %2 |
| %4:i32 = add %3, 2i |
| %5:i32 = let %4 |
| loop [i: %b2, b: %b3] { # loop_1 |
| %b2 = block { # initializer |
| store %2, %5 |
| next_iteration %b3 |
| } |
| %b3 = block { # body |
| exit_loop # loop_1 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenWriteToVarInLoopInitializer_ThenUseLoad) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* load = b.Load(var); |
| auto* loop = b.Loop(); |
| b.Append(loop->Initializer(), [&] { |
| b.Store(var, 2_i); |
| b.NextIteration(loop); |
| }); |
| b.Append(loop->Body(), [&] { b.ExitLoop(loop); }); |
| b.Return(fn, load); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| loop [i: %b2, b: %b3] { # loop_1 |
| %b2 = block { # initializer |
| store %2, 2i |
| next_iteration %b3 |
| } |
| %b3 = block { # body |
| exit_loop # loop_1 |
| } |
| } |
| ret %3 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| %4:i32 = let %3 |
| loop [i: %b2, b: %b3] { # loop_1 |
| %b2 = block { # initializer |
| store %2, 2i |
| next_iteration %b3 |
| } |
| %b3 = block { # body |
| exit_loop # loop_1 |
| } |
| } |
| ret %4 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, UnsequencedOutsideLoopBody) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* v = b.Add(ty.i32(), 1_i, 2_i); |
| auto* loop = b.Loop(); |
| b.Append(loop->Body(), [&] { b.Return(fn, v); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:i32 = add 1i, 2i |
| loop [b: %b2] { # loop_1 |
| %b2 = block { # body |
| ret %2 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, SequencedOutsideLoopBody) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| auto* v_1 = b.Load(var); |
| auto* v_2 = b.Add(ty.i32(), v_1, 2_i); |
| auto* loop = b.Loop(); |
| b.Append(loop->Body(), [&] { b.Return(fn, v_2); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| %3:i32 = load %2 |
| %4:i32 = add %3, 2i |
| loop [b: %b2] { # loop_1 |
| %b2 = block { # body |
| ret %4 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| %3:i32 = load %2 |
| %4:i32 = add %3, 2i |
| %5:i32 = let %4 |
| loop [b: %b2] { # loop_1 |
| %b2 = block { # body |
| ret %5 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenWriteToVarInLoopBody_ThenUseLoad) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* load = b.Load(var); |
| auto* loop = b.Loop(); |
| b.Append(loop->Body(), [&] { |
| b.Store(var, 2_i); |
| b.ExitLoop(loop); |
| }); |
| b.Return(fn, load); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| loop [b: %b2] { # loop_1 |
| %b2 = block { # body |
| store %2, 2i |
| exit_loop # loop_1 |
| } |
| } |
| ret %3 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| %4:i32 = let %3 |
| loop [b: %b2] { # loop_1 |
| %b2 = block { # body |
| store %2, 2i |
| exit_loop # loop_1 |
| } |
| } |
| ret %4 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, UnsequencedOutsideLoopContinuing) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* v = b.Add(ty.i32(), 1_i, 2_i); |
| auto* loop = b.Loop(); |
| b.Append(loop->Body(), [&] { b.Continue(loop); }); |
| b.Append(loop->Continuing(), [&] { b.BreakIf(loop, b.Equal(ty.bool_(), v, 3_i)); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:i32 = add 1i, 2i |
| loop [b: %b2, c: %b3] { # loop_1 |
| %b2 = block { # body |
| continue %b3 |
| } |
| %b3 = block { # continuing |
| %3:bool = eq %2, 3i |
| break_if %3 %b2 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = src; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, SequencedOutsideLoopContinuing) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| auto* v_1 = b.Load(var); |
| auto* v_2 = b.Add(ty.i32(), v_1, 2_i); |
| auto* loop = b.Loop(); |
| b.Append(loop->Body(), [&] { b.Continue(loop); }); |
| b.Append(loop->Continuing(), [&] { b.BreakIf(loop, b.Equal(ty.bool_(), v_2, 3_i)); }); |
| b.Return(fn, 0_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| %3:i32 = load %2 |
| %4:i32 = add %3, 2i |
| loop [b: %b2, c: %b3] { # loop_1 |
| %b2 = block { # body |
| continue %b3 |
| } |
| %b3 = block { # continuing |
| %5:bool = eq %4, 3i |
| break_if %5 %b2 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| Run(ValueToLet); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| %3:i32 = load %2 |
| %4:i32 = add %3, 2i |
| %5:i32 = let %4 |
| loop [b: %b2, c: %b3] { # loop_1 |
| %b2 = block { # body |
| continue %b3 |
| } |
| %b3 = block { # continuing |
| %6:bool = eq %5, 3i |
| break_if %6 %b2 |
| } |
| } |
| ret 0i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenWriteToVarInLoopContinuing_ThenUseLoad) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* load = b.Load(var); |
| auto* loop = b.Loop(); |
| b.Append(loop->Body(), [&] { b.Continue(loop); }); |
| b.Append(loop->Continuing(), [&] { |
| b.Store(var, 2_i); |
| b.BreakIf(loop, true); |
| }); |
| b.Return(fn, load); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| loop [b: %b2, c: %b3] { # loop_1 |
| %b2 = block { # body |
| continue %b3 |
| } |
| %b3 = block { # continuing |
| store %2, 2i |
| break_if true %b2 |
| } |
| } |
| ret %3 |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| %3:i32 = load %2 |
| %4:i32 = let %3 |
| loop [b: %b2, c: %b3] { # loop_1 |
| %b2 = block { # body |
| continue %b3 |
| } |
| %b3 = block { # continuing |
| store %2, 2i |
| break_if true %b2 |
| } |
| } |
| ret %4 |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVarInLoopInitializer_ThenReadAndWriteToVarInLoopBody) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* loop = b.Loop(); |
| b.Append(loop->Initializer(), [&] { |
| auto* load = b.Load(var); |
| b.NextIteration(loop); |
| b.Append(loop->Body(), [&] { |
| b.Store(var, b.Add(ty.i32(), load, 1_i)); |
| b.ExitLoop(loop); |
| }); |
| }); |
| b.Return(fn, 3_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| loop [i: %b2, b: %b3] { # loop_1 |
| %b2 = block { # initializer |
| %3:i32 = load %2 |
| next_iteration %b3 |
| } |
| %b3 = block { # body |
| %4:i32 = add %3, 1i |
| store %2, %4 |
| exit_loop # loop_1 |
| } |
| } |
| ret 3i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| loop [i: %b2, b: %b3] { # loop_1 |
| %b2 = block { # initializer |
| %3:i32 = load %2 |
| %4:i32 = let %3 |
| next_iteration %b3 |
| } |
| %b3 = block { # body |
| %5:i32 = add %4, 1i |
| store %2, %5 |
| exit_loop # loop_1 |
| } |
| } |
| ret 3i |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVarInLoopInitializer_ThenReadAndWriteToVarInLoopContinuing) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* loop = b.Loop(); |
| b.Append(loop->Initializer(), [&] { |
| auto* load = b.Load(var); |
| b.NextIteration(loop); |
| b.Append(loop->Body(), [&] { b.Continue(loop); }); |
| b.Append(loop->Continuing(), [&] { |
| b.Store(var, b.Add(ty.i32(), load, 1_i)); |
| b.BreakIf(loop, true); |
| }); |
| }); |
| b.Return(fn, 3_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| loop [i: %b2, b: %b3, c: %b4] { # loop_1 |
| %b2 = block { # initializer |
| %3:i32 = load %2 |
| next_iteration %b3 |
| } |
| %b3 = block { # body |
| continue %b4 |
| } |
| %b4 = block { # continuing |
| %4:i32 = add %3, 1i |
| store %2, %4 |
| break_if true %b3 |
| } |
| } |
| ret 3i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| loop [i: %b2, b: %b3, c: %b4] { # loop_1 |
| %b2 = block { # initializer |
| %3:i32 = load %2 |
| %4:i32 = let %3 |
| next_iteration %b3 |
| } |
| %b3 = block { # body |
| continue %b4 |
| } |
| %b4 = block { # continuing |
| %5:i32 = add %4, 1i |
| store %2, %5 |
| break_if true %b3 |
| } |
| } |
| ret 3i |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| TEST_F(WgslWriter_ValueToLetTest, LoadVarInLoopBody_ThenReadAndWriteToVarInLoopContinuing) { |
| auto* fn = b.Function("f", ty.i32()); |
| b.Append(fn->Block(), [&] { |
| auto* var = b.Var<function, i32>(); |
| b.Store(var, 1_i); |
| auto* loop = b.Loop(); |
| b.Append(loop->Body(), [&] { |
| auto* load = b.Load(var); |
| b.Continue(loop); |
| |
| b.Append(loop->Continuing(), [&] { |
| b.Store(var, b.Add(ty.i32(), load, 1_i)); |
| b.BreakIf(loop, true); |
| }); |
| }); |
| b.Return(fn, 3_i); |
| }); |
| |
| auto* src = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| loop [b: %b2, c: %b3] { # loop_1 |
| %b2 = block { # body |
| %3:i32 = load %2 |
| continue %b3 |
| } |
| %b3 = block { # continuing |
| %4:i32 = add %3, 1i |
| store %2, %4 |
| break_if true %b2 |
| } |
| } |
| ret 3i |
| } |
| } |
| )"; |
| |
| EXPECT_EQ(src, str()); |
| |
| auto* expect = R"( |
| %f = func():i32 -> %b1 { |
| %b1 = block { |
| %2:ptr<function, i32, read_write> = var |
| store %2, 1i |
| loop [b: %b2, c: %b3] { # loop_1 |
| %b2 = block { # body |
| %3:i32 = load %2 |
| %4:i32 = let %3 |
| continue %b3 |
| } |
| %b3 = block { # continuing |
| %5:i32 = add %4, 1i |
| store %2, %5 |
| break_if true %b2 |
| } |
| } |
| ret 3i |
| } |
| } |
| )"; |
| |
| Run(ValueToLet); |
| |
| EXPECT_EQ(expect, str()); |
| } |
| |
| } // namespace |
| } // namespace tint::wgsl::writer::raise |