diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index 461556dac1..b59fa37d4d 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -508,8 +508,8 @@ libtint_source_set("libtint_core_all_src") { "transform/multiplanar_external_texture.h", "transform/num_workgroups_from_uniform.cc", "transform/num_workgroups_from_uniform.h", - "transform/promote_initializers_to_const_var.cc", - "transform/promote_initializers_to_const_var.h", + "transform/promote_initializers_to_let.cc", + "transform/promote_initializers_to_let.h", "transform/promote_side_effects_to_decl.cc", "transform/promote_side_effects_to_decl.h", "transform/remove_continue_in_switch.cc", @@ -1183,7 +1183,7 @@ if (tint_build_unittests) { "transform/module_scope_var_to_entry_point_param_test.cc", "transform/multiplanar_external_texture_test.cc", "transform/num_workgroups_from_uniform_test.cc", - "transform/promote_initializers_to_const_var_test.cc", + "transform/promote_initializers_to_let_test.cc", "transform/promote_side_effects_to_decl_test.cc", "transform/remove_continue_in_switch_test.cc", "transform/remove_phonies_test.cc", diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index 32359b5236..50f586e801 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -432,8 +432,8 @@ set(TINT_LIB_SRCS transform/multiplanar_external_texture.h transform/num_workgroups_from_uniform.cc transform/num_workgroups_from_uniform.h - transform/promote_initializers_to_const_var.cc - transform/promote_initializers_to_const_var.h + transform/promote_initializers_to_let.cc + transform/promote_initializers_to_let.h transform/promote_side_effects_to_decl.cc transform/promote_side_effects_to_decl.h transform/remove_continue_in_switch.cc @@ -1106,7 +1106,7 @@ if(TINT_BUILD_TESTS) transform/module_scope_var_to_entry_point_param_test.cc transform/multiplanar_external_texture_test.cc transform/num_workgroups_from_uniform_test.cc - transform/promote_initializers_to_const_var_test.cc + transform/promote_initializers_to_let_test.cc transform/promote_side_effects_to_decl_test.cc transform/remove_continue_in_switch_test.cc transform/remove_phonies_test.cc diff --git a/src/tint/transform/promote_initializers_to_const_var_test.cc b/src/tint/transform/promote_initializers_to_const_var_test.cc deleted file mode 100644 index f322478ce0..0000000000 --- a/src/tint/transform/promote_initializers_to_const_var_test.cc +++ /dev/null @@ -1,625 +0,0 @@ -// Copyright 2021 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/promote_initializers_to_const_var.h" - -#include "src/tint/transform/test_helper.h" - -namespace tint::transform { -namespace { - -using PromoteInitializersToConstVarTest = TransformTest; - -TEST_F(PromoteInitializersToConstVarTest, EmptyModule) { - auto* src = ""; - auto* expect = ""; - - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, BasicArray) { - auto* src = R"( -fn f() { - var f0 = 1.0; - var f1 = 2.0; - var f2 = 3.0; - var f3 = 4.0; - var i = array(f0, f1, f2, f3)[2]; -} -)"; - - auto* expect = R"( -fn f() { - var f0 = 1.0; - var f1 = 2.0; - var f2 = 3.0; - var f3 = 4.0; - let tint_symbol = array(f0, f1, f2, f3); - var i = tint_symbol[2]; -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, BasicStruct) { - auto* src = R"( -struct S { - a : i32, - b : f32, - c : vec3, -}; - -fn f() { - var x = S(1, 2.0, vec3()).b; -} -)"; - - auto* expect = R"( -struct S { - a : i32, - b : f32, - c : vec3, -} - -fn f() { - let tint_symbol = S(1, 2.0, vec3()); - var x = tint_symbol.b; -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, BasicStruct_OutOfOrder) { - auto* src = R"( -fn f() { - var x = S(1, 2.0, vec3()).b; -} - -struct S { - a : i32, - b : f32, - c : vec3, -}; -)"; - - auto* expect = R"( -fn f() { - let tint_symbol = S(1, 2.0, vec3()); - var x = tint_symbol.b; -} - -struct S { - a : i32, - b : f32, - c : vec3, -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopInit) { - auto* src = R"( -fn f() { - var insert_after = 1; - for(var i = array(0.0, 1.0, 2.0, 3.0)[2]; ; ) { - break; - } -} -)"; - - auto* expect = R"( -fn f() { - var insert_after = 1; - let tint_symbol = array(0.0, 1.0, 2.0, 3.0); - for(var i = tint_symbol[2]; ; ) { - break; - } -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, StructInForLoopInit) { - auto* src = R"( -struct S { - a : i32, - b : f32, - c : vec3, -}; - -fn f() { - var insert_after = 1; - for(var x = S(1, 2.0, vec3()).b; ; ) { - break; - } -} -)"; - - auto* expect = R"( -struct S { - a : i32, - b : f32, - c : vec3, -} - -fn f() { - var insert_after = 1; - let tint_symbol = S(1, 2.0, vec3()); - for(var x = tint_symbol.b; ; ) { - break; - } -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, StructInForLoopInit_OutOfOrder) { - auto* src = R"( -fn f() { - var insert_after = 1; - for(var x = S(1, 2.0, vec3()).b; ; ) { - break; - } -} - -struct S { - a : i32, - b : f32, - c : vec3, -}; -)"; - - auto* expect = R"( -fn f() { - var insert_after = 1; - let tint_symbol = S(1, 2.0, vec3()); - for(var x = tint_symbol.b; ; ) { - break; - } -} - -struct S { - a : i32, - b : f32, - c : vec3, -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopCond) { - auto* src = R"( -fn f() { - var f = 1.0; - for(; f == array(f)[0]; f = f + 1.0) { - var marker = 1; - } -} -)"; - - auto* expect = R"( -fn f() { - var f = 1.0; - loop { - let tint_symbol = array(f); - if (!((f == tint_symbol[0]))) { - break; - } - { - var marker = 1; - } - - continuing { - f = (f + 1.0); - } - } -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopCont) { - auto* src = R"( -fn f() { - var f = 0.0; - for(; f < 10.0; f = f + array(1.0)[0]) { - var marker = 1; - } -} -)"; - - auto* expect = R"( -fn f() { - var f = 0.0; - loop { - if (!((f < 10.0))) { - break; - } - { - var marker = 1; - } - - continuing { - let tint_symbol = array(1.0); - f = (f + tint_symbol[0]); - } - } -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopInitCondCont) { - auto* src = R"( -fn f() { - for(var f = array(0.0)[0]; - f < array(1.0)[0]; - f = f + array(2.0)[0]) { - var marker = 1; - } -} -)"; - - auto* expect = R"( -fn f() { - let tint_symbol = array(0.0); - { - var f = tint_symbol[0]; - loop { - let tint_symbol_1 = array(1.0); - if (!((f < tint_symbol_1[0]))) { - break; - } - { - var marker = 1; - } - - continuing { - let tint_symbol_2 = array(2.0); - f = (f + tint_symbol_2[0]); - } - } - } -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, ArrayInElseIf) { - auto* src = R"( -fn f() { - var f = 1.0; - if (true) { - var marker = 0; - } else if (f == array(f, f)[0]) { - var marker = 1; - } -} -)"; - - auto* expect = R"( -fn f() { - var f = 1.0; - if (true) { - var marker = 0; - } else { - let tint_symbol = array(f, f); - if ((f == tint_symbol[0])) { - var marker = 1; - } - } -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, ArrayInElseIfChain) { - auto* src = R"( -fn f() { - var f = 1.0; - if (true) { - var marker = 0; - } else if (true) { - var marker = 1; - } else if (f == array(f, f)[0]) { - var marker = 2; - } else if (f == array(f, f)[1]) { - var marker = 3; - } else if (true) { - var marker = 4; - } else { - var marker = 5; - } -} -)"; - - auto* expect = R"( -fn f() { - var f = 1.0; - if (true) { - var marker = 0; - } else if (true) { - var marker = 1; - } else { - let tint_symbol = array(f, f); - if ((f == tint_symbol[0])) { - var marker = 2; - } else { - let tint_symbol_1 = array(f, f); - if ((f == tint_symbol_1[1])) { - var marker = 3; - } else if (true) { - var marker = 4; - } else { - var marker = 5; - } - } - } -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, ArrayInArrayArray) { - auto* src = R"( -fn f() { - var i = array, 2u>(array(1.0, 2.0), array(3.0, 4.0))[0][1]; -} -)"; - - auto* expect = R"( -fn f() { - let tint_symbol = array(1.0, 2.0); - let tint_symbol_1 = array(3.0, 4.0); - let tint_symbol_2 = array, 2u>(tint_symbol, tint_symbol_1); - var i = tint_symbol_2[0][1]; -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, StructNested) { - auto* src = R"( -struct S1 { - a : i32, -}; - -struct S2 { - a : i32, - b : S1, - c : i32, -}; - -struct S3 { - a : S2, -}; - -fn f() { - var x = S3(S2(1, S1(2), 3)).a.b.a; -} -)"; - - auto* expect = R"( -struct S1 { - a : i32, -} - -struct S2 { - a : i32, - b : S1, - c : i32, -} - -struct S3 { - a : S2, -} - -fn f() { - let tint_symbol = S1(2); - let tint_symbol_1 = S2(1, tint_symbol, 3); - let tint_symbol_2 = S3(tint_symbol_1); - var x = tint_symbol_2.a.b.a; -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, Mixed) { - auto* src = R"( -struct S1 { - a : i32, -}; - -struct S2 { - a : array, -}; - -fn f() { - var x = S2(array(S1(1), S1(2), S1(3))).a[1].a; -} -)"; - - auto* expect = R"( -struct S1 { - a : i32, -} - -struct S2 { - a : array, -} - -fn f() { - let tint_symbol = S1(1); - let tint_symbol_1 = S1(2); - let tint_symbol_2 = S1(3); - let tint_symbol_3 = array(tint_symbol, tint_symbol_1, tint_symbol_2); - let tint_symbol_4 = S2(tint_symbol_3); - var x = tint_symbol_4.a[1].a; -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, Mixed_OutOfOrder) { - auto* src = R"( -fn f() { - var x = S2(array(S1(1), S1(2), S1(3))).a[1].a; -} - -struct S2 { - a : array, -}; - -struct S1 { - a : i32, -}; -)"; - - auto* expect = R"( -fn f() { - let tint_symbol = S1(1); - let tint_symbol_1 = S1(2); - let tint_symbol_2 = S1(3); - let tint_symbol_3 = array(tint_symbol, tint_symbol_1, tint_symbol_2); - let tint_symbol_4 = S2(tint_symbol_3); - var x = tint_symbol_4.a[1].a; -} - -struct S2 { - a : array, -} - -struct S1 { - a : i32, -} -)"; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, NoChangeOnVarDecl) { - auto* src = R"( -struct S { - a : i32, - b : f32, - c : i32, -} - -fn f() { - var local_arr = array(0.0, 1.0, 2.0, 3.0); - var local_str = S(1, 2.0, 3); -} - -let module_arr : array = array(0.0, 1.0, 2.0, 3.0); - -let module_str : S = S(1, 2.0, 3); -)"; - - auto* expect = src; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -TEST_F(PromoteInitializersToConstVarTest, NoChangeOnVarDecl_OutOfOrder) { - auto* src = R"( -fn f() { - var local_arr = array(0.0, 1.0, 2.0, 3.0); - var local_str = S(1, 2.0, 3); -} - -let module_str : S = S(1, 2.0, 3); - -struct S { - a : i32, - b : f32, - c : i32, -} - -let module_arr : array = array(0.0, 1.0, 2.0, 3.0); -)"; - - auto* expect = src; - - DataMap data; - auto got = Run(src); - - EXPECT_EQ(expect, str(got)); -} - -} // namespace -} // namespace tint::transform diff --git a/src/tint/transform/promote_initializers_to_const_var.cc b/src/tint/transform/promote_initializers_to_let.cc similarity index 50% rename from src/tint/transform/promote_initializers_to_const_var.cc rename to src/tint/transform/promote_initializers_to_let.cc index 6e0ba55ccc..b57fb257ea 100644 --- a/src/tint/transform/promote_initializers_to_const_var.cc +++ b/src/tint/transform/promote_initializers_to_let.cc @@ -12,32 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "src/tint/transform/promote_initializers_to_const_var.h" +#include "src/tint/transform/promote_initializers_to_let.h" #include "src/tint/program_builder.h" #include "src/tint/sem/call.h" #include "src/tint/sem/statement.h" #include "src/tint/sem/type_constructor.h" #include "src/tint/transform/utils/hoist_to_decl_before.h" -TINT_INSTANTIATE_TYPEINFO(tint::transform::PromoteInitializersToConstVar); +TINT_INSTANTIATE_TYPEINFO(tint::transform::PromoteInitializersToLet); namespace tint::transform { -PromoteInitializersToConstVar::PromoteInitializersToConstVar() = default; +PromoteInitializersToLet::PromoteInitializersToLet() = default; -PromoteInitializersToConstVar::~PromoteInitializersToConstVar() = default; +PromoteInitializersToLet::~PromoteInitializersToLet() = default; -void PromoteInitializersToConstVar::Run(CloneContext& ctx, const DataMap&, DataMap&) const { +void PromoteInitializersToLet::Run(CloneContext& ctx, const DataMap&, DataMap&) const { HoistToDeclBefore hoist_to_decl_before(ctx); // Hoists array and structure initializers to a constant variable, declared // just before the statement of usage. - auto type_ctor_to_let = [&](const ast::CallExpression* expr) { - auto* ctor = ctx.src->Sem().Get(expr)->UnwrapMaterialize()->As(); - if (!ctor->Target()->Is()) { - return true; - } - auto* sem_stmt = ctor->Stmt(); + auto promote = [&](const sem::Expression* expr) { + auto* sem_stmt = expr->Stmt(); if (!sem_stmt) { // Expression is outside of a statement. This usually means the // expression is part of a global (module-scope) constant declaration. @@ -49,7 +45,7 @@ void PromoteInitializersToConstVar::Run(CloneContext& ctx, const DataMap&, DataM auto* stmt = sem_stmt->Declaration(); if (auto* src_var_decl = stmt->As()) { - if (src_var_decl->variable->constructor == expr) { + if (src_var_decl->variable->constructor == expr->Declaration()) { // This statement is just a variable declaration with the // initializer as the constructor value. This is what we're // attempting to transform to, and so ignore. @@ -57,20 +53,49 @@ void PromoteInitializersToConstVar::Run(CloneContext& ctx, const DataMap&, DataM } } - auto* src_ty = ctor->Type(); + auto* src_ty = expr->Type(); if (!src_ty->IsAnyOf()) { // We only care about array and struct initializers return true; } - return hoist_to_decl_before.Add(ctor, expr, true); + return hoist_to_decl_before.Add(expr, expr->Declaration(), true); }; for (auto* node : ctx.src->ASTNodes().Objects()) { - if (auto* call_expr = node->As()) { - if (!type_ctor_to_let(call_expr)) { - return; - } + bool ok = Switch( + node, // + [&](const ast::CallExpression* expr) { + if (auto* sem = ctx.src->Sem().Get(expr)) { + auto* ctor = sem->UnwrapMaterialize()->As(); + if (ctor->Target()->Is()) { + return promote(sem); + } + } + return true; + }, + [&](const ast::IdentifierExpression* expr) { + if (auto* user = ctx.src->Sem().Get(expr)) { + // Identifier resolves to a variable + if (auto* stmt = user->Stmt()) { + if (auto* decl = stmt->Declaration()->As(); + decl && decl->variable->Is()) { + // The identifier is used on the RHS of a 'const' declaration. Ignore. + return true; + } + } + if (user->Variable()->Declaration()->Is()) { + // The identifier resolves to a 'const' variable, but isn't used to + // initialize another 'const'. This needs promoting. + return promote(user); + } + } + return true; + }, + [&](Default) { return true; }); + + if (!ok) { + return; } } diff --git a/src/tint/transform/promote_initializers_to_const_var.h b/src/tint/transform/promote_initializers_to_let.h similarity index 63% rename from src/tint/transform/promote_initializers_to_const_var.h rename to src/tint/transform/promote_initializers_to_let.h index 67a32c48b8..41f99d7b37 100644 --- a/src/tint/transform/promote_initializers_to_const_var.h +++ b/src/tint/transform/promote_initializers_to_let.h @@ -12,23 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_CONST_VAR_H_ -#define SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_CONST_VAR_H_ +#ifndef SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_LET_H_ +#define SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_LET_H_ #include "src/tint/transform/transform.h" namespace tint::transform { -/// A transform that hoists the array and structure initializers to a constant -/// variable, declared just before the statement of usage. +/// A transform that hoists array and structure constructors, and identifiers resolving to a +/// 'const' array to a 'let' variable, declared just before the statement of usage. +/// This transform is used by backends that do not support expressions that operate on an immediate +/// array or structure. For example, the following is not immediately expressable for HLSL: +/// `array(1, 2)[0]` /// @see crbug.com/tint/406 -class PromoteInitializersToConstVar : public Castable { +class PromoteInitializersToLet : public Castable { public: /// Constructor - PromoteInitializersToConstVar(); + PromoteInitializersToLet(); /// Destructor - ~PromoteInitializersToConstVar() override; + ~PromoteInitializersToLet() override; protected: /// Runs the transform using the CloneContext built for transforming a @@ -42,4 +45,4 @@ class PromoteInitializersToConstVar : public Castable(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, BasicArray) { + auto* src = R"( +fn f() { + var f0 = 1.0; + var f1 = 2.0; + var f2 = 3.0; + var f3 = 4.0; + var i = array(f0, f1, f2, f3)[2]; +} +)"; + + auto* expect = R"( +fn f() { + var f0 = 1.0; + var f1 = 2.0; + var f2 = 3.0; + var f3 = 4.0; + let tint_symbol = array(f0, f1, f2, f3); + var i = tint_symbol[2]; +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, BasicStruct) { + auto* src = R"( +struct S { + a : i32, + b : f32, + c : vec3, +}; + +fn f() { + var x = S(1, 2.0, vec3()).b; +} +)"; + + auto* expect = R"( +struct S { + a : i32, + b : f32, + c : vec3, +} + +fn f() { + let tint_symbol = S(1, 2.0, vec3()); + var x = tint_symbol.b; +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, BasicStruct_OutOfOrder) { + auto* src = R"( +fn f() { + var x = S(1, 2.0, vec3()).b; +} + +struct S { + a : i32, + b : f32, + c : vec3, +}; +)"; + + auto* expect = R"( +fn f() { + let tint_symbol = S(1, 2.0, vec3()); + var x = tint_symbol.b; +} + +struct S { + a : i32, + b : f32, + c : vec3, +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, GlobalConstBasicArray) { + auto* src = R"( +const f0 = 1.0; + +const f1 = 2.0; + +const C = array(f0, f1); + +fn f() { + var f0 = 100.0; + var f1 = 100.0; + var i = C[1]; +} +)"; + + auto* expect = R"( +const f0 = 1.0; + +const f1 = 2.0; + +const C = array(f0, f1); + +fn f() { + var f0 = 100.0; + var f1 = 100.0; + let tint_symbol = C; + var i = tint_symbol[1]; +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, GlobalConstBasicArray_OutOfOrder) { + auto* src = R"( +fn f() { + var f0 = 100.0; + var f1 = 100.0; + var i = C[1]; +} + +const C = array(f0, f1); + +const f0 = 1.0; + +const f1 = 2.0; +)"; + + auto* expect = R"( +fn f() { + var f0 = 100.0; + var f1 = 100.0; + let tint_symbol = C; + var i = tint_symbol[1]; +} + +const C = array(f0, f1); + +const f0 = 1.0; + +const f1 = 2.0; +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, LocalConstBasicArray) { + auto* src = R"( +fn f() { + const f0 = 1.0; + const f1 = 2.0; + const C = array(f0, f1); + var i = C[1]; +} +)"; + + auto* expect = R"( +fn f() { + const f0 = 1.0; + const f1 = 2.0; + const C = array(f0, f1); + let tint_symbol = C; + var i = tint_symbol[1]; +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, ArrayInForLoopInit) { + auto* src = R"( +fn f() { + var insert_after = 1; + for(var i = array(0.0, 1.0, 2.0, 3.0)[2]; ; ) { + break; + } +} +)"; + + auto* expect = R"( +fn f() { + var insert_after = 1; + let tint_symbol = array(0.0, 1.0, 2.0, 3.0); + for(var i = tint_symbol[2]; ; ) { + break; + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopInit) { + auto* src = R"( +fn f() { + const arr = array(0.0, 1.0, 2.0, 3.0); + var insert_after = 1; + for(var i = arr[2]; ; ) { + break; + } +} +)"; + + auto* expect = R"( +fn f() { + const arr = array(0.0, 1.0, 2.0, 3.0); + var insert_after = 1; + let tint_symbol = arr; + for(var i = tint_symbol[2]; ; ) { + break; + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInForLoopInit) { + auto* src = R"( +const arr = array(0.0, 1.0, 2.0, 3.0); + +fn f() { + var insert_after = 1; + for(var i = arr[2]; ; ) { + break; + } +} +)"; + + auto* expect = R"( +const arr = array(0.0, 1.0, 2.0, 3.0); + +fn f() { + var insert_after = 1; + let tint_symbol = arr; + for(var i = tint_symbol[2]; ; ) { + break; + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, StructInForLoopInit) { + auto* src = R"( +struct S { + a : i32, + b : f32, + c : vec3, +}; + +fn f() { + var insert_after = 1; + for(var x = S(1, 2.0, vec3()).b; ; ) { + break; + } +} +)"; + + auto* expect = R"( +struct S { + a : i32, + b : f32, + c : vec3, +} + +fn f() { + var insert_after = 1; + let tint_symbol = S(1, 2.0, vec3()); + for(var x = tint_symbol.b; ; ) { + break; + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, StructInForLoopInit_OutOfOrder) { + auto* src = R"( +fn f() { + var insert_after = 1; + for(var x = S(1, 2.0, vec3()).b; ; ) { + break; + } +} + +struct S { + a : i32, + b : f32, + c : vec3, +}; +)"; + + auto* expect = R"( +fn f() { + var insert_after = 1; + let tint_symbol = S(1, 2.0, vec3()); + for(var x = tint_symbol.b; ; ) { + break; + } +} + +struct S { + a : i32, + b : f32, + c : vec3, +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, ArrayInForLoopCond) { + auto* src = R"( +fn f() { + var f = 1.0; + for(; f == array(f)[0]; f = f + 1.0) { + var marker = 1; + } +} +)"; + + auto* expect = R"( +fn f() { + var f = 1.0; + loop { + let tint_symbol = array(f); + if (!((f == tint_symbol[0]))) { + break; + } + { + var marker = 1; + } + + continuing { + f = (f + 1.0); + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopCond) { + auto* src = R"( +fn f() { + const f = 1.0; + const arr = array(f); + for(var i = f; i == arr[0]; i = i + 1.0) { + var marker = 1; + } +} +)"; + + auto* expect = R"( +fn f() { + const f = 1.0; + const arr = array(f); + { + var i = f; + loop { + let tint_symbol = arr; + if (!((i == tint_symbol[0]))) { + break; + } + { + var marker = 1; + } + + continuing { + i = (i + 1.0); + } + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInForLoopCond) { + auto* src = R"( +const f = 1.0; + +const arr = array(f); + +fn F() { + for(var i = f; i == arr[0]; i = i + 1.0) { + var marker = 1; + } +} +)"; + + auto* expect = R"( +const f = 1.0; + +const arr = array(f); + +fn F() { + { + var i = f; + loop { + let tint_symbol = arr; + if (!((i == tint_symbol[0]))) { + break; + } + { + var marker = 1; + } + + continuing { + i = (i + 1.0); + } + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, ArrayInForLoopCont) { + auto* src = R"( +fn f() { + var f = 0.0; + for(; f < 10.0; f = f + array(1.0)[0]) { + var marker = 1; + } +} +)"; + + auto* expect = R"( +fn f() { + var f = 0.0; + loop { + if (!((f < 10.0))) { + break; + } + { + var marker = 1; + } + + continuing { + let tint_symbol = array(1.0); + f = (f + tint_symbol[0]); + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopCont) { + auto* src = R"( +fn f() { + const arr = array(1.0); + var f = 0.0; + for(; f < 10.0; f = f + arr[0]) { + var marker = 1; + } +} +)"; + + auto* expect = R"( +fn f() { + const arr = array(1.0); + var f = 0.0; + loop { + if (!((f < 10.0))) { + break; + } + { + var marker = 1; + } + + continuing { + let tint_symbol = arr; + f = (f + tint_symbol[0]); + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInForLoopCont) { + auto* src = R"( +const arr = array(1.0); + +fn f() { + var f = 0.0; + for(; f < 10.0; f = f + arr[0]) { + var marker = 1; + } +} +)"; + + auto* expect = R"( +const arr = array(1.0); + +fn f() { + var f = 0.0; + loop { + if (!((f < 10.0))) { + break; + } + { + var marker = 1; + } + + continuing { + let tint_symbol = arr; + f = (f + tint_symbol[0]); + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, ArrayInForLoopInitCondCont) { + auto* src = R"( +fn f() { + for(var f = array(0.0)[0]; + f < array(1.0)[0]; + f = f + array(2.0)[0]) { + var marker = 1; + } +} +)"; + + auto* expect = R"( +fn f() { + let tint_symbol = array(0.0); + { + var f = tint_symbol[0]; + loop { + let tint_symbol_1 = array(1.0); + if (!((f < tint_symbol_1[0]))) { + break; + } + { + var marker = 1; + } + + continuing { + let tint_symbol_2 = array(2.0); + f = (f + tint_symbol_2[0]); + } + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopInitCondCont) { + auto* src = R"( +fn f() { + const arr_a = array(0.0); + const arr_b = array(1.0); + const arr_c = array(2.0); + for(var f = arr_a[0]; f < arr_b[0]; f = f + arr_c[0]) { + var marker = 1; + } +} +)"; + + auto* expect = R"( +fn f() { + const arr_a = array(0.0); + const arr_b = array(1.0); + const arr_c = array(2.0); + let tint_symbol = arr_a; + { + var f = tint_symbol[0]; + loop { + let tint_symbol_1 = arr_b; + if (!((f < tint_symbol_1[0]))) { + break; + } + { + var marker = 1; + } + + continuing { + let tint_symbol_2 = arr_c; + f = (f + tint_symbol_2[0]); + } + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, ArrayInElseIf) { + auto* src = R"( +fn f() { + var f = 1.0; + if (true) { + var marker = 0; + } else if (f == array(f, f)[0]) { + var marker = 1; + } +} +)"; + + auto* expect = R"( +fn f() { + var f = 1.0; + if (true) { + var marker = 0; + } else { + let tint_symbol = array(f, f); + if ((f == tint_symbol[0])) { + var marker = 1; + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, ArrayInElseIfChain) { + auto* src = R"( +fn f() { + var f = 1.0; + if (true) { + var marker = 0; + } else if (true) { + var marker = 1; + } else if (f == array(f, f)[0]) { + var marker = 2; + } else if (f == array(f, f)[1]) { + var marker = 3; + } else if (true) { + var marker = 4; + } else { + var marker = 5; + } +} +)"; + + auto* expect = R"( +fn f() { + var f = 1.0; + if (true) { + var marker = 0; + } else if (true) { + var marker = 1; + } else { + let tint_symbol = array(f, f); + if ((f == tint_symbol[0])) { + var marker = 2; + } else { + let tint_symbol_1 = array(f, f); + if ((f == tint_symbol_1[1])) { + var marker = 3; + } else if (true) { + var marker = 4; + } else { + var marker = 5; + } + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, LocalConstArrayInElseIfChain) { + auto* src = R"( +fn f() { + const f = 1.0; + const arr = array(f, f); + if (true) { + var marker = 0; + } else if (true) { + var marker = 1; + } else if (f == arr[0]) { + var marker = 2; + } else if (f == arr[1]) { + var marker = 3; + } else if (true) { + var marker = 4; + } else { + var marker = 5; + } +} +)"; + + auto* expect = R"( +fn f() { + const f = 1.0; + const arr = array(f, f); + if (true) { + var marker = 0; + } else if (true) { + var marker = 1; + } else { + let tint_symbol = arr; + if ((f == tint_symbol[0])) { + var marker = 2; + } else { + let tint_symbol_1 = arr; + if ((f == tint_symbol_1[1])) { + var marker = 3; + } else if (true) { + var marker = 4; + } else { + var marker = 5; + } + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInElseIfChain) { + auto* src = R"( +const f = 1.0; + +const arr = array(f, f); + +fn F() { + if (true) { + var marker = 0; + } else if (true) { + var marker = 1; + } else if (f == arr[0]) { + var marker = 2; + } else if (f == arr[1]) { + var marker = 3; + } else if (true) { + var marker = 4; + } else { + var marker = 5; + } +} +)"; + + auto* expect = R"( +const f = 1.0; + +const arr = array(f, f); + +fn F() { + if (true) { + var marker = 0; + } else if (true) { + var marker = 1; + } else { + let tint_symbol = arr; + if ((f == tint_symbol[0])) { + var marker = 2; + } else { + let tint_symbol_1 = arr; + if ((f == tint_symbol_1[1])) { + var marker = 3; + } else if (true) { + var marker = 4; + } else { + var marker = 5; + } + } + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, ArrayInArrayArray) { + auto* src = R"( +fn f() { + var i = array, 2u>(array(1.0, 2.0), array(3.0, 4.0))[0][1]; +} +)"; + + auto* expect = R"( +fn f() { + let tint_symbol = array(1.0, 2.0); + let tint_symbol_1 = array(3.0, 4.0); + let tint_symbol_2 = array, 2u>(tint_symbol, tint_symbol_1); + var i = tint_symbol_2[0][1]; +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, LocalConstArrayInArrayArray) { + auto* src = R"( +fn f() { + const arr_0 = array(1.0, 2.0); + const arr_1 = array(3.0, 4.0); + const arr_2 = array, 2u>(arr_0, arr_1); + var i = arr_2[0][1]; +} +)"; + + auto* expect = R"( +fn f() { + const arr_0 = array(1.0, 2.0); + const arr_1 = array(3.0, 4.0); + const arr_2 = array, 2u>(arr_0, arr_1); + let tint_symbol = arr_2; + var i = tint_symbol[0][1]; +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInArrayArray) { + auto* src = R"( +const arr_0 = array(1.0, 2.0); + +const arr_1 = array(3.0, 4.0); + +const arr_2 = array, 2u>(arr_0, arr_1); + +fn f() { + var i = arr_2[0][1]; +} +)"; + + auto* expect = R"( +const arr_0 = array(1.0, 2.0); + +const arr_1 = array(3.0, 4.0); + +const arr_2 = array, 2u>(arr_0, arr_1); + +fn f() { + let tint_symbol = arr_2; + var i = tint_symbol[0][1]; +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, StructNested) { + auto* src = R"( +struct S1 { + a : i32, +}; + +struct S2 { + a : i32, + b : S1, + c : i32, +}; + +struct S3 { + a : S2, +}; + +fn f() { + var x = S3(S2(1, S1(2), 3)).a.b.a; +} +)"; + + auto* expect = R"( +struct S1 { + a : i32, +} + +struct S2 { + a : i32, + b : S1, + c : i32, +} + +struct S3 { + a : S2, +} + +fn f() { + let tint_symbol = S1(2); + let tint_symbol_1 = S2(1, tint_symbol, 3); + let tint_symbol_2 = S3(tint_symbol_1); + var x = tint_symbol_2.a.b.a; +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, Mixed) { + auto* src = R"( +struct S1 { + a : i32, +}; + +struct S2 { + a : array, +}; + +fn f() { + var x = S2(array(S1(1), S1(2), S1(3))).a[1].a; +} +)"; + + auto* expect = R"( +struct S1 { + a : i32, +} + +struct S2 { + a : array, +} + +fn f() { + let tint_symbol = S1(1); + let tint_symbol_1 = S1(2); + let tint_symbol_2 = S1(3); + let tint_symbol_3 = array(tint_symbol, tint_symbol_1, tint_symbol_2); + let tint_symbol_4 = S2(tint_symbol_3); + var x = tint_symbol_4.a[1].a; +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, Mixed_OutOfOrder) { + auto* src = R"( +fn f() { + var x = S2(array(S1(1), S1(2), S1(3))).a[1].a; +} + +struct S2 { + a : array, +}; + +struct S1 { + a : i32, +}; +)"; + + auto* expect = R"( +fn f() { + let tint_symbol = S1(1); + let tint_symbol_1 = S1(2); + let tint_symbol_2 = S1(3); + let tint_symbol_3 = array(tint_symbol, tint_symbol_1, tint_symbol_2); + let tint_symbol_4 = S2(tint_symbol_3); + var x = tint_symbol_4.a[1].a; +} + +struct S2 { + a : array, +} + +struct S1 { + a : i32, +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, NoChangeOnVarDecl) { + auto* src = R"( +struct S { + a : i32, + b : f32, + c : i32, +} + +fn f() { + var local_arr = array(0.0, 1.0, 2.0, 3.0); + var local_str = S(1, 2.0, 3); +} + +let module_arr : array = array(0.0, 1.0, 2.0, 3.0); + +let module_str : S = S(1, 2.0, 3); +)"; + + auto* expect = src; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, NoChangeOnVarDecl_OutOfOrder) { + auto* src = R"( +fn f() { + var local_arr = array(0.0, 1.0, 2.0, 3.0); + var local_str = S(1, 2.0, 3); +} + +let module_str : S = S(1, 2.0, 3); + +struct S { + a : i32, + b : f32, + c : i32, +} + +let module_arr : array = array(0.0, 1.0, 2.0, 3.0); +)"; + + auto* expect = src; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(PromoteInitializersToLetTest, ForLoopShadowing) { + auto* src = R"( +fn X() { + var i = 10; + for(var f = 0; f < 10; f = f + array(i)[0]) { + var i = 20; + } +} + +fn Y() { + var i = 10; + for(var f = 0; f < array(i)[0]; f = f + 1) { + var i = 20; + } +} + +fn Z() { + var i = 10; + for(var f = array(i)[0]; f < 10; f = f + 1) { + var i = 20; + } +} +)"; + + auto* expect = R"( +fn X() { + var i = 10; + { + var f = 0; + loop { + if (!((f < 10))) { + break; + } + { + var i = 20; + } + + continuing { + let tint_symbol = array(i); + f = (f + tint_symbol[0]); + } + } + } +} + +fn Y() { + var i = 10; + { + var f = 0; + loop { + let tint_symbol_1 = array(i); + if (!((f < tint_symbol_1[0]))) { + break; + } + { + var i = 20; + } + + continuing { + f = (f + 1); + } + } + } +} + +fn Z() { + var i = 10; + let tint_symbol_2 = array(i); + for(var f = tint_symbol_2[0]; (f < 10); f = (f + 1)) { + var i = 20; + } +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + +} // namespace +} // namespace tint::transform diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc index 6603ce7667..d2cb602431 100644 --- a/src/tint/writer/glsl/generator_impl.cc +++ b/src/tint/writer/glsl/generator_impl.cc @@ -58,7 +58,7 @@ #include "src/tint/transform/fold_trivial_single_use_lets.h" #include "src/tint/transform/loop_to_for_loop.h" #include "src/tint/transform/manager.h" -#include "src/tint/transform/promote_initializers_to_const_var.h" +#include "src/tint/transform/promote_initializers_to_let.h" #include "src/tint/transform/promote_side_effects_to_decl.h" #include "src/tint/transform/remove_phonies.h" #include "src/tint/transform/renamer.h" @@ -226,7 +226,7 @@ SanitizedResult Sanitize(const Program* in, options.binding_points, options.access_controls, options.allow_collisions); manager.Add(); - manager.Add(); + manager.Add(); manager.Add(); manager.Add(); data.Add( @@ -1773,7 +1773,7 @@ bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* exp // to a shader-creation time constant value, and this can be removed. if (auto constant = sem->ConstantValue()) { // We do not want to inline array constants, as this will undo the work of - // PromoteInitializersToConstVar, which ensures that arrays are declarated in 'let's + // PromoteInitializersToLet, which ensures that arrays are declarated in 'let's // before their usage. if (!constant.Type()->Is()) { return EmitConstant(out, constant); diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc index c2a03b8ce3..8139e6b780 100644 --- a/src/tint/writer/hlsl/generator_impl.cc +++ b/src/tint/writer/hlsl/generator_impl.cc @@ -60,7 +60,7 @@ #include "src/tint/transform/loop_to_for_loop.h" #include "src/tint/transform/manager.h" #include "src/tint/transform/num_workgroups_from_uniform.h" -#include "src/tint/transform/promote_initializers_to_const_var.h" +#include "src/tint/transform/promote_initializers_to_let.h" #include "src/tint/transform/promote_side_effects_to_decl.h" #include "src/tint/transform/remove_continue_in_switch.h" #include "src/tint/transform/remove_phonies.h" @@ -231,7 +231,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) { // DecomposeMemoryAccess special-cases the arrayLength() intrinsic, which // will be transformed by CalculateArrayLength manager.Add(); - manager.Add(); + manager.Add(); manager.Add(); @@ -2618,7 +2618,7 @@ bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* exp // to a shader-creation time constant value, and this can be removed. if (auto constant = sem->ConstantValue()) { // We do not want to inline array constants, as this will undo the work of - // PromoteInitializersToConstVar, which ensures that arrays are declarated in 'let's + // PromoteInitializersToLet, which ensures that arrays are declarated in 'let's // before their usage. if (!constant.Type()->Is()) { return EmitConstant(out, constant); diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc index a13e58a5ee..dd25dcbf6a 100644 --- a/src/tint/writer/msl/generator_impl.cc +++ b/src/tint/writer/msl/generator_impl.cc @@ -64,7 +64,7 @@ #include "src/tint/transform/expand_compound_assignment.h" #include "src/tint/transform/manager.h" #include "src/tint/transform/module_scope_var_to_entry_point_param.h" -#include "src/tint/transform/promote_initializers_to_const_var.h" +#include "src/tint/transform/promote_initializers_to_let.h" #include "src/tint/transform/promote_side_effects_to_decl.h" #include "src/tint/transform/remove_phonies.h" #include "src/tint/transform/simplify_pointers.h" @@ -204,7 +204,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) { manager.Add(); manager.Add(); manager.Add(); - manager.Add(); + manager.Add(); manager.Add(); manager.Add(); @@ -1709,7 +1709,7 @@ bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* exp // to a shader-creation time constant value, and this can be removed. if (auto constant = sem->ConstantValue()) { // We do not want to inline array constants, as this will undo the work of - // PromoteInitializersToConstVar, which ensures that arrays are declarated in 'let's + // PromoteInitializersToLet, which ensures that arrays are declarated in 'let's // before their usage. if (!constant.Type()->Is()) { return EmitConstant(out, constant);