// Copyright 2020 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 #include "gtest/gtest.h" #include "src/ast/assignment_statement.h" #include "src/ast/break_statement.h" #include "src/ast/continue_statement.h" #include "src/ast/identifier_expression.h" #include "src/ast/int_literal.h" #include "src/ast/loop_statement.h" #include "src/ast/scalar_constructor_expression.h" #include "src/ast/type/i32_type.h" #include "src/context.h" #include "src/type_determiner.h" #include "src/writer/spirv/builder.h" #include "src/writer/spirv/spv_dump.h" namespace tint { namespace writer { namespace spirv { namespace { using BuilderTest = testing::Test; TEST_F(BuilderTest, Loop_Empty) { // loop { // } ast::LoopStatement expr; Context ctx; ast::Module mod; TypeDeterminer td(&ctx, &mod); ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); Builder b(&mod); b.push_function(Function{}); EXPECT_TRUE(b.GenerateLoopStatement(&expr)) << b.error(); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpBranch %1 %1 = OpLabel OpLoopMerge %2 %3 None OpBranch %4 %4 = OpLabel OpBranch %3 %3 = OpLabel OpBranch %1 %2 = OpLabel )"); } TEST_F(BuilderTest, Loop_WithoutContinuing) { ast::type::I32Type i32; // loop { // v = 2; // } auto var = std::make_unique("v", ast::StorageClass::kPrivate, &i32); ast::StatementList body; body.push_back(std::make_unique( std::make_unique("v"), std::make_unique( std::make_unique(&i32, 2)))); ast::StatementList continuing; ast::LoopStatement expr(std::move(body), std::move(continuing)); Context ctx; ast::Module mod; TypeDeterminer td(&ctx, &mod); td.RegisterVariableForTesting(var.get()); ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); Builder b(&mod); b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error(); EXPECT_TRUE(b.GenerateLoopStatement(&expr)) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1 %2 = OpTypePointer Private %3 %1 = OpVariable %2 Private %8 = OpConstant %3 2 )"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpBranch %4 %4 = OpLabel OpLoopMerge %5 %6 None OpBranch %7 %7 = OpLabel OpStore %1 %8 OpBranch %6 %6 = OpLabel OpBranch %4 %5 = OpLabel )"); } TEST_F(BuilderTest, Loop_WithContinuing) { ast::type::I32Type i32; // loop { // a = 2; // continuing { // a = 3; // } // } auto var = std::make_unique("v", ast::StorageClass::kPrivate, &i32); ast::StatementList body; body.push_back(std::make_unique( std::make_unique("v"), std::make_unique( std::make_unique(&i32, 2)))); ast::StatementList continuing; continuing.push_back(std::make_unique( std::make_unique("v"), std::make_unique( std::make_unique(&i32, 3)))); ast::LoopStatement expr(std::move(body), std::move(continuing)); Context ctx; ast::Module mod; TypeDeterminer td(&ctx, &mod); td.RegisterVariableForTesting(var.get()); ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); Builder b(&mod); b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error(); EXPECT_TRUE(b.GenerateLoopStatement(&expr)) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1 %2 = OpTypePointer Private %3 %1 = OpVariable %2 Private %8 = OpConstant %3 2 %9 = OpConstant %3 3 )"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpBranch %4 %4 = OpLabel OpLoopMerge %5 %6 None OpBranch %7 %7 = OpLabel OpStore %1 %8 OpBranch %6 %6 = OpLabel OpStore %1 %9 OpBranch %4 %5 = OpLabel )"); } TEST_F(BuilderTest, Loop_WithContinue) { // loop { // continue; // } ast::StatementList body; body.push_back(std::make_unique()); ast::StatementList continuing; ast::LoopStatement expr(std::move(body), std::move(continuing)); Context ctx; ast::Module mod; TypeDeterminer td(&ctx, &mod); ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); Builder b(&mod); b.push_function(Function{}); EXPECT_TRUE(b.GenerateLoopStatement(&expr)) << b.error(); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpBranch %1 %1 = OpLabel OpLoopMerge %2 %3 None OpBranch %4 %4 = OpLabel OpBranch %3 %3 = OpLabel OpBranch %1 %2 = OpLabel )"); } TEST_F(BuilderTest, DISABLED_Loop_WithConditionalContinue) {} TEST_F(BuilderTest, Loop_WithBreak) { // loop { // break; // } ast::StatementList body; body.push_back(std::make_unique()); ast::StatementList continuing; ast::LoopStatement expr(std::move(body), std::move(continuing)); Context ctx; ast::Module mod; TypeDeterminer td(&ctx, &mod); ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); Builder b(&mod); b.push_function(Function{}); EXPECT_TRUE(b.GenerateLoopStatement(&expr)) << b.error(); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpBranch %1 %1 = OpLabel OpLoopMerge %2 %3 None OpBranch %4 %4 = OpLabel OpBranch %2 %3 = OpLabel OpBranch %1 %2 = OpLabel )"); } TEST_F(BuilderTest, DISABLED_Loop_WithConditionalBreak) {} } // namespace } // namespace spirv } // namespace writer } // namespace tint