Convert CaseSelector to IR.

This CL converts the case selectors over from ast CaseSelectors to IR
CaseSelectors. They work the same way in that a `nullptr` value signals
a `default` selector but they only store the resulting `constant::Value`
instead of the `ast::Expression`.

Bug: tint:1718
Change-Id: Ied62d661e03a7f8da4c1e1bdaccc04f21ab38111
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/116364
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
dan sinclair 2023-01-06 17:58:40 +00:00 committed by Dawn LUCI CQ
parent 19bc66a375
commit 0258f276b5
5 changed files with 40 additions and 22 deletions

View File

@ -77,7 +77,7 @@ Switch* Builder::CreateSwitch(const ast::SwitchStatement* stmt) {
return ir_switch;
}
Block* Builder::CreateCase(Switch* s, utils::VectorRef<const ast::CaseSelector*> selectors) {
Block* Builder::CreateCase(Switch* s, utils::VectorRef<Switch::CaseSelector> selectors) {
s->cases.Push(Switch::Case{selectors, CreateBlock()});
Block* b = s->cases.Back().start_target;

View File

@ -39,9 +39,6 @@
namespace tint {
class Program;
} // namespace tint
namespace tint::ast {
class CaseSelector;
} // namespace tint::ast
namespace tint::ir {
@ -87,7 +84,7 @@ class Builder {
/// @param s the switch to create the case into
/// @param selectors the case selectors for the case statement
/// @returns the start block for the case flow node
Block* CreateCase(Switch* s, utils::VectorRef<const ast::CaseSelector*> selectors);
Block* CreateCase(Switch* s, utils::VectorRef<Switch::CaseSelector> selectors);
/// Branches the given block to the given flow node.
/// @param from the block to branch from

View File

@ -44,6 +44,7 @@
#include "src/tint/program.h"
#include "src/tint/sem/expression.h"
#include "src/tint/sem/module.h"
#include "src/tint/sem/switch_statement.h"
namespace tint::ir {
namespace {
@ -437,9 +438,19 @@ bool BuilderImpl::EmitSwitch(const ast::SwitchStatement* stmt) {
{
FlowStackScope scope(this, switch_node);
for (const auto* c : stmt->body) {
current_flow_block = builder.CreateCase(switch_node, c->selectors);
if (!EmitStatement(c->body)) {
const auto* sem = builder.ir.program->Sem().Get(stmt);
for (const auto* c : sem->Cases()) {
utils::Vector<Switch::CaseSelector, 4> selectors;
for (const auto* selector : c->Selectors()) {
if (selector->IsDefault()) {
selectors.Push({nullptr});
} else {
selectors.Push({selector->Value()->Clone(clone_ctx_)});
}
}
current_flow_block = builder.CreateCase(switch_node, selectors);
if (!EmitStatement(c->Body()->Declaration())) {
return false;
}
BranchToIfNeeded(switch_node->merge_target);

View File

@ -16,6 +16,7 @@
#include "src/tint/ast/case_selector.h"
#include "src/tint/ast/int_literal_expression.h"
#include "src/tint/constant/scalar.h"
namespace tint::ir {
namespace {
@ -1151,15 +1152,15 @@ TEST_F(IR_BuilderImplTest, Switch) {
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_TRUE(flow->cases[0].selectors[0].val->Is<constant::Scalar<tint::i32>>());
EXPECT_EQ(0_i, flow->cases[0].selectors[0].val->As<constant::Scalar<tint::i32>>()->ValueOf());
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_TRUE(flow->cases[1].selectors[0].val->Is<constant::Scalar<tint::i32>>());
EXPECT_EQ(1_i, flow->cases[1].selectors[0].val->As<constant::Scalar<tint::i32>>()->ValueOf());
ASSERT_EQ(1u, flow->cases[2].selectors.Length());
EXPECT_TRUE(flow->cases[2].selectors[0]->IsDefault());
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());
@ -1205,7 +1206,7 @@ TEST_F(IR_BuilderImplTest, Switch_OnlyDefault) {
auto* func = m.functions[0];
ASSERT_EQ(1u, flow->cases[0].selectors.Length());
EXPECT_TRUE(flow->cases[0].selectors[0]->IsDefault());
EXPECT_TRUE(flow->cases[0].selectors[0].IsDefault());
EXPECT_EQ(1u, flow->inbound_branches.Length());
EXPECT_EQ(1u, flow->cases[0].start_target->inbound_branches.Length());
@ -1257,11 +1258,11 @@ TEST_F(IR_BuilderImplTest, Switch_WithBreak) {
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_TRUE(flow->cases[0].selectors[0].val->Is<constant::Scalar<tint::i32>>());
EXPECT_EQ(0_i, flow->cases[0].selectors[0].val->As<constant::Scalar<tint::i32>>()->ValueOf());
ASSERT_EQ(1u, flow->cases[1].selectors.Length());
EXPECT_TRUE(flow->cases[1].selectors[0]->IsDefault());
EXPECT_TRUE(flow->cases[1].selectors[0].IsDefault());
EXPECT_EQ(1u, flow->inbound_branches.Length());
EXPECT_EQ(1u, flow->cases[0].start_target->inbound_branches.Length());
@ -1323,11 +1324,11 @@ TEST_F(IR_BuilderImplTest, Switch_AllReturn) {
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_TRUE(flow->cases[0].selectors[0].val->Is<constant::Scalar<tint::i32>>());
EXPECT_EQ(0_i, flow->cases[0].selectors[0].val->As<constant::Scalar<tint::i32>>()->ValueOf());
ASSERT_EQ(1u, flow->cases[1].selectors.Length());
EXPECT_TRUE(flow->cases[1].selectors[0]->IsDefault());
EXPECT_TRUE(flow->cases[1].selectors[0].IsDefault());
EXPECT_EQ(1u, flow->inbound_branches.Length());
EXPECT_EQ(1u, flow->cases[0].start_target->inbound_branches.Length());

View File

@ -15,13 +15,13 @@
#ifndef SRC_TINT_IR_SWITCH_H_
#define SRC_TINT_IR_SWITCH_H_
#include "src/tint/constant/value.h"
#include "src/tint/ir/block.h"
#include "src/tint/ir/flow_node.h"
#include "src/tint/ir/value.h"
// Forward declarations
namespace tint::ast {
class CaseSelector;
class SwitchStatement;
} // namespace tint::ast
@ -30,10 +30,19 @@ namespace tint::ir {
/// Flow node representing a switch statement
class Switch : public Castable<Switch, FlowNode> {
public:
/// A case selector
struct CaseSelector {
/// @returns true if this is a default selector
bool IsDefault() const { return val == nullptr; }
/// The selector value, or nullptr if this is the default selector
constant::Value* val = nullptr;
};
/// A case label in the struct
struct Case {
/// The case selector for this node
utils::Vector<const ast::CaseSelector*, 4> selectors;
utils::Vector<CaseSelector, 4> selectors;
/// The start block for the case block.
Block* start_target;
};