tint/transform: fix PromoteInitializersToLet for constant expressions

Fix more edge cases uncovered with tint:1781

Fixed: tint:1781
Change-Id: I58d120185f47c10bc9fe55dd95a198d496c4ec94
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/113024
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton
2022-12-09 12:34:36 +00:00
committed by Dawn LUCI CQ
parent dd0d45102a
commit f528d33d52
73 changed files with 653 additions and 824 deletions

View File

@@ -16,11 +16,14 @@
#include <utility>
#include "src/tint/ast/traverse_expressions.h"
#include "src/tint/program_builder.h"
#include "src/tint/sem/call.h"
#include "src/tint/sem/statement.h"
#include "src/tint/sem/type_initializer.h"
#include "src/tint/transform/utils/hoist_to_decl_before.h"
#include "src/tint/type/struct.h"
#include "src/tint/utils/hashset.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::PromoteInitializersToLet);
@@ -36,87 +39,111 @@ Transform::ApplyResult PromoteInitializersToLet::Apply(const Program* src,
ProgramBuilder b;
CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
HoistToDeclBefore hoist_to_decl_before(ctx);
bool any_promoted = false;
// Hoists array and structure initializers to a constant variable, declared
// just before the statement of usage.
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.
// These must be constexpr, and so cannot contain the type of
// expressions that must be sanitized.
return true;
// Returns true if the expression should be hoisted to a new let statement before the
// expression's statement.
auto should_hoist = [&](const sem::Expression* expr) {
if (!expr->Type()->IsAnyOf<type::Array, type::StructBase>()) {
// We only care about array and struct initializers
return false;
}
auto* stmt = sem_stmt->Declaration();
// Check whether the expression is an array or structure constructor
{
// Follow const-chains
auto* root_expr = expr;
if (expr->Stage() == sem::EvaluationStage::kConstant) {
while (auto* user = root_expr->UnwrapMaterialize()->As<sem::VariableUser>()) {
root_expr = user->Variable()->Initializer();
}
}
if (auto* src_var_decl = stmt->As<ast::VariableDeclStatement>()) {
if (src_var_decl->variable->initializer == expr->Declaration()) {
// This statement is just a variable declaration with the
// initializer as the initializer value. This is what we're
// attempting to transform to, and so ignore.
return true;
auto* ctor = root_expr->UnwrapMaterialize()->As<sem::Call>();
if (!ctor || !ctor->Target()->Is<sem::TypeInitializer>()) {
// Root expression is not a type constructor. Not interested in this.
return false;
}
}
auto* src_ty = expr->Type();
if (!src_ty->IsAnyOf<type::Array, sem::Struct>()) {
// We only care about array and struct initializers
return true;
if (auto* src_var_decl = expr->Stmt()->Declaration()->As<ast::VariableDeclStatement>()) {
if (src_var_decl->variable->initializer == expr->Declaration()) {
// This statement is just a variable declaration with the initializer as the
// initializer value. This is what we're attempting to transform to, and so
// ignore.
return false;
}
}
any_promoted = true;
return hoist_to_decl_before.Add(expr, expr->Declaration(),
HoistToDeclBefore::VariableKind::kLet);
return true;
};
// A list of expressions that should be hoisted.
utils::Vector<const sem::Expression*, 32> to_hoist;
// A set of expressions that are constant, which _may_ need to be hoisted.
utils::Hashset<const ast::Expression*, 32> const_chains;
// Walk the AST nodes. This order guarantees that leaf-expressions are visited first.
for (auto* node : src->ASTNodes().Objects()) {
bool ok = Switch(
node, //
[&](const ast::CallExpression* expr) {
if (auto* sem = src->Sem().Get(expr)) {
auto* ctor = sem->UnwrapMaterialize()->As<sem::Call>();
if (ctor->Target()->Is<sem::TypeInitializer>()) {
return promote(sem);
}
if (auto* sem = src->Sem().Get<sem::Expression>(node)) {
auto* stmt = sem->Stmt();
if (!stmt) {
// Expression is outside of a statement. This usually means the expression is part
// of a global (module-scope) constant declaration. These must be constexpr, and so
// cannot contain the type of expressions that must be sanitized.
continue;
}
if (sem->Stage() == sem::EvaluationStage::kConstant) {
// Expression is constant. We only need to hoist expressions if they're the
// outermost constant expression in a chain. Remove the immediate child nodes of the
// expression from const_chains, and add this expression to the const_chains. As we
// visit leaf-expressions first, this means the content of const_chains only
// contains the outer-most constant expressions.
auto* expr = sem->Declaration();
bool ok = ast::TraverseExpressions(
expr, b.Diagnostics(), [&](const ast::Expression* child) {
const_chains.Remove(child);
return child == expr ? ast::TraverseAction::Descend
: ast::TraverseAction::Skip;
});
if (!ok) {
return Program(std::move(b));
}
return true;
},
[&](const ast::IdentifierExpression* expr) {
if (auto* sem = src->Sem().Get(expr)) {
if (auto* user = sem->UnwrapMaterialize()->As<sem::VariableUser>()) {
// Identifier resolves to a variable
if (auto* stmt = user->Stmt()) {
if (auto* decl = stmt->Declaration()->As<ast::VariableDeclStatement>();
decl && decl->variable->Is<ast::Const>()) {
// The identifier is used on the RHS of a 'const' declaration.
// Ignore.
return true;
}
}
if (user->Variable()->Declaration()->Is<ast::Const>()) {
// 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 Program(std::move(b));
const_chains.Add(expr);
} else if (should_hoist(sem)) {
to_hoist.Push(sem);
}
}
}
if (!any_promoted) {
// After walking the full AST, const_chains only contains the outer-most constant expressions.
// Check if any of these need hoisting, and append those to to_hoist.
for (auto* expr : const_chains) {
if (auto* sem = src->Sem().Get(expr); should_hoist(sem)) {
to_hoist.Push(sem);
}
}
if (to_hoist.IsEmpty()) {
// Nothing to do. Skip.
return SkipTransform;
}
// The order of to_hoist is currently undefined. Sort by AST node id, which will make this
// deterministic.
to_hoist.Sort([&](auto* expr_a, auto* expr_b) {
return expr_a->Declaration()->node_id < expr_b->Declaration()->node_id;
});
// Hoist all the expression in to_hoist to a constant variable, declared just before the
// statement of usage.
HoistToDeclBefore hoist_to_decl_before(ctx);
for (auto* expr : to_hoist) {
if (!hoist_to_decl_before.Add(expr, expr->Declaration(),
HoistToDeclBefore::VariableKind::kLet)) {
return Program(std::move(b));
}
}
ctx.Clone();
return Program(std::move(b));
}

View File

@@ -30,7 +30,21 @@ TEST_F(PromoteInitializersToLetTest, EmptyModule) {
EXPECT_EQ(expect, str(got));
}
TEST_F(PromoteInitializersToLetTest, BasicArray) {
TEST_F(PromoteInitializersToLetTest, BasicConstArray) {
auto* src = R"(
fn f() {
const f0 = 1.0;
const f1 = 2.0;
const f2 = 3.0;
const f3 = 4.0;
var i = array<f32, 4u>(f0, f1, f2, f3)[2];
}
)";
EXPECT_FALSE(ShouldRun<PromoteInitializersToLet>(src));
}
TEST_F(PromoteInitializersToLetTest, BasicRuntimeArray) {
auto* src = R"(
fn f() {
var f0 = 1.0;
@@ -52,13 +66,12 @@ fn f() {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PromoteInitializersToLetTest, BasicStruct) {
TEST_F(PromoteInitializersToLetTest, BasicConstStruct) {
auto* src = R"(
struct S {
a : i32,
@@ -69,6 +82,23 @@ struct S {
fn f() {
var x = S(1, 2.0, vec3<f32>()).b;
}
)";
EXPECT_FALSE(ShouldRun<PromoteInitializersToLet>(src));
}
TEST_F(PromoteInitializersToLetTest, BasicRuntimeStruct) {
auto* src = R"(
struct S {
a : i32,
b : f32,
c : vec3<f32>,
};
fn f() {
let runtime_value = 1;
var x = S(runtime_value, 2.0, vec3<f32>()).b;
}
)";
auto* expect = R"(
@@ -79,12 +109,12 @@ struct S {
}
fn f() {
let tint_symbol = S(1, 2.0, vec3<f32>());
let runtime_value = 1;
let tint_symbol = S(runtime_value, 2.0, vec3<f32>());
var x = tint_symbol.b;
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -93,7 +123,8 @@ fn f() {
TEST_F(PromoteInitializersToLetTest, BasicStruct_OutOfOrder) {
auto* src = R"(
fn f() {
var x = S(1, 2.0, vec3<f32>()).b;
let runtime_value = 1;
var x = S(runtime_value, 2.0, vec3<f32>()).b;
}
struct S {
@@ -105,7 +136,8 @@ struct S {
auto* expect = R"(
fn f() {
let tint_symbol = S(1, 2.0, vec3<f32>());
let runtime_value = 1;
let tint_symbol = S(runtime_value, 2.0, vec3<f32>());
var x = tint_symbol.b;
}
@@ -116,7 +148,6 @@ struct S {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -133,29 +164,29 @@ const C = array<f32, 2u>(f0, f1);
fn f() {
var f0 = 100.0;
var f1 = 100.0;
var i = C[1];
var i = C[1]; // Not hoisted, as the final const value is not an array
}
)";
auto* expect = R"(
const f0 = 1.0;
const f1 = 2.0;
const C = array<f32, 2u>(f0, f1);
EXPECT_FALSE(ShouldRun<PromoteInitializersToLet>(src));
}
TEST_F(PromoteInitializersToLetTest, GlobalConstBasicArray_OutOfOrder) {
auto* src = R"(
fn f() {
var f0 = 100.0;
var f1 = 100.0;
let tint_symbol = C;
var i = tint_symbol[1];
var i = C[1];
}
const C = array<f32, 2u>(f0, f1);
const f0 = 1.0;
const f1 = 2.0;
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
EXPECT_FALSE(ShouldRun<PromoteInitializersToLet>(src));
}
TEST_F(PromoteInitializersToLetTest, GlobalConstArrayDynamicIndex) {
@@ -183,43 +214,6 @@ fn vs_main(@builtin(vertex_index) in_vertex_index : u32) -> @builtin(position) v
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(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<f32, 2u>(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<f32, 2u>(f0, f1);
const f0 = 1.0;
const f1 = 2.0;
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -231,7 +225,21 @@ fn f() {
const f0 = 1.0;
const f1 = 2.0;
const C = array<f32, 2u>(f0, f1);
var i = C[1];
var i = C[1]; // Not hoisted, as the final const value is not an array
}
)";
EXPECT_FALSE(ShouldRun<PromoteInitializersToLet>(src));
}
TEST_F(PromoteInitializersToLetTest, LocalConstBasicArrayRuntimeIndex) {
auto* src = R"(
fn f() {
const f0 = 1.0;
const f1 = 2.0;
const C = array<f32, 2u>(f0, f1);
let runtime_value = 1;
var i = C[runtime_value];
}
)";
@@ -240,12 +248,12 @@ fn f() {
const f0 = 1.0;
const f1 = 2.0;
const C = array<f32, 2u>(f0, f1);
let runtime_value = 1;
let tint_symbol = C;
var i = tint_symbol[1];
var i = tint_symbol[runtime_value];
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -255,7 +263,7 @@ TEST_F(PromoteInitializersToLetTest, ArrayInForLoopInit) {
auto* src = R"(
fn f() {
var insert_after = 1;
for(var i = array<f32, 4u>(0.0, 1.0, 2.0, 3.0)[2]; ; ) {
for(var i = array<f32, 4u>(0.0, 1.0, 2.0, 3.0)[insert_after]; ; ) {
break;
}
}
@@ -265,13 +273,12 @@ fn f() {
fn f() {
var insert_after = 1;
let tint_symbol = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
for(var i = tint_symbol[2]; ; ) {
for(var i = tint_symbol[insert_after]; ; ) {
break;
}
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -281,8 +288,9 @@ TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopInit) {
auto* src = R"(
fn f() {
const arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
let runtime_value = 1;
var insert_after = 1;
for(var i = arr[2]; ; ) {
for(var i = arr[runtime_value]; ; ) {
break;
}
}
@@ -291,15 +299,15 @@ fn f() {
auto* expect = R"(
fn f() {
const arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
let runtime_value = 1;
var insert_after = 1;
let tint_symbol = arr;
for(var i = tint_symbol[2]; ; ) {
for(var i = tint_symbol[runtime_value]; ; ) {
break;
}
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -310,8 +318,9 @@ TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInForLoopInit) {
const arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
fn f() {
let runtime_value = 1;
var insert_after = 1;
for(var i = arr[2]; ; ) {
for(var i = arr[runtime_value]; ; ) {
break;
}
}
@@ -321,15 +330,15 @@ fn f() {
const arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
fn f() {
let runtime_value = 1;
var insert_after = 1;
let tint_symbol = arr;
for(var i = tint_symbol[2]; ; ) {
for(var i = tint_symbol[runtime_value]; ; ) {
break;
}
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -343,9 +352,13 @@ struct S {
c : vec3<f32>,
};
fn get_b_runtime(s : S) -> f32 {
return s.b;
}
fn f() {
var insert_after = 1;
for(var x = S(1, 2.0, vec3<f32>()).b; ; ) {
for(var x = get_b_runtime(S(1, 2.0, vec3<f32>())); ; ) {
break;
}
}
@@ -358,16 +371,19 @@ struct S {
c : vec3<f32>,
}
fn get_b_runtime(s : S) -> f32 {
return s.b;
}
fn f() {
var insert_after = 1;
let tint_symbol = S(1, 2.0, vec3<f32>());
for(var x = tint_symbol.b; ; ) {
for(var x = get_b_runtime(tint_symbol); ; ) {
break;
}
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -377,11 +393,15 @@ TEST_F(PromoteInitializersToLetTest, StructInForLoopInit_OutOfOrder) {
auto* src = R"(
fn f() {
var insert_after = 1;
for(var x = S(1, 2.0, vec3<f32>()).b; ; ) {
for(var x = get_b_runtime(S(1, 2.0, vec3<f32>())); ; ) {
break;
}
}
fn get_b_runtime(s : S) -> f32 {
return s.b;
}
struct S {
a : i32,
b : f32,
@@ -393,11 +413,15 @@ struct S {
fn f() {
var insert_after = 1;
let tint_symbol = S(1, 2.0, vec3<f32>());
for(var x = tint_symbol.b; ; ) {
for(var x = get_b_runtime(tint_symbol); ; ) {
break;
}
}
fn get_b_runtime(s : S) -> f32 {
return s.b;
}
struct S {
a : i32,
b : f32,
@@ -405,7 +429,6 @@ struct S {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -440,7 +463,6 @@ fn f() {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -449,9 +471,10 @@ fn f() {
TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopCond) {
auto* src = R"(
fn f() {
let runtime_value = 0;
const f = 1.0;
const arr = array<f32, 1u>(f);
for(var i = f; i == arr[0]; i = i + 1.0) {
for(var i = f; i == arr[runtime_value]; i = i + 1.0) {
var marker = 1;
}
}
@@ -459,13 +482,14 @@ fn f() {
auto* expect = R"(
fn f() {
let runtime_value = 0;
const f = 1.0;
const arr = array<f32, 1u>(f);
{
var i = f;
loop {
let tint_symbol = arr;
if (!((i == tint_symbol[0]))) {
if (!((i == tint_symbol[runtime_value]))) {
break;
}
{
@@ -480,7 +504,6 @@ fn f() {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -493,7 +516,8 @@ const f = 1.0;
const arr = array<f32, 1u>(f);
fn F() {
for(var i = f; i == arr[0]; i = i + 1.0) {
let runtime_value = 0;
for(var i = f; i == arr[runtime_value]; i = i + 1.0) {
var marker = 1;
}
}
@@ -505,11 +529,12 @@ const f = 1.0;
const arr = array<f32, 1u>(f);
fn F() {
let runtime_value = 0;
{
var i = f;
loop {
let tint_symbol = arr;
if (!((i == tint_symbol[0]))) {
if (!((i == tint_symbol[runtime_value]))) {
break;
}
{
@@ -524,7 +549,6 @@ fn F() {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -533,8 +557,9 @@ fn F() {
TEST_F(PromoteInitializersToLetTest, ArrayInForLoopCont) {
auto* src = R"(
fn f() {
let runtime_value = 0;
var f = 0.0;
for(; f < 10.0; f = f + array<f32, 1u>(1.0)[0]) {
for(; f < 10.0; f = f + array<f32, 1u>(1.0)[runtime_value]) {
var marker = 1;
}
}
@@ -542,6 +567,7 @@ fn f() {
auto* expect = R"(
fn f() {
let runtime_value = 0;
var f = 0.0;
loop {
if (!((f < 10.0))) {
@@ -553,13 +579,12 @@ fn f() {
continuing {
let tint_symbol = array<f32, 1u>(1.0);
f = (f + tint_symbol[0]);
f = (f + tint_symbol[runtime_value]);
}
}
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -568,9 +593,10 @@ fn f() {
TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopCont) {
auto* src = R"(
fn f() {
let runtime_value = 0;
const arr = array<f32, 1u>(1.0);
var f = 0.0;
for(; f < 10.0; f = f + arr[0]) {
for(; f < 10.0; f = f + arr[runtime_value]) {
var marker = 1;
}
}
@@ -578,6 +604,7 @@ fn f() {
auto* expect = R"(
fn f() {
let runtime_value = 0;
const arr = array<f32, 1u>(1.0);
var f = 0.0;
loop {
@@ -590,13 +617,12 @@ fn f() {
continuing {
let tint_symbol = arr;
f = (f + tint_symbol[0]);
f = (f + tint_symbol[runtime_value]);
}
}
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -607,8 +633,9 @@ TEST_F(PromoteInitializersToLetTest, GlobalConstArrayInForLoopCont) {
const arr = array<f32, 1u>(1.0);
fn f() {
let runtime_value = 0;
var f = 0.0;
for(; f < 10.0; f = f + arr[0]) {
for(; f < 10.0; f = f + arr[runtime_value]) {
var marker = 1;
}
}
@@ -618,6 +645,7 @@ fn f() {
const arr = array<f32, 1u>(1.0);
fn f() {
let runtime_value = 0;
var f = 0.0;
loop {
if (!((f < 10.0))) {
@@ -629,13 +657,12 @@ fn f() {
continuing {
let tint_symbol = arr;
f = (f + tint_symbol[0]);
f = (f + tint_symbol[runtime_value]);
}
}
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -644,9 +671,10 @@ fn f() {
TEST_F(PromoteInitializersToLetTest, ArrayInForLoopInitCondCont) {
auto* src = R"(
fn f() {
for(var f = array<f32, 1u>(0.0)[0];
f < array<f32, 1u>(1.0)[0];
f = f + array<f32, 1u>(2.0)[0]) {
let runtime_value = 0;
for(var f = array<f32, 1u>(0.0)[runtime_value];
f < array<f32, 1u>(1.0)[runtime_value];
f = f + array<f32, 1u>(2.0)[runtime_value]) {
var marker = 1;
}
}
@@ -654,12 +682,13 @@ fn f() {
auto* expect = R"(
fn f() {
let runtime_value = 0;
let tint_symbol = array<f32, 1u>(0.0);
{
var f = tint_symbol[0];
var f = tint_symbol[runtime_value];
loop {
let tint_symbol_1 = array<f32, 1u>(1.0);
if (!((f < tint_symbol_1[0]))) {
if (!((f < tint_symbol_1[runtime_value]))) {
break;
}
{
@@ -668,14 +697,13 @@ fn f() {
continuing {
let tint_symbol_2 = array<f32, 1u>(2.0);
f = (f + tint_symbol_2[0]);
f = (f + tint_symbol_2[runtime_value]);
}
}
}
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -684,10 +712,11 @@ fn f() {
TEST_F(PromoteInitializersToLetTest, LocalConstArrayInForLoopInitCondCont) {
auto* src = R"(
fn f() {
let runtime_value = 0;
const arr_a = array<f32, 1u>(0.0);
const arr_b = array<f32, 1u>(1.0);
const arr_c = array<f32, 1u>(2.0);
for(var f = arr_a[0]; f < arr_b[0]; f = f + arr_c[0]) {
for(var f = arr_a[runtime_value]; f < arr_b[runtime_value]; f = f + arr_c[runtime_value]) {
var marker = 1;
}
}
@@ -695,15 +724,16 @@ fn f() {
auto* expect = R"(
fn f() {
let runtime_value = 0;
const arr_a = array<f32, 1u>(0.0);
const arr_b = array<f32, 1u>(1.0);
const arr_c = array<f32, 1u>(2.0);
let tint_symbol = arr_a;
{
var f = tint_symbol[0];
var f = tint_symbol[runtime_value];
loop {
let tint_symbol_1 = arr_b;
if (!((f < tint_symbol_1[0]))) {
if (!((f < tint_symbol_1[runtime_value]))) {
break;
}
{
@@ -712,14 +742,13 @@ fn f() {
continuing {
let tint_symbol_2 = arr_c;
f = (f + tint_symbol_2[0]);
f = (f + tint_symbol_2[runtime_value]);
}
}
}
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -751,7 +780,6 @@ fn f() {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -802,7 +830,6 @@ fn f() {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -811,15 +838,16 @@ fn f() {
TEST_F(PromoteInitializersToLetTest, LocalConstArrayInElseIfChain) {
auto* src = R"(
fn f() {
let runtime_value = 0;
const f = 1.0;
const arr = array<f32, 2u>(f, f);
if (true) {
var marker = 0;
} else if (true) {
var marker = 1;
} else if (f == arr[0]) {
} else if (f == arr[runtime_value]) {
var marker = 2;
} else if (f == arr[1]) {
} else if (f == arr[runtime_value + 1]) {
var marker = 3;
} else if (true) {
var marker = 4;
@@ -831,6 +859,7 @@ fn f() {
auto* expect = R"(
fn f() {
let runtime_value = 0;
const f = 1.0;
const arr = array<f32, 2u>(f, f);
if (true) {
@@ -839,11 +868,11 @@ fn f() {
var marker = 1;
} else {
let tint_symbol = arr;
if ((f == tint_symbol[0])) {
if ((f == tint_symbol[runtime_value])) {
var marker = 2;
} else {
let tint_symbol_1 = arr;
if ((f == tint_symbol_1[1])) {
if ((f == tint_symbol_1[(runtime_value + 1)])) {
var marker = 3;
} else if (true) {
var marker = 4;
@@ -855,7 +884,6 @@ fn f() {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -868,13 +896,14 @@ const f = 1.0;
const arr = array<f32, 2u>(f, f);
fn F() {
let runtime_value = 0;
if (true) {
var marker = 0;
} else if (true) {
var marker = 1;
} else if (f == arr[0]) {
} else if (f == arr[runtime_value]) {
var marker = 2;
} else if (f == arr[1]) {
} else if (f == arr[runtime_value + 1]) {
var marker = 3;
} else if (true) {
var marker = 4;
@@ -890,17 +919,18 @@ const f = 1.0;
const arr = array<f32, 2u>(f, f);
fn F() {
let runtime_value = 0;
if (true) {
var marker = 0;
} else if (true) {
var marker = 1;
} else {
let tint_symbol = arr;
if ((f == tint_symbol[0])) {
if ((f == tint_symbol[runtime_value])) {
var marker = 2;
} else {
let tint_symbol_1 = arr;
if ((f == tint_symbol_1[1])) {
if ((f == tint_symbol_1[(runtime_value + 1)])) {
var marker = 3;
} else if (true) {
var marker = 4;
@@ -912,35 +942,43 @@ fn F() {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PromoteInitializersToLetTest, ArrayInArrayArray) {
TEST_F(PromoteInitializersToLetTest, ArrayInArrayArrayConstIndex) {
auto* src = R"(
fn f() {
var i = array<array<f32, 2u>, 2u>(array<f32, 2u>(1.0, 2.0), array<f32, 2u>(3.0, 4.0))[0][1];
}
)";
auto* expect = R"(
EXPECT_FALSE(ShouldRun<PromoteInitializersToLet>(src));
}
TEST_F(PromoteInitializersToLetTest, ArrayInArrayArrayRuntimeIndex) {
auto* src = R"(
fn f() {
let tint_symbol = array<f32, 2u>(1.0, 2.0);
let tint_symbol_1 = array<f32, 2u>(3.0, 4.0);
let tint_symbol_2 = array<array<f32, 2u>, 2u>(tint_symbol, tint_symbol_1);
var i = tint_symbol_2[0][1];
let runtime_value = 1;
var i = array<array<f32, 2u>, 2u>(array<f32, 2u>(1.0, 2.0), array<f32, 2u>(3.0, 4.0))[runtime_value][runtime_value + 1];
}
)";
auto* expect = R"(
fn f() {
let runtime_value = 1;
let tint_symbol = array<array<f32, 2u>, 2u>(array<f32, 2u>(1.0, 2.0), array<f32, 2u>(3.0, 4.0));
var i = tint_symbol[runtime_value][(runtime_value + 1)];
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PromoteInitializersToLetTest, LocalConstArrayInArrayArray) {
TEST_F(PromoteInitializersToLetTest, LocalConstArrayInArrayArrayConstIndex) {
auto* src = R"(
fn f() {
const arr_0 = array<f32, 2u>(1.0, 2.0);
@@ -948,19 +986,33 @@ fn f() {
const arr_2 = array<array<f32, 2u>, 2u>(arr_0, arr_1);
var i = arr_2[0][1];
}
)";
EXPECT_FALSE(ShouldRun<PromoteInitializersToLet>(src));
}
TEST_F(PromoteInitializersToLetTest, LocalConstArrayInArrayArrayRuntimeIndex) {
auto* src = R"(
fn f() {
let runtime_value = 1;
const arr_0 = array<f32, 2u>(1.0, 2.0);
const arr_1 = array<f32, 2u>(3.0, 4.0);
const arr_2 = array<array<f32, 2u>, 2u>(arr_0, arr_1);
var i = arr_2[runtime_value][runtime_value + 1];
}
)";
auto* expect = R"(
fn f() {
let runtime_value = 1;
const arr_0 = array<f32, 2u>(1.0, 2.0);
const arr_1 = array<f32, 2u>(3.0, 4.0);
const arr_2 = array<array<f32, 2u>, 2u>(arr_0, arr_1);
let tint_symbol = arr_2;
var i = tint_symbol[0][1];
var i = tint_symbol[runtime_value][(runtime_value + 1)];
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -975,7 +1027,8 @@ const arr_1 = array<f32, 2u>(3.0, 4.0);
const arr_2 = array<array<f32, 2u>, 2u>(arr_0, arr_1);
fn f() {
var i = arr_2[0][1];
let runtime_value = 1;
var i = arr_2[runtime_value][runtime_value + 1];
}
)";
@@ -987,12 +1040,12 @@ const arr_1 = array<f32, 2u>(3.0, 4.0);
const arr_2 = array<array<f32, 2u>, 2u>(arr_0, arr_1);
fn f() {
let runtime_value = 1;
let tint_symbol = arr_2;
var i = tint_symbol[0][1];
var i = tint_symbol[runtime_value][(runtime_value + 1)];
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -1014,8 +1067,12 @@ struct S3 {
a : S2,
};
fn get_a(s : S3) -> S2 {
return s.a;
}
fn f() {
var x = S3(S2(1, S1(2), 3)).a.b.a;
var x = get_a(S3(S2(1, S1(2), 3))).b.a;
}
)";
@@ -1034,15 +1091,16 @@ struct S3 {
a : S2,
}
fn get_a(s : S3) -> S2 {
return s.a;
}
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;
let tint_symbol = S3(S2(1, S1(2), 3));
var x = get_a(tint_symbol).b.a;
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -1058,8 +1116,12 @@ struct S2 {
a : array<S1, 3u>,
};
fn get_a(s : S2) -> array<S1, 3u> {
return s.a;
}
fn f() {
var x = S2(array<S1, 3u>(S1(1), S1(2), S1(3))).a[1].a;
var x = get_a(S2(array<S1, 3u>(S1(1), S1(2), S1(3))))[1].a;
}
)";
@@ -1072,17 +1134,16 @@ struct S2 {
a : array<S1, 3u>,
}
fn get_a(s : S2) -> array<S1, 3u> {
return s.a;
}
fn f() {
let tint_symbol = S1(1);
let tint_symbol_1 = S1(2);
let tint_symbol_2 = S1(3);
let tint_symbol_3 = array<S1, 3u>(tint_symbol, tint_symbol_1, tint_symbol_2);
let tint_symbol_4 = S2(tint_symbol_3);
var x = tint_symbol_4.a[1].a;
let tint_symbol = S2(array<S1, 3u>(S1(1), S1(2), S1(3)));
var x = get_a(tint_symbol)[1].a;
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -1091,7 +1152,11 @@ fn f() {
TEST_F(PromoteInitializersToLetTest, Mixed_OutOfOrder) {
auto* src = R"(
fn f() {
var x = S2(array<S1, 3u>(S1(1), S1(2), S1(3))).a[1].a;
var x = get_a(S2(array<S1, 3u>(S1(1), S1(2), S1(3))))[1].a;
}
fn get_a(s : S2) -> array<S1, 3u> {
return s.a;
}
struct S2 {
@@ -1105,12 +1170,12 @@ struct S1 {
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<S1, 3u>(tint_symbol, tint_symbol_1, tint_symbol_2);
let tint_symbol_4 = S2(tint_symbol_3);
var x = tint_symbol_4.a[1].a;
let tint_symbol = S2(array<S1, 3u>(S1(1), S1(2), S1(3)));
var x = get_a(tint_symbol)[1].a;
}
fn get_a(s : S2) -> array<S1, 3u> {
return s.a;
}
struct S2 {
@@ -1122,7 +1187,6 @@ struct S1 {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -1144,7 +1208,6 @@ const module_str : F = F(2.0);
auto* expect = src;
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -1166,7 +1229,6 @@ const module_arr : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
auto* expect = src;
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));
@@ -1246,7 +1308,6 @@ fn Z() {
}
)";
DataMap data;
auto got = Run<PromoteInitializersToLet>(src);
EXPECT_EQ(expect, str(got));