Remove infrastructure for fallthrough
This Cl removes the internal infrastructor and backend code generation for the fallthrough statement. Bug: tint:1644 Change-Id: I2a1de7d527865e5a7221074f4e0fb106599f4c57 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/109005 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com> Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
bf586f6dfd
commit
267f1748c8
|
@ -247,8 +247,6 @@ libtint_source_set("libtint_core_all_src") {
|
||||||
"ast/f16.h",
|
"ast/f16.h",
|
||||||
"ast/f32.cc",
|
"ast/f32.cc",
|
||||||
"ast/f32.h",
|
"ast/f32.h",
|
||||||
"ast/fallthrough_statement.cc",
|
|
||||||
"ast/fallthrough_statement.h",
|
|
||||||
"ast/float_literal_expression.cc",
|
"ast/float_literal_expression.cc",
|
||||||
"ast/float_literal_expression.h",
|
"ast/float_literal_expression.h",
|
||||||
"ast/for_loop_statement.cc",
|
"ast/for_loop_statement.cc",
|
||||||
|
@ -1047,7 +1045,6 @@ if (tint_build_unittests) {
|
||||||
"ast/external_texture_test.cc",
|
"ast/external_texture_test.cc",
|
||||||
"ast/f16_test.cc",
|
"ast/f16_test.cc",
|
||||||
"ast/f32_test.cc",
|
"ast/f32_test.cc",
|
||||||
"ast/fallthrough_statement_test.cc",
|
|
||||||
"ast/float_literal_expression_test.cc",
|
"ast/float_literal_expression_test.cc",
|
||||||
"ast/for_loop_statement_test.cc",
|
"ast/for_loop_statement_test.cc",
|
||||||
"ast/function_test.cc",
|
"ast/function_test.cc",
|
||||||
|
@ -1159,8 +1156,8 @@ if (tint_build_unittests) {
|
||||||
"resolver/resolver_test.cc",
|
"resolver/resolver_test.cc",
|
||||||
"resolver/resolver_test_helper.cc",
|
"resolver/resolver_test_helper.cc",
|
||||||
"resolver/resolver_test_helper.h",
|
"resolver/resolver_test_helper.h",
|
||||||
"resolver/side_effects_test.cc",
|
|
||||||
"resolver/root_identifier_test.cc",
|
"resolver/root_identifier_test.cc",
|
||||||
|
"resolver/side_effects_test.cc",
|
||||||
"resolver/static_assert_test.cc",
|
"resolver/static_assert_test.cc",
|
||||||
"resolver/struct_address_space_use_test.cc",
|
"resolver/struct_address_space_use_test.cc",
|
||||||
"resolver/struct_layout_test.cc",
|
"resolver/struct_layout_test.cc",
|
||||||
|
@ -1480,7 +1477,6 @@ if (tint_build_unittests) {
|
||||||
"writer/wgsl/generator_impl_continue_test.cc",
|
"writer/wgsl/generator_impl_continue_test.cc",
|
||||||
"writer/wgsl/generator_impl_discard_test.cc",
|
"writer/wgsl/generator_impl_discard_test.cc",
|
||||||
"writer/wgsl/generator_impl_enable_test.cc",
|
"writer/wgsl/generator_impl_enable_test.cc",
|
||||||
"writer/wgsl/generator_impl_fallthrough_test.cc",
|
|
||||||
"writer/wgsl/generator_impl_function_test.cc",
|
"writer/wgsl/generator_impl_function_test.cc",
|
||||||
"writer/wgsl/generator_impl_global_decl_test.cc",
|
"writer/wgsl/generator_impl_global_decl_test.cc",
|
||||||
"writer/wgsl/generator_impl_identifier_test.cc",
|
"writer/wgsl/generator_impl_identifier_test.cc",
|
||||||
|
|
|
@ -139,8 +139,6 @@ list(APPEND TINT_LIB_SRCS
|
||||||
ast/f16.h
|
ast/f16.h
|
||||||
ast/f32.cc
|
ast/f32.cc
|
||||||
ast/f32.h
|
ast/f32.h
|
||||||
ast/fallthrough_statement.cc
|
|
||||||
ast/fallthrough_statement.h
|
|
||||||
ast/float_literal_expression.cc
|
ast/float_literal_expression.cc
|
||||||
ast/float_literal_expression.h
|
ast/float_literal_expression.h
|
||||||
ast/for_loop_statement.cc
|
ast/for_loop_statement.cc
|
||||||
|
@ -786,7 +784,6 @@ if(TINT_BUILD_TESTS)
|
||||||
ast/external_texture_test.cc
|
ast/external_texture_test.cc
|
||||||
ast/f16_test.cc
|
ast/f16_test.cc
|
||||||
ast/f32_test.cc
|
ast/f32_test.cc
|
||||||
ast/fallthrough_statement_test.cc
|
|
||||||
ast/float_literal_expression_test.cc
|
ast/float_literal_expression_test.cc
|
||||||
ast/for_loop_statement_test.cc
|
ast/for_loop_statement_test.cc
|
||||||
ast/function_test.cc
|
ast/function_test.cc
|
||||||
|
@ -1150,7 +1147,6 @@ if(TINT_BUILD_TESTS)
|
||||||
writer/wgsl/generator_impl_continue_test.cc
|
writer/wgsl/generator_impl_continue_test.cc
|
||||||
writer/wgsl/generator_impl_discard_test.cc
|
writer/wgsl/generator_impl_discard_test.cc
|
||||||
writer/wgsl/generator_impl_enable_test.cc
|
writer/wgsl/generator_impl_enable_test.cc
|
||||||
writer/wgsl/generator_impl_fallthrough_test.cc
|
|
||||||
writer/wgsl/generator_impl_function_test.cc
|
writer/wgsl/generator_impl_function_test.cc
|
||||||
writer/wgsl/generator_impl_global_decl_test.cc
|
writer/wgsl/generator_impl_global_decl_test.cc
|
||||||
writer/wgsl/generator_impl_identifier_test.cc
|
writer/wgsl/generator_impl_identifier_test.cc
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
// 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 "src/tint/ast/fallthrough_statement.h"
|
|
||||||
|
|
||||||
#include "src/tint/program_builder.h"
|
|
||||||
|
|
||||||
TINT_INSTANTIATE_TYPEINFO(tint::ast::FallthroughStatement);
|
|
||||||
|
|
||||||
namespace tint::ast {
|
|
||||||
|
|
||||||
FallthroughStatement::FallthroughStatement(ProgramID pid, NodeID nid, const Source& src)
|
|
||||||
: Base(pid, nid, src) {}
|
|
||||||
|
|
||||||
FallthroughStatement::FallthroughStatement(FallthroughStatement&&) = default;
|
|
||||||
|
|
||||||
FallthroughStatement::~FallthroughStatement() = default;
|
|
||||||
|
|
||||||
const FallthroughStatement* FallthroughStatement::Clone(CloneContext* ctx) const {
|
|
||||||
// Clone arguments outside of create() call to have deterministic ordering
|
|
||||||
auto src = ctx->Clone(source);
|
|
||||||
return ctx->dst->create<FallthroughStatement>(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace tint::ast
|
|
|
@ -1,43 +0,0 @@
|
||||||
// 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.
|
|
||||||
|
|
||||||
#ifndef SRC_TINT_AST_FALLTHROUGH_STATEMENT_H_
|
|
||||||
#define SRC_TINT_AST_FALLTHROUGH_STATEMENT_H_
|
|
||||||
|
|
||||||
#include "src/tint/ast/statement.h"
|
|
||||||
|
|
||||||
namespace tint::ast {
|
|
||||||
|
|
||||||
/// An fallthrough statement
|
|
||||||
class FallthroughStatement final : public Castable<FallthroughStatement, Statement> {
|
|
||||||
public:
|
|
||||||
/// Constructor
|
|
||||||
/// @param pid the identifier of the program that owns this node
|
|
||||||
/// @param nid the unique node identifier
|
|
||||||
/// @param src the source of this node
|
|
||||||
FallthroughStatement(ProgramID pid, NodeID nid, const Source& src);
|
|
||||||
/// Move constructor
|
|
||||||
FallthroughStatement(FallthroughStatement&&);
|
|
||||||
~FallthroughStatement() override;
|
|
||||||
|
|
||||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
|
||||||
/// `ctx`.
|
|
||||||
/// @param ctx the clone context
|
|
||||||
/// @return the newly cloned node
|
|
||||||
const FallthroughStatement* Clone(CloneContext* ctx) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace tint::ast
|
|
||||||
|
|
||||||
#endif // SRC_TINT_AST_FALLTHROUGH_STATEMENT_H_
|
|
|
@ -1,45 +0,0 @@
|
||||||
// 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 "src/tint/ast/fallthrough_statement.h"
|
|
||||||
|
|
||||||
#include "src/tint/ast/test_helper.h"
|
|
||||||
|
|
||||||
namespace tint::ast {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using FallthroughStatementTest = TestHelper;
|
|
||||||
|
|
||||||
TEST_F(FallthroughStatementTest, Creation) {
|
|
||||||
auto* stmt = create<FallthroughStatement>();
|
|
||||||
EXPECT_EQ(stmt->source.range.begin.line, 0u);
|
|
||||||
EXPECT_EQ(stmt->source.range.begin.column, 0u);
|
|
||||||
EXPECT_EQ(stmt->source.range.end.line, 0u);
|
|
||||||
EXPECT_EQ(stmt->source.range.end.column, 0u);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FallthroughStatementTest, Creation_WithSource) {
|
|
||||||
auto* stmt = create<FallthroughStatement>(Source{Source::Location{20, 2}});
|
|
||||||
auto src = stmt->source;
|
|
||||||
EXPECT_EQ(src.range.begin.line, 20u);
|
|
||||||
EXPECT_EQ(src.range.begin.column, 2u);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FallthroughStatementTest, IsFallthrough) {
|
|
||||||
auto* stmt = create<FallthroughStatement>();
|
|
||||||
EXPECT_TRUE(stmt->Is<FallthroughStatement>());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
} // namespace tint::ast
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "src/tint/ast/call_statement.h"
|
#include "src/tint/ast/call_statement.h"
|
||||||
#include "src/tint/ast/continue_statement.h"
|
#include "src/tint/ast/continue_statement.h"
|
||||||
#include "src/tint/ast/discard_statement.h"
|
#include "src/tint/ast/discard_statement.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/if_statement.h"
|
#include "src/tint/ast/if_statement.h"
|
||||||
#include "src/tint/ast/loop_statement.h"
|
#include "src/tint/ast/loop_statement.h"
|
||||||
#include "src/tint/ast/return_statement.h"
|
#include "src/tint/ast/return_statement.h"
|
||||||
|
@ -58,9 +57,6 @@ const char* Statement::Name() const {
|
||||||
if (Is<DiscardStatement>()) {
|
if (Is<DiscardStatement>()) {
|
||||||
return "discard statement";
|
return "discard statement";
|
||||||
}
|
}
|
||||||
if (Is<FallthroughStatement>()) {
|
|
||||||
return "fallthrough statement";
|
|
||||||
}
|
|
||||||
if (Is<IfStatement>()) {
|
if (Is<IfStatement>()) {
|
||||||
return "if statement";
|
return "if statement";
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "src/tint/ast/break_if_statement.h"
|
#include "src/tint/ast/break_if_statement.h"
|
||||||
#include "src/tint/ast/break_statement.h"
|
#include "src/tint/ast/break_statement.h"
|
||||||
#include "src/tint/ast/continue_statement.h"
|
#include "src/tint/ast/continue_statement.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/for_loop_statement.h"
|
#include "src/tint/ast/for_loop_statement.h"
|
||||||
#include "src/tint/ast/function.h"
|
#include "src/tint/ast/function.h"
|
||||||
#include "src/tint/ast/if_statement.h"
|
#include "src/tint/ast/if_statement.h"
|
||||||
|
@ -210,7 +209,6 @@ bool BuilderImpl::EmitStatement(const ast::Statement* stmt) {
|
||||||
// [&](const ast::CallStatement* c) { },
|
// [&](const ast::CallStatement* c) { },
|
||||||
[&](const ast::ContinueStatement* c) { return EmitContinue(c); },
|
[&](const ast::ContinueStatement* c) { return EmitContinue(c); },
|
||||||
// [&](const ast::DiscardStatement* d) { },
|
// [&](const ast::DiscardStatement* d) { },
|
||||||
[&](const ast::FallthroughStatement*) { return EmitFallthrough(); },
|
|
||||||
[&](const ast::IfStatement* i) { return EmitIf(i); },
|
[&](const ast::IfStatement* i) { return EmitIf(i); },
|
||||||
[&](const ast::LoopStatement* l) { return EmitLoop(l); },
|
[&](const ast::LoopStatement* l) { return EmitLoop(l); },
|
||||||
[&](const ast::ForLoopStatement* l) { return EmitForLoop(l); },
|
[&](const ast::ForLoopStatement* l) { return EmitForLoop(l); },
|
||||||
|
@ -415,25 +413,12 @@ bool BuilderImpl::EmitSwitch(const ast::SwitchStatement* stmt) {
|
||||||
{
|
{
|
||||||
FlowStackScope scope(this, switch_node);
|
FlowStackScope scope(this, switch_node);
|
||||||
|
|
||||||
// TODO(crbug.com/tint/1644): This can be simplifed when fallthrough is removed, a single
|
|
||||||
// loop can be used to iterate each body statement and emit for the case. Two loops are
|
|
||||||
// needed in order to have the target for a fallthrough.
|
|
||||||
for (const auto* c : stmt->body) {
|
for (const auto* c : stmt->body) {
|
||||||
builder_.CreateCase(switch_node, c->selectors);
|
current_flow_block_ = builder_.CreateCase(switch_node, c->selectors);
|
||||||
}
|
if (!EmitStatement(c->body)) {
|
||||||
|
|
||||||
for (size_t i = 0; i < stmt->body.Length(); ++i) {
|
|
||||||
current_flow_block_ = switch_node->cases[i].start_target;
|
|
||||||
if (i < (stmt->body.Length() - 1)) {
|
|
||||||
fallthrough_target_ = switch_node->cases[i + 1].start_target;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!EmitStatement(stmt->body[i]->body)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
BranchToIfNeeded(switch_node->merge_target);
|
BranchToIfNeeded(switch_node->merge_target);
|
||||||
|
|
||||||
fallthrough_target_ = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current_flow_block_ = nullptr;
|
current_flow_block_ = nullptr;
|
||||||
|
@ -514,10 +499,4 @@ bool BuilderImpl::EmitBreakIf(const ast::BreakIfStatement* stmt) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuilderImpl::EmitFallthrough() {
|
|
||||||
TINT_ASSERT(IR, fallthrough_target_ != nullptr);
|
|
||||||
BranchTo(fallthrough_target_);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
|
|
@ -134,10 +134,6 @@ class BuilderImpl {
|
||||||
/// @returns true if successful, false otherwise.
|
/// @returns true if successful, false otherwise.
|
||||||
bool EmitBreakIf(const ast::BreakIfStatement* stmt);
|
bool EmitBreakIf(const ast::BreakIfStatement* stmt);
|
||||||
|
|
||||||
/// Emits a fallthrough statement
|
|
||||||
/// @returns true if successful, false otherwise
|
|
||||||
bool EmitFallthrough();
|
|
||||||
|
|
||||||
/// Retrieve the IR Flow node for a given AST node.
|
/// Retrieve the IR Flow node for a given AST node.
|
||||||
/// @param n the node to lookup
|
/// @param n the node to lookup
|
||||||
/// @returns the FlowNode for the given ast::Node or nullptr if it doesn't exist.
|
/// @returns the FlowNode for the given ast::Node or nullptr if it doesn't exist.
|
||||||
|
@ -166,9 +162,6 @@ class BuilderImpl {
|
||||||
Block* current_flow_block_ = nullptr;
|
Block* current_flow_block_ = nullptr;
|
||||||
Function* current_function_ = nullptr;
|
Function* current_function_ = nullptr;
|
||||||
|
|
||||||
// TODO(crbug.com/tint/1644): Remove this when fallthrough is removed.
|
|
||||||
Block* fallthrough_target_ = nullptr;
|
|
||||||
|
|
||||||
/// Map from ast nodes to flow nodes, used to retrieve the flow node for a given AST node.
|
/// Map from ast nodes to flow nodes, used to retrieve the flow node for a given AST node.
|
||||||
/// Used for testing purposes.
|
/// Used for testing purposes.
|
||||||
std::unordered_map<const ast::Node*, const FlowNode*> ast_to_flow_;
|
std::unordered_map<const ast::Node*, const FlowNode*> ast_to_flow_;
|
||||||
|
|
|
@ -1313,64 +1313,5 @@ TEST_F(IRBuilderImplTest, Switch_AllReturn) {
|
||||||
EXPECT_EQ(flow->merge_target->branch_target, nullptr);
|
EXPECT_EQ(flow->merge_target->branch_target, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(crbug.com/tint/1644): Remove when fallthrough is removed.
|
|
||||||
TEST_F(IRBuilderImplTest, Switch_Fallthrough) {
|
|
||||||
// func -> switch -> case 1
|
|
||||||
// -> case 2
|
|
||||||
// -> default
|
|
||||||
//
|
|
||||||
// [case 1] -> switch merge
|
|
||||||
// [case 2] -> default
|
|
||||||
// [default] -> switch merge
|
|
||||||
// [switch merge] -> func end
|
|
||||||
//
|
|
||||||
auto* ast_switch =
|
|
||||||
Switch(1_i, utils::Vector{Case(utils::Vector{CaseSelector(0_i)}, Block()),
|
|
||||||
Case(utils::Vector{CaseSelector(1_i)}, Block(Fallthrough())),
|
|
||||||
DefaultCase(Block())});
|
|
||||||
|
|
||||||
WrapInFunction(ast_switch);
|
|
||||||
auto& b = Build();
|
|
||||||
|
|
||||||
auto r = b.Build();
|
|
||||||
ASSERT_TRUE(r) << b.error();
|
|
||||||
auto m = r.Move();
|
|
||||||
|
|
||||||
auto* ir_switch = b.FlowNodeForAstNode(ast_switch);
|
|
||||||
ASSERT_NE(ir_switch, nullptr);
|
|
||||||
ASSERT_TRUE(ir_switch->Is<ir::Switch>());
|
|
||||||
|
|
||||||
auto* flow = ir_switch->As<ir::Switch>();
|
|
||||||
ASSERT_NE(flow->merge_target, nullptr);
|
|
||||||
ASSERT_EQ(3u, flow->cases.Length());
|
|
||||||
|
|
||||||
ASSERT_EQ(1u, m.functions.Length());
|
|
||||||
auto* func = m.functions[0];
|
|
||||||
|
|
||||||
ASSERT_EQ(1u, flow->cases[0].selectors.Length());
|
|
||||||
ASSERT_TRUE(flow->cases[0].selectors[0]->expr->Is<ast::IntLiteralExpression>());
|
|
||||||
EXPECT_EQ(0_i, flow->cases[0].selectors[0]->expr->As<ast::IntLiteralExpression>()->value);
|
|
||||||
|
|
||||||
ASSERT_EQ(1u, flow->cases[1].selectors.Length());
|
|
||||||
ASSERT_TRUE(flow->cases[1].selectors[0]->expr->Is<ast::IntLiteralExpression>());
|
|
||||||
EXPECT_EQ(1_i, flow->cases[1].selectors[0]->expr->As<ast::IntLiteralExpression>()->value);
|
|
||||||
|
|
||||||
ASSERT_EQ(1u, flow->cases[2].selectors.Length());
|
|
||||||
EXPECT_TRUE(flow->cases[2].selectors[0]->IsDefault());
|
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
|
||||||
EXPECT_EQ(1u, flow->cases[0].start_target->inbound_branches.Length());
|
|
||||||
EXPECT_EQ(1u, flow->cases[1].start_target->inbound_branches.Length());
|
|
||||||
EXPECT_EQ(2u, flow->cases[2].start_target->inbound_branches.Length());
|
|
||||||
EXPECT_EQ(2u, flow->merge_target->inbound_branches.Length());
|
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
|
||||||
|
|
||||||
EXPECT_EQ(func->start_target->branch_target, ir_switch);
|
|
||||||
EXPECT_EQ(flow->cases[0].start_target->branch_target, flow->merge_target);
|
|
||||||
EXPECT_EQ(flow->cases[1].start_target->branch_target, flow->cases[2].start_target);
|
|
||||||
EXPECT_EQ(flow->cases[2].start_target->branch_target, flow->merge_target);
|
|
||||||
EXPECT_EQ(flow->merge_target->branch_target, func->end_target);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
#include "src/tint/ast/external_texture.h"
|
#include "src/tint/ast/external_texture.h"
|
||||||
#include "src/tint/ast/f16.h"
|
#include "src/tint/ast/f16.h"
|
||||||
#include "src/tint/ast/f32.h"
|
#include "src/tint/ast/f32.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/float_literal_expression.h"
|
#include "src/tint/ast/float_literal_expression.h"
|
||||||
#include "src/tint/ast/for_loop_statement.h"
|
#include "src/tint/ast/for_loop_statement.h"
|
||||||
#include "src/tint/ast/i32.h"
|
#include "src/tint/ast/i32.h"
|
||||||
|
@ -2932,17 +2931,6 @@ class ProgramBuilder {
|
||||||
/// @returns the selector pointer
|
/// @returns the selector pointer
|
||||||
const ast::CaseSelector* DefaultCaseSelector() { return create<ast::CaseSelector>(nullptr); }
|
const ast::CaseSelector* DefaultCaseSelector() { return create<ast::CaseSelector>(nullptr); }
|
||||||
|
|
||||||
/// Creates an ast::FallthroughStatement
|
|
||||||
/// @param source the source information
|
|
||||||
/// @returns the fallthrough statement pointer
|
|
||||||
const ast::FallthroughStatement* Fallthrough(const Source& source) {
|
|
||||||
return create<ast::FallthroughStatement>(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an ast::FallthroughStatement
|
|
||||||
/// @returns the fallthrough statement pointer
|
|
||||||
const ast::FallthroughStatement* Fallthrough() { return create<ast::FallthroughStatement>(); }
|
|
||||||
|
|
||||||
/// Creates an ast::BuiltinAttribute
|
/// Creates an ast::BuiltinAttribute
|
||||||
/// @param source the source information
|
/// @param source the source information
|
||||||
/// @param builtin the builtin value
|
/// @param builtin the builtin value
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
#include "src/tint/ast/break_statement.h"
|
#include "src/tint/ast/break_statement.h"
|
||||||
#include "src/tint/ast/continue_statement.h"
|
#include "src/tint/ast/continue_statement.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/switch_statement.h"
|
#include "src/tint/ast/switch_statement.h"
|
||||||
#include "src/tint/resolver/resolver_test_helper.h"
|
#include "src/tint/resolver/resolver_test_helper.h"
|
||||||
|
|
||||||
|
@ -378,24 +377,6 @@ TEST_F(ResolverControlBlockValidationTest, NonUniqueCaseSelectorValueSint_Fail)
|
||||||
"12:34 note: previous case declared here");
|
"12:34 note: previous case declared here");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverControlBlockValidationTest, LastClauseLastStatementIsFallthrough_Fail) {
|
|
||||||
// var a : i32 = 2;
|
|
||||||
// switch (a) {
|
|
||||||
// default: { fallthrough; }
|
|
||||||
// }
|
|
||||||
auto* var = Var("a", ty.i32(), Expr(2_i));
|
|
||||||
auto* fallthrough = create<ast::FallthroughStatement>(Source{{12, 34}});
|
|
||||||
auto* block = Block(Decl(var), //
|
|
||||||
Switch("a", //
|
|
||||||
DefaultCase(Block(fallthrough))));
|
|
||||||
WrapInFunction(block);
|
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
|
||||||
EXPECT_EQ(r()->error(),
|
|
||||||
"12:34 error: a fallthrough statement must not be used in the last "
|
|
||||||
"switch case");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ResolverControlBlockValidationTest, SwitchCase_Pass) {
|
TEST_F(ResolverControlBlockValidationTest, SwitchCase_Pass) {
|
||||||
// var a : i32 = 2;
|
// var a : i32 = 2;
|
||||||
// switch (a) {
|
// switch (a) {
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
#include "src/tint/ast/external_texture.h"
|
#include "src/tint/ast/external_texture.h"
|
||||||
#include "src/tint/ast/f16.h"
|
#include "src/tint/ast/f16.h"
|
||||||
#include "src/tint/ast/f32.h"
|
#include "src/tint/ast/f32.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/for_loop_statement.h"
|
#include "src/tint/ast/for_loop_statement.h"
|
||||||
#include "src/tint/ast/i32.h"
|
#include "src/tint/ast/i32.h"
|
||||||
#include "src/tint/ast/id_attribute.h"
|
#include "src/tint/ast/id_attribute.h"
|
||||||
|
@ -320,7 +319,7 @@ class DependencyScanner {
|
||||||
[&](const ast::StaticAssert* assertion) { TraverseExpression(assertion->condition); },
|
[&](const ast::StaticAssert* assertion) { TraverseExpression(assertion->condition); },
|
||||||
[&](Default) {
|
[&](Default) {
|
||||||
if (!stmt->IsAnyOf<ast::BreakStatement, ast::ContinueStatement,
|
if (!stmt->IsAnyOf<ast::BreakStatement, ast::ContinueStatement,
|
||||||
ast::DiscardStatement, ast::FallthroughStatement>()) {
|
ast::DiscardStatement>()) {
|
||||||
UnhandledNode(diagnostics_, stmt);
|
UnhandledNode(diagnostics_, stmt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1273,8 +1273,6 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
|
||||||
Switch(V, //
|
Switch(V, //
|
||||||
Case(CaseSelector(1_i), //
|
Case(CaseSelector(1_i), //
|
||||||
Block(Assign(V, V))), //
|
Block(Assign(V, V))), //
|
||||||
Case(CaseSelector(2_i), //
|
|
||||||
Block(Fallthrough())), //
|
|
||||||
DefaultCase(Block(Assign(V, V)))), //
|
DefaultCase(Block(Assign(V, V)))), //
|
||||||
Return(V), //
|
Return(V), //
|
||||||
Break(), //
|
Break(), //
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
#include "src/tint/ast/depth_texture.h"
|
#include "src/tint/ast/depth_texture.h"
|
||||||
#include "src/tint/ast/disable_validation_attribute.h"
|
#include "src/tint/ast/disable_validation_attribute.h"
|
||||||
#include "src/tint/ast/discard_statement.h"
|
#include "src/tint/ast/discard_statement.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/for_loop_statement.h"
|
#include "src/tint/ast/for_loop_statement.h"
|
||||||
#include "src/tint/ast/id_attribute.h"
|
#include "src/tint/ast/id_attribute.h"
|
||||||
#include "src/tint/ast/if_statement.h"
|
#include "src/tint/ast/if_statement.h"
|
||||||
|
@ -1217,7 +1216,6 @@ sem::Statement* Resolver::Statement(const ast::Statement* stmt) {
|
||||||
[&](const ast::CompoundAssignmentStatement* c) { return CompoundAssignmentStatement(c); },
|
[&](const ast::CompoundAssignmentStatement* c) { return CompoundAssignmentStatement(c); },
|
||||||
[&](const ast::ContinueStatement* c) { return ContinueStatement(c); },
|
[&](const ast::ContinueStatement* c) { return ContinueStatement(c); },
|
||||||
[&](const ast::DiscardStatement* d) { return DiscardStatement(d); },
|
[&](const ast::DiscardStatement* d) { return DiscardStatement(d); },
|
||||||
[&](const ast::FallthroughStatement* f) { return FallthroughStatement(f); },
|
|
||||||
[&](const ast::IncrementDecrementStatement* i) { return IncrementDecrementStatement(i); },
|
[&](const ast::IncrementDecrementStatement* i) { return IncrementDecrementStatement(i); },
|
||||||
[&](const ast::ReturnStatement* r) { return ReturnStatement(r); },
|
[&](const ast::ReturnStatement* r) { return ReturnStatement(r); },
|
||||||
[&](const ast::VariableDeclStatement* v) { return VariableDeclStatement(v); },
|
[&](const ast::VariableDeclStatement* v) { return VariableDeclStatement(v); },
|
||||||
|
@ -3146,7 +3144,7 @@ sem::SwitchStatement* Resolver::SwitchStatement(const ast::SwitchStatement* stmt
|
||||||
if (behaviors.Contains(sem::Behavior::kBreak)) {
|
if (behaviors.Contains(sem::Behavior::kBreak)) {
|
||||||
behaviors.Add(sem::Behavior::kNext);
|
behaviors.Add(sem::Behavior::kNext);
|
||||||
}
|
}
|
||||||
behaviors.Remove(sem::Behavior::kBreak, sem::Behavior::kFallthrough);
|
behaviors.Remove(sem::Behavior::kBreak);
|
||||||
|
|
||||||
return validator_.SwitchStatement(stmt);
|
return validator_.SwitchStatement(stmt);
|
||||||
});
|
});
|
||||||
|
@ -3308,16 +3306,6 @@ sem::Statement* Resolver::DiscardStatement(const ast::DiscardStatement* stmt) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::Statement* Resolver::FallthroughStatement(const ast::FallthroughStatement* stmt) {
|
|
||||||
auto* sem =
|
|
||||||
builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
|
|
||||||
return StatementScope(stmt, sem, [&] {
|
|
||||||
sem->Behaviors() = sem::Behavior::kFallthrough;
|
|
||||||
|
|
||||||
return validator_.FallthroughStatement(sem);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
sem::Statement* Resolver::IncrementDecrementStatement(
|
sem::Statement* Resolver::IncrementDecrementStatement(
|
||||||
const ast::IncrementDecrementStatement* stmt) {
|
const ast::IncrementDecrementStatement* stmt) {
|
||||||
auto* sem =
|
auto* sem =
|
||||||
|
|
|
@ -212,7 +212,6 @@ class Resolver {
|
||||||
sem::Statement* CompoundAssignmentStatement(const ast::CompoundAssignmentStatement*);
|
sem::Statement* CompoundAssignmentStatement(const ast::CompoundAssignmentStatement*);
|
||||||
sem::Statement* ContinueStatement(const ast::ContinueStatement*);
|
sem::Statement* ContinueStatement(const ast::ContinueStatement*);
|
||||||
sem::Statement* DiscardStatement(const ast::DiscardStatement*);
|
sem::Statement* DiscardStatement(const ast::DiscardStatement*);
|
||||||
sem::Statement* FallthroughStatement(const ast::FallthroughStatement*);
|
|
||||||
sem::ForLoopStatement* ForLoopStatement(const ast::ForLoopStatement*);
|
sem::ForLoopStatement* ForLoopStatement(const ast::ForLoopStatement*);
|
||||||
sem::WhileStatement* WhileStatement(const ast::WhileStatement*);
|
sem::WhileStatement* WhileStatement(const ast::WhileStatement*);
|
||||||
sem::GlobalVariable* GlobalVariable(const ast::Variable*);
|
sem::GlobalVariable* GlobalVariable(const ast::Variable*);
|
||||||
|
|
|
@ -477,10 +477,9 @@ class UniformityGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Propagate all variables assignments to the containing scope if the behavior is
|
// Propagate all variables assignments to the containing scope if the behavior is
|
||||||
// either 'Next' or 'Fallthrough'.
|
// 'Next'.
|
||||||
auto& behaviors = sem_.Get(b)->Behaviors();
|
auto& behaviors = sem_.Get(b)->Behaviors();
|
||||||
if (behaviors.Contains(sem::Behavior::kNext) ||
|
if (behaviors.Contains(sem::Behavior::kNext)) {
|
||||||
behaviors.Contains(sem::Behavior::kFallthrough)) {
|
|
||||||
for (auto var : scoped_assignments) {
|
for (auto var : scoped_assignments) {
|
||||||
current_function_->variables.Set(var.key, var.value);
|
current_function_->variables.Set(var.key, var.value);
|
||||||
}
|
}
|
||||||
|
@ -613,8 +612,6 @@ class UniformityGraph {
|
||||||
|
|
||||||
[&](const ast::DiscardStatement*) { return cf; },
|
[&](const ast::DiscardStatement*) { return cf; },
|
||||||
|
|
||||||
[&](const ast::FallthroughStatement*) { return cf; },
|
|
||||||
|
|
||||||
[&](const ast::ForLoopStatement* f) {
|
[&](const ast::ForLoopStatement* f) {
|
||||||
auto* sem_loop = sem_.Get(f);
|
auto* sem_loop = sem_.Get(f);
|
||||||
auto* cfx = CreateNode("loop_start");
|
auto* cfx = CreateNode("loop_start");
|
||||||
|
@ -937,46 +934,35 @@ class UniformityGraph {
|
||||||
info.type = "switch";
|
info.type = "switch";
|
||||||
|
|
||||||
auto* cf_n = v;
|
auto* cf_n = v;
|
||||||
bool previous_case_has_fallthrough = false;
|
|
||||||
for (auto* c : s->body) {
|
for (auto* c : s->body) {
|
||||||
auto* sem_case = sem_.Get(c);
|
auto* sem_case = sem_.Get(c);
|
||||||
|
|
||||||
if (previous_case_has_fallthrough) {
|
current_function_->variables.Push();
|
||||||
cf_n = ProcessStatement(cf_n, c->body);
|
cf_n = ProcessStatement(v, c->body);
|
||||||
} else {
|
|
||||||
current_function_->variables.Push();
|
|
||||||
cf_n = ProcessStatement(v, c->body);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cf_end) {
|
if (cf_end) {
|
||||||
cf_end->AddEdge(cf_n);
|
cf_end->AddEdge(cf_n);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_fallthrough =
|
if (sem_case->Behaviors().Contains(sem::Behavior::kNext)) {
|
||||||
sem_case->Behaviors().Contains(sem::Behavior::kFallthrough);
|
// Propagate variable values to the switch exit nodes.
|
||||||
if (!has_fallthrough) {
|
for (auto* var : current_function_->local_var_decls) {
|
||||||
if (sem_case->Behaviors().Contains(sem::Behavior::kNext)) {
|
// Skip variables that were declared inside the switch.
|
||||||
// Propagate variable values to the switch exit nodes.
|
if (auto* lv = var->As<sem::LocalVariable>();
|
||||||
for (auto* var : current_function_->local_var_decls) {
|
lv && lv->Statement()->FindFirstParent(
|
||||||
// Skip variables that were declared inside the switch.
|
[&](auto* st) { return st == sem_switch; })) {
|
||||||
if (auto* lv = var->As<sem::LocalVariable>();
|
continue;
|
||||||
lv && lv->Statement()->FindFirstParent(
|
|
||||||
[&](auto* st) { return st == sem_switch; })) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an edge from the variable exit node to its new value.
|
|
||||||
auto* exit_node = info.var_exit_nodes.GetOrCreate(var, [&]() {
|
|
||||||
auto name =
|
|
||||||
builder_->Symbols().NameFor(var->Declaration()->symbol);
|
|
||||||
return CreateNode(name + "_value_" + info.type + "_exit");
|
|
||||||
});
|
|
||||||
exit_node->AddEdge(current_function_->variables.Get(var));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add an edge from the variable exit node to its new value.
|
||||||
|
auto* exit_node = info.var_exit_nodes.GetOrCreate(var, [&]() {
|
||||||
|
auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
|
||||||
|
return CreateNode(name + "_value_" + info.type + "_exit");
|
||||||
|
});
|
||||||
|
exit_node->AddEdge(current_function_->variables.Get(var));
|
||||||
}
|
}
|
||||||
current_function_->variables.Pop();
|
|
||||||
}
|
}
|
||||||
previous_case_has_fallthrough = has_fallthrough;
|
current_function_->variables.Pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update nodes for any variables assigned in the switch statement.
|
// Update nodes for any variables assigned in the switch statement.
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
#include "src/tint/ast/depth_texture.h"
|
#include "src/tint/ast/depth_texture.h"
|
||||||
#include "src/tint/ast/disable_validation_attribute.h"
|
#include "src/tint/ast/disable_validation_attribute.h"
|
||||||
#include "src/tint/ast/discard_statement.h"
|
#include "src/tint/ast/discard_statement.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/for_loop_statement.h"
|
#include "src/tint/ast/for_loop_statement.h"
|
||||||
#include "src/tint/ast/id_attribute.h"
|
#include "src/tint/ast/id_attribute.h"
|
||||||
#include "src/tint/ast/if_statement.h"
|
#include "src/tint/ast/if_statement.h"
|
||||||
|
@ -1538,26 +1537,6 @@ bool Validator::Call(const sem::Call* call, sem::Statement* current_statement) c
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Validator::FallthroughStatement(const sem::Statement* stmt) const {
|
|
||||||
if (auto* block = As<sem::BlockStatement>(stmt->Parent())) {
|
|
||||||
if (auto* c = As<sem::CaseStatement>(block->Parent())) {
|
|
||||||
if (block->Declaration()->Last() == stmt->Declaration()) {
|
|
||||||
if (auto* s = As<sem::SwitchStatement>(c->Parent())) {
|
|
||||||
if (c->Declaration() != s->Declaration()->body.Back()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
AddError("a fallthrough statement must not be used in the last switch case",
|
|
||||||
stmt->Declaration()->source);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AddError("fallthrough must only be used as the last statement of a case block",
|
|
||||||
stmt->Declaration()->source);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Validator::LoopStatement(const sem::LoopStatement* stmt) const {
|
bool Validator::LoopStatement(const sem::LoopStatement* stmt) const {
|
||||||
if (stmt->Behaviors().Empty()) {
|
if (stmt->Behaviors().Empty()) {
|
||||||
AddError("loop does not exit", stmt->Declaration()->source.Begin());
|
AddError("loop does not exit", stmt->Declaration()->source.Begin());
|
||||||
|
|
|
@ -223,11 +223,6 @@ class Validator {
|
||||||
/// @returns true on success, false otherwise
|
/// @returns true on success, false otherwise
|
||||||
bool WhileStatement(const sem::WhileStatement* stmt) const;
|
bool WhileStatement(const sem::WhileStatement* stmt) const;
|
||||||
|
|
||||||
/// Validates a fallthrough statement
|
|
||||||
/// @param stmt the fallthrough to validate
|
|
||||||
/// @returns true on success, false otherwise
|
|
||||||
bool FallthroughStatement(const sem::Statement* stmt) const;
|
|
||||||
|
|
||||||
/// Validates a function
|
/// Validates a function
|
||||||
/// @param func the function to validate
|
/// @param func the function to validate
|
||||||
/// @param stage the current pipeline stage
|
/// @param stage the current pipeline stage
|
||||||
|
|
|
@ -24,8 +24,6 @@ std::ostream& operator<<(std::ostream& out, Behavior behavior) {
|
||||||
return out << "Break";
|
return out << "Break";
|
||||||
case Behavior::kContinue:
|
case Behavior::kContinue:
|
||||||
return out << "Continue";
|
return out << "Continue";
|
||||||
case Behavior::kFallthrough:
|
|
||||||
return out << "Fallthrough";
|
|
||||||
case Behavior::kNext:
|
case Behavior::kNext:
|
||||||
return out << "Next";
|
return out << "Next";
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ enum class Behavior {
|
||||||
kReturn,
|
kReturn,
|
||||||
kBreak,
|
kBreak,
|
||||||
kContinue,
|
kContinue,
|
||||||
kFallthrough,
|
|
||||||
kNext,
|
kNext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "src/tint/ast/call_statement.h"
|
#include "src/tint/ast/call_statement.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/id_attribute.h"
|
#include "src/tint/ast/id_attribute.h"
|
||||||
#include "src/tint/ast/internal_attribute.h"
|
#include "src/tint/ast/internal_attribute.h"
|
||||||
#include "src/tint/ast/interpolate_attribute.h"
|
#include "src/tint/ast/interpolate_attribute.h"
|
||||||
|
@ -104,8 +103,8 @@ namespace {
|
||||||
|
|
||||||
const char kTempNamePrefix[] = "tint_tmp";
|
const char kTempNamePrefix[] = "tint_tmp";
|
||||||
|
|
||||||
bool last_is_break_or_fallthrough(const ast::BlockStatement* stmts) {
|
bool last_is_break(const ast::BlockStatement* stmts) {
|
||||||
return IsAnyOf<ast::BreakStatement, ast::FallthroughStatement>(stmts->Last());
|
return IsAnyOf<ast::BreakStatement>(stmts->Last());
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* convert_texel_format_to_glsl(const ast::TexelFormat format) {
|
const char* convert_texel_format_to_glsl(const ast::TexelFormat format) {
|
||||||
|
@ -1821,7 +1820,7 @@ bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
|
||||||
if (!EmitStatements(stmt->body->statements)) {
|
if (!EmitStatements(stmt->body->statements)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!last_is_break_or_fallthrough(stmt->body)) {
|
if (!last_is_break(stmt->body)) {
|
||||||
line() << "break;";
|
line() << "break;";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2748,10 +2747,6 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
|
||||||
},
|
},
|
||||||
[&](const ast::ContinueStatement* c) { return EmitContinue(c); },
|
[&](const ast::ContinueStatement* c) { return EmitContinue(c); },
|
||||||
[&](const ast::DiscardStatement* d) { return EmitDiscard(d); },
|
[&](const ast::DiscardStatement* d) { return EmitDiscard(d); },
|
||||||
[&](const ast::FallthroughStatement*) {
|
|
||||||
line() << "/* fallthrough */";
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
[&](const ast::IfStatement* i) { return EmitIf(i); },
|
[&](const ast::IfStatement* i) { return EmitIf(i); },
|
||||||
[&](const ast::LoopStatement* l) { return EmitLoop(l); },
|
[&](const ast::LoopStatement* l) { return EmitLoop(l); },
|
||||||
[&](const ast::ForLoopStatement* l) { return EmitForLoop(l); },
|
[&](const ast::ForLoopStatement* l) { return EmitForLoop(l); },
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/writer/glsl/test_helper.h"
|
#include "src/tint/writer/glsl/test_helper.h"
|
||||||
|
|
||||||
using namespace tint::number_suffixes; // NOLINT
|
using namespace tint::number_suffixes; // NOLINT
|
||||||
|
@ -53,22 +52,6 @@ TEST_F(GlslGeneratorImplTest_Case, Emit_Case_BreaksByDefault) {
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(GlslGeneratorImplTest_Case, Emit_Case_WithFallthrough) {
|
|
||||||
auto* s = Switch(1_i, Case(CaseSelector(5_i), Block(create<ast::FallthroughStatement>())),
|
|
||||||
DefaultCase());
|
|
||||||
WrapInFunction(s);
|
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
|
||||||
|
|
||||||
gen.increment_indent();
|
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
|
|
||||||
EXPECT_EQ(gen.result(), R"( case 5: {
|
|
||||||
/* fallthrough */
|
|
||||||
}
|
|
||||||
)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(GlslGeneratorImplTest_Case, Emit_Case_MultipleSelectors) {
|
TEST_F(GlslGeneratorImplTest_Case, Emit_Case_MultipleSelectors) {
|
||||||
auto* s = Switch(1_i,
|
auto* s = Switch(1_i,
|
||||||
Case(
|
Case(
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "src/tint/ast/call_statement.h"
|
#include "src/tint/ast/call_statement.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/id_attribute.h"
|
#include "src/tint/ast/id_attribute.h"
|
||||||
#include "src/tint/ast/internal_attribute.h"
|
#include "src/tint/ast/internal_attribute.h"
|
||||||
#include "src/tint/ast/interpolate_attribute.h"
|
#include "src/tint/ast/interpolate_attribute.h"
|
||||||
|
@ -2506,18 +2505,7 @@ bool GeneratorImpl::EmitCase(const ast::SwitchStatement* s, size_t case_idx) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline all fallthrough case statements. FXC cannot handle fallthroughs.
|
if (!tint::IsAnyOf<ast::BreakStatement>(stmt->body->Last())) {
|
||||||
while (tint::Is<ast::FallthroughStatement>(stmt->body->Last())) {
|
|
||||||
case_idx++;
|
|
||||||
stmt = s->body[case_idx];
|
|
||||||
// Generate each fallthrough case statement in a new block. This is done to
|
|
||||||
// prevent symbol collision of variables declared in these cases statements.
|
|
||||||
if (!EmitBlock(stmt->body)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tint::IsAnyOf<ast::BreakStatement, ast::FallthroughStatement>(stmt->body->Last())) {
|
|
||||||
line() << "break;";
|
line() << "break;";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3534,10 +3522,6 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
|
||||||
[&](const ast::DiscardStatement* d) { //
|
[&](const ast::DiscardStatement* d) { //
|
||||||
return EmitDiscard(d);
|
return EmitDiscard(d);
|
||||||
},
|
},
|
||||||
[&](const ast::FallthroughStatement*) { //
|
|
||||||
line() << "/* fallthrough */";
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
[&](const ast::IfStatement* i) { //
|
[&](const ast::IfStatement* i) { //
|
||||||
return EmitIf(i);
|
return EmitIf(i);
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/writer/hlsl/test_helper.h"
|
#include "src/tint/writer/hlsl/test_helper.h"
|
||||||
|
|
||||||
using namespace tint::number_suffixes; // NOLINT
|
using namespace tint::number_suffixes; // NOLINT
|
||||||
|
@ -53,28 +52,6 @@ TEST_F(HlslGeneratorImplTest_Case, Emit_Case_BreaksByDefault) {
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Case, Emit_Case_WithFallthrough) {
|
|
||||||
auto* s = Switch(1_i, //
|
|
||||||
Case(CaseSelector(4_i), Block(create<ast::FallthroughStatement>())), //
|
|
||||||
Case(CaseSelector(5_i), Block(create<ast::ReturnStatement>())), //
|
|
||||||
DefaultCase());
|
|
||||||
WrapInFunction(s);
|
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
|
||||||
|
|
||||||
gen.increment_indent();
|
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.error();
|
|
||||||
EXPECT_EQ(gen.result(), R"( case 4: {
|
|
||||||
/* fallthrough */
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Case, Emit_Case_MultipleSelectors) {
|
TEST_F(HlslGeneratorImplTest_Case, Emit_Case_MultipleSelectors) {
|
||||||
auto* s = Switch(1_i,
|
auto* s = Switch(1_i,
|
||||||
Case(utils::Vector{CaseSelector(5_i), CaseSelector(6_i)},
|
Case(utils::Vector{CaseSelector(5_i), CaseSelector(6_i)},
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include "src/tint/ast/bool_literal_expression.h"
|
#include "src/tint/ast/bool_literal_expression.h"
|
||||||
#include "src/tint/ast/call_statement.h"
|
#include "src/tint/ast/call_statement.h"
|
||||||
#include "src/tint/ast/disable_validation_attribute.h"
|
#include "src/tint/ast/disable_validation_attribute.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/float_literal_expression.h"
|
#include "src/tint/ast/float_literal_expression.h"
|
||||||
#include "src/tint/ast/id_attribute.h"
|
#include "src/tint/ast/id_attribute.h"
|
||||||
#include "src/tint/ast/interpolate_attribute.h"
|
#include "src/tint/ast/interpolate_attribute.h"
|
||||||
|
@ -85,8 +84,8 @@
|
||||||
namespace tint::writer::msl {
|
namespace tint::writer::msl {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool last_is_break_or_fallthrough(const ast::BlockStatement* stmts) {
|
bool last_is_break(const ast::BlockStatement* stmts) {
|
||||||
return IsAnyOf<ast::BreakStatement, ast::FallthroughStatement>(stmts->Last());
|
return IsAnyOf<ast::BreakStatement>(stmts->Last());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintF32(std::ostream& out, float value) {
|
void PrintF32(std::ostream& out, float value) {
|
||||||
|
@ -1587,7 +1586,7 @@ bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!last_is_break_or_fallthrough(stmt->body)) {
|
if (!last_is_break(stmt->body)) {
|
||||||
line() << "break;";
|
line() << "break;";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2426,10 +2425,6 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
|
||||||
[&](const ast::DiscardStatement* d) { //
|
[&](const ast::DiscardStatement* d) { //
|
||||||
return EmitDiscard(d);
|
return EmitDiscard(d);
|
||||||
},
|
},
|
||||||
[&](const ast::FallthroughStatement*) { //
|
|
||||||
line() << "/* fallthrough */";
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
[&](const ast::IfStatement* i) { //
|
[&](const ast::IfStatement* i) { //
|
||||||
return EmitIf(i);
|
return EmitIf(i);
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/writer/msl/test_helper.h"
|
#include "src/tint/writer/msl/test_helper.h"
|
||||||
|
|
||||||
using namespace tint::number_suffixes; // NOLINT
|
using namespace tint::number_suffixes; // NOLINT
|
||||||
|
@ -53,22 +52,6 @@ TEST_F(MslGeneratorImplTest, Emit_Case_BreaksByDefault) {
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, Emit_Case_WithFallthrough) {
|
|
||||||
auto* s = Switch(1_i, Case(CaseSelector(5_i), Block(create<ast::FallthroughStatement>())),
|
|
||||||
DefaultCase());
|
|
||||||
WrapInFunction(s);
|
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
|
||||||
|
|
||||||
gen.increment_indent();
|
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
|
|
||||||
EXPECT_EQ(gen.result(), R"( case 5: {
|
|
||||||
/* fallthrough */
|
|
||||||
}
|
|
||||||
)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, Emit_Case_MultipleSelectors) {
|
TEST_F(MslGeneratorImplTest, Emit_Case_MultipleSelectors) {
|
||||||
auto* s = Switch(1_i,
|
auto* s = Switch(1_i,
|
||||||
Case(
|
Case(
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
#include "spirv/unified1/GLSL.std.450.h"
|
#include "spirv/unified1/GLSL.std.450.h"
|
||||||
#include "src/tint/ast/call_statement.h"
|
#include "src/tint/ast/call_statement.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/id_attribute.h"
|
#include "src/tint/ast/id_attribute.h"
|
||||||
#include "src/tint/ast/internal_attribute.h"
|
#include "src/tint/ast/internal_attribute.h"
|
||||||
#include "src/tint/ast/traverse_expressions.h"
|
#include "src/tint/ast/traverse_expressions.h"
|
||||||
|
@ -86,10 +85,6 @@ uint32_t pipeline_stage_to_execution_model(ast::PipelineStage stage) {
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LastIsFallthrough(const ast::BlockStatement* stmts) {
|
|
||||||
return !stmts->Empty() && stmts->Last()->Is<ast::FallthroughStatement>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the matrix type that is `type` or that is wrapped by
|
/// Returns the matrix type that is `type` or that is wrapped by
|
||||||
/// one or more levels of an arrays inside of `type`.
|
/// one or more levels of an arrays inside of `type`.
|
||||||
/// @param type the given type, which must not be null
|
/// @param type the given type, which must not be null
|
||||||
|
@ -3515,9 +3510,7 @@ bool Builder::GenerateSwitchStatement(const ast::SwitchStatement* stmt) {
|
||||||
bool generated_default = false;
|
bool generated_default = false;
|
||||||
auto& body = stmt->body;
|
auto& body = stmt->body;
|
||||||
// We output the case statements in order they were entered in the original
|
// We output the case statements in order they were entered in the original
|
||||||
// source. Each fallthrough goes to the next case entry, so is a forward
|
// source. The branch is to the merge block which comes after the switch statement.
|
||||||
// branch, otherwise the branch is to the merge block which comes after
|
|
||||||
// the switch statement.
|
|
||||||
for (uint32_t i = 0; i < body.Length(); i++) {
|
for (uint32_t i = 0; i < body.Length(); i++) {
|
||||||
auto* item = body[i];
|
auto* item = body[i];
|
||||||
|
|
||||||
|
@ -3531,17 +3524,7 @@ bool Builder::GenerateSwitchStatement(const ast::SwitchStatement* stmt) {
|
||||||
if (!GenerateBlockStatement(item->body)) {
|
if (!GenerateBlockStatement(item->body)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (InsideBasicBlock()) {
|
||||||
if (LastIsFallthrough(item->body)) {
|
|
||||||
if (i == (body.Length() - 1)) {
|
|
||||||
// This case is caught by Resolver validation
|
|
||||||
TINT_UNREACHABLE(Writer, builder_.Diagnostics());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!push_function_inst(spv::Op::OpBranch, {Operand(case_ids[i + 1])})) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (InsideBasicBlock()) {
|
|
||||||
if (!push_function_inst(spv::Op::OpBranch, {Operand(merge_block_id)})) {
|
if (!push_function_inst(spv::Op::OpBranch, {Operand(merge_block_id)})) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3671,10 +3654,6 @@ bool Builder::GenerateStatement(const ast::Statement* stmt) {
|
||||||
[&](const ast::CallStatement* c) { return GenerateCallExpression(c->expr) != 0; },
|
[&](const ast::CallStatement* c) { return GenerateCallExpression(c->expr) != 0; },
|
||||||
[&](const ast::ContinueStatement* c) { return GenerateContinueStatement(c); },
|
[&](const ast::ContinueStatement* c) { return GenerateContinueStatement(c); },
|
||||||
[&](const ast::DiscardStatement* d) { return GenerateDiscardStatement(d); },
|
[&](const ast::DiscardStatement* d) { return GenerateDiscardStatement(d); },
|
||||||
[&](const ast::FallthroughStatement*) {
|
|
||||||
// Do nothing here, the fallthrough gets handled by the switch code.
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
[&](const ast::IfStatement* i) { return GenerateIfStatement(i); },
|
[&](const ast::IfStatement* i) { return GenerateIfStatement(i); },
|
||||||
[&](const ast::LoopStatement* l) { return GenerateLoopStatement(l); },
|
[&](const ast::LoopStatement* l) { return GenerateLoopStatement(l); },
|
||||||
[&](const ast::ReturnStatement* r) { return GenerateReturnStatement(r); },
|
[&](const ast::ReturnStatement* r) { return GenerateReturnStatement(r); },
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/writer/spirv/spv_dump.h"
|
#include "src/tint/writer/spirv/spv_dump.h"
|
||||||
#include "src/tint/writer/spirv/test_helper.h"
|
#include "src/tint/writer/spirv/test_helper.h"
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/writer/spirv/spv_dump.h"
|
#include "src/tint/writer/spirv/spv_dump.h"
|
||||||
#include "src/tint/writer/spirv/test_helper.h"
|
#include "src/tint/writer/spirv/test_helper.h"
|
||||||
|
|
||||||
|
@ -328,69 +327,6 @@ OpFunctionEnd
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BuilderTest, Switch_CaseWithFallthrough) {
|
|
||||||
// switch(a) {
|
|
||||||
// case 1i:
|
|
||||||
// v = 1i;
|
|
||||||
// fallthrough;
|
|
||||||
// case 2i:
|
|
||||||
// v = 2i;
|
|
||||||
// default: {}
|
|
||||||
// v = 3i;
|
|
||||||
// }
|
|
||||||
|
|
||||||
auto* v = GlobalVar("v", ty.i32(), ast::AddressSpace::kPrivate);
|
|
||||||
auto* a = GlobalVar("a", ty.i32(), ast::AddressSpace::kPrivate);
|
|
||||||
|
|
||||||
auto* func = Func("a_func", utils::Empty, ty.void_(),
|
|
||||||
utils::Vector{
|
|
||||||
Switch(Expr("a"), //
|
|
||||||
Case(CaseSelector(1_i), //
|
|
||||||
Block(Assign("v", 1_i), Fallthrough())), //
|
|
||||||
Case(CaseSelector(2_i), //
|
|
||||||
Block(Assign("v", 2_i))), //
|
|
||||||
DefaultCase(Block(Assign("v", 3_i)))),
|
|
||||||
});
|
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
|
||||||
|
|
||||||
ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
|
|
||||||
ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
|
|
||||||
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
|
|
||||||
|
|
||||||
EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
|
|
||||||
OpName %5 "a"
|
|
||||||
OpName %8 "a_func"
|
|
||||||
%3 = OpTypeInt 32 1
|
|
||||||
%2 = OpTypePointer Private %3
|
|
||||||
%4 = OpConstantNull %3
|
|
||||||
%1 = OpVariable %2 Private %4
|
|
||||||
%5 = OpVariable %2 Private %4
|
|
||||||
%7 = OpTypeVoid
|
|
||||||
%6 = OpTypeFunction %7
|
|
||||||
%15 = OpConstant %3 1
|
|
||||||
%16 = OpConstant %3 2
|
|
||||||
%17 = OpConstant %3 3
|
|
||||||
%8 = OpFunction %7 None %6
|
|
||||||
%9 = OpLabel
|
|
||||||
%11 = OpLoad %3 %5
|
|
||||||
OpSelectionMerge %10 None
|
|
||||||
OpSwitch %11 %12 1 %13 2 %14
|
|
||||||
%13 = OpLabel
|
|
||||||
OpStore %1 %15
|
|
||||||
OpBranch %14
|
|
||||||
%14 = OpLabel
|
|
||||||
OpStore %1 %16
|
|
||||||
OpBranch %10
|
|
||||||
%12 = OpLabel
|
|
||||||
OpStore %1 %17
|
|
||||||
OpBranch %10
|
|
||||||
%10 = OpLabel
|
|
||||||
OpReturn
|
|
||||||
OpFunctionEnd
|
|
||||||
)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(BuilderTest, Switch_WithNestedBreak) {
|
TEST_F(BuilderTest, Switch_WithNestedBreak) {
|
||||||
// switch (a) {
|
// switch (a) {
|
||||||
// case 1:
|
// case 1:
|
||||||
|
@ -460,7 +396,7 @@ TEST_F(BuilderTest, Switch_AllReturn) {
|
||||||
// return 1i;
|
// return 1i;
|
||||||
// }
|
// }
|
||||||
// case 2i: {
|
// case 2i: {
|
||||||
// fallthrough;
|
// return 1i;
|
||||||
// }
|
// }
|
||||||
// default: {
|
// default: {
|
||||||
// return 3i;
|
// return 3i;
|
||||||
|
@ -469,9 +405,9 @@ TEST_F(BuilderTest, Switch_AllReturn) {
|
||||||
|
|
||||||
auto* fn = Func("f", utils::Empty, ty.i32(),
|
auto* fn = Func("f", utils::Empty, ty.i32(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
Switch(1_i, //
|
Switch(1_i, //
|
||||||
Case(CaseSelector(1_i), Block(Return(1_i))), //
|
Case(CaseSelector(1_i), Block(Return(1_i))), //
|
||||||
Case(CaseSelector(2_i), Block(Fallthrough())), //
|
Case(CaseSelector(2_i), Block(Return(1_i))), //
|
||||||
DefaultCase(Block(Return(3_i)))),
|
DefaultCase(Block(Return(3_i)))),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -491,7 +427,7 @@ OpSwitch %6 %7 1 %8 2 %9
|
||||||
%8 = OpLabel
|
%8 = OpLabel
|
||||||
OpReturnValue %6
|
OpReturnValue %6
|
||||||
%9 = OpLabel
|
%9 = OpLabel
|
||||||
OpBranch %7
|
OpReturnValue %6
|
||||||
%7 = OpLabel
|
%7 = OpLabel
|
||||||
OpReturnValue %10
|
OpReturnValue %10
|
||||||
%5 = OpLabel
|
%5 = OpLabel
|
||||||
|
|
|
@ -970,7 +970,6 @@ bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
|
||||||
[&](const ast::CompoundAssignmentStatement* c) { return EmitCompoundAssign(c); },
|
[&](const ast::CompoundAssignmentStatement* c) { return EmitCompoundAssign(c); },
|
||||||
[&](const ast::ContinueStatement* c) { return EmitContinue(c); },
|
[&](const ast::ContinueStatement* c) { return EmitContinue(c); },
|
||||||
[&](const ast::DiscardStatement* d) { return EmitDiscard(d); },
|
[&](const ast::DiscardStatement* d) { return EmitDiscard(d); },
|
||||||
[&](const ast::FallthroughStatement* f) { return EmitFallthrough(f); },
|
|
||||||
[&](const ast::IfStatement* i) { return EmitIf(i); },
|
[&](const ast::IfStatement* i) { return EmitIf(i); },
|
||||||
[&](const ast::IncrementDecrementStatement* l) { return EmitIncrementDecrement(l); },
|
[&](const ast::IncrementDecrementStatement* l) { return EmitIncrementDecrement(l); },
|
||||||
[&](const ast::LoopStatement* l) { return EmitLoop(l); },
|
[&](const ast::LoopStatement* l) { return EmitLoop(l); },
|
||||||
|
@ -1093,11 +1092,6 @@ bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitFallthrough(const ast::FallthroughStatement*) {
|
|
||||||
line() << "fallthrough;";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GeneratorImpl::EmitIf(const ast::IfStatement* stmt) {
|
bool GeneratorImpl::EmitIf(const ast::IfStatement* stmt) {
|
||||||
{
|
{
|
||||||
auto out = line();
|
auto out = line();
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include "src/tint/ast/compound_assignment_statement.h"
|
#include "src/tint/ast/compound_assignment_statement.h"
|
||||||
#include "src/tint/ast/continue_statement.h"
|
#include "src/tint/ast/continue_statement.h"
|
||||||
#include "src/tint/ast/discard_statement.h"
|
#include "src/tint/ast/discard_statement.h"
|
||||||
#include "src/tint/ast/fallthrough_statement.h"
|
|
||||||
#include "src/tint/ast/for_loop_statement.h"
|
#include "src/tint/ast/for_loop_statement.h"
|
||||||
#include "src/tint/ast/if_statement.h"
|
#include "src/tint/ast/if_statement.h"
|
||||||
#include "src/tint/ast/index_accessor_expression.h"
|
#include "src/tint/ast/index_accessor_expression.h"
|
||||||
|
@ -124,10 +123,6 @@ class GeneratorImpl : public TextGenerator {
|
||||||
/// @param expr the expression
|
/// @param expr the expression
|
||||||
/// @returns true if the expression was emitted
|
/// @returns true if the expression was emitted
|
||||||
bool EmitExpression(std::ostream& out, const ast::Expression* expr);
|
bool EmitExpression(std::ostream& out, const ast::Expression* expr);
|
||||||
/// Handles generating a fallthrough statement
|
|
||||||
/// @param stmt the fallthrough statement
|
|
||||||
/// @returns true if the statement was successfully emitted
|
|
||||||
bool EmitFallthrough(const ast::FallthroughStatement* stmt);
|
|
||||||
/// Handles generating a function
|
/// Handles generating a function
|
||||||
/// @param func the function to generate
|
/// @param func the function to generate
|
||||||
/// @returns true if the function was emitted
|
/// @returns true if the function was emitted
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
// 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 "src/tint/writer/wgsl/test_helper.h"
|
|
||||||
|
|
||||||
using namespace tint::number_suffixes; // NOLINT
|
|
||||||
|
|
||||||
namespace tint::writer::wgsl {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using WgslGeneratorImplTest = TestHelper;
|
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, Emit_Fallthrough) {
|
|
||||||
auto* f = create<ast::FallthroughStatement>();
|
|
||||||
WrapInFunction(Switch(1_i, //
|
|
||||||
Case(CaseSelector(1_i), Block(f)), //
|
|
||||||
DefaultCase()));
|
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
|
||||||
|
|
||||||
gen.increment_indent();
|
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
|
|
||||||
EXPECT_EQ(gen.result(), " fallthrough;\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
} // namespace tint::writer::wgsl
|
|
Loading…
Reference in New Issue