Store expressions in switch case statements.

This CL moves switch case statements to store Expression instead
of an IntLiteralExpression. The SEM is updated to store the
materialized constant instead of accessing the expression value
directly.

Bug: tint:1633
Change-Id: Id79dabb806be1049f775299732bc1c7b1bf0c05f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106300
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Auto-Submit: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
dan sinclair
2022-10-19 00:43:41 +00:00
committed by Dawn LUCI CQ
parent 00aa7ef462
commit d32fbe07e7
19 changed files with 360 additions and 120 deletions

View File

@@ -3024,7 +3024,7 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
for (size_t i = last_clause_index;; --i) {
// Create a list of integer literals for the selector values leading to
// this case clause.
utils::Vector<const ast::IntLiteralExpression*, 4> selectors;
utils::Vector<const ast::Expression*, 4> selectors;
const bool has_selectors = clause_heads[i]->case_values.has_value();
if (has_selectors) {
auto values = clause_heads[i]->case_values.value();

View File

@@ -2148,21 +2148,19 @@ Maybe<const ast::CaseStatement*> ParserImpl::switch_body() {
}
// case_selectors
// : const_literal (COMMA const_literal)* COMMA?
// : expression (COMMA expression)* COMMA?
Expect<ParserImpl::CaseSelectorList> ParserImpl::expect_case_selectors() {
CaseSelectorList selectors;
while (continue_parsing()) {
auto cond = const_literal();
if (cond.errored) {
auto expr = expression();
if (expr.errored) {
return Failure::kErrored;
} else if (!cond.matched) {
break;
} else if (!cond->Is<ast::IntLiteralExpression>()) {
return add_error(cond.value->source, "invalid case selector must be an integer value");
}
selectors.Push(cond.value->As<ast::IntLiteralExpression>());
if (!expr.matched) {
break;
}
selectors.Push(expr.value);
if (!match(Token::Type::kComma)) {
break;

View File

@@ -74,7 +74,7 @@ class ParserImpl {
/// Pre-determined small vector sizes for AST pointers
//! @cond Doxygen_Suppress
using AttributeList = utils::Vector<const ast::Attribute*, 4>;
using CaseSelectorList = utils::Vector<const ast::IntLiteralExpression*, 4>;
using CaseSelectorList = utils::Vector<const ast::Expression*, 4>;
using CaseStatementList = utils::Vector<const ast::CaseStatement*, 4>;
using ExpressionList = utils::Vector<const ast::Expression*, 8>;
using ParameterList = utils::Vector<const ast::Parameter*, 8>;

View File

@@ -1339,14 +1339,6 @@ fn f() { switch(1) { case ^: } }
)");
}
TEST_F(ParserImplErrorTest, SwitchStmtInvalidCase2) {
EXPECT("fn f() { switch(1) { case false: } }",
R"(test.wgsl:1:27 error: invalid case selector must be an integer value
fn f() { switch(1) { case false: } }
^^^^^
)");
}
TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingLBrace) {
EXPECT("fn f() { switch(1) { case 1: } }",
R"(test.wgsl:1:30 error: expected '{' for case statement

View File

@@ -26,10 +26,42 @@ TEST_F(ParserImplTest, SwitchBody_Case) {
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
auto* stmt = e->As<ast::CaseStatement>();
ASSERT_EQ(stmt->selectors.Length(), 1u);
EXPECT_EQ(stmt->selectors[0]->value, 1);
EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(stmt->selectors[0]->Is<ast::IntLiteralExpression>());
auto* expr = stmt->selectors[0]->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
}
TEST_F(ParserImplTest, SwitchBody_Case_Expression) {
auto p = parser("case 1 + 2 { a = 4; }");
auto e = p->switch_body();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
auto* stmt = e->As<ast::CaseStatement>();
ASSERT_EQ(stmt->selectors.Length(), 1u);
ASSERT_TRUE(stmt->selectors[0]->Is<ast::BinaryExpression>());
auto* expr = stmt->selectors[0]->As<ast::BinaryExpression>();
EXPECT_EQ(ast::BinaryOp::kAdd, expr->op);
auto* v = expr->lhs->As<ast::IntLiteralExpression>();
ASSERT_NE(nullptr, v);
EXPECT_EQ(v->value, 1u);
v = expr->rhs->As<ast::IntLiteralExpression>();
ASSERT_NE(nullptr, v);
EXPECT_EQ(v->value, 2u);
ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
}
@@ -43,10 +75,14 @@ TEST_F(ParserImplTest, SwitchBody_Case_WithColon) {
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
auto* stmt = e->As<ast::CaseStatement>();
ASSERT_EQ(stmt->selectors.Length(), 1u);
EXPECT_EQ(stmt->selectors[0]->value, 1);
EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(stmt->selectors[0]->Is<ast::IntLiteralExpression>());
auto* expr = stmt->selectors[0]->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
}
@@ -62,9 +98,16 @@ TEST_F(ParserImplTest, SwitchBody_Case_TrailingComma) {
EXPECT_FALSE(e->IsDefault());
auto* stmt = e->As<ast::CaseStatement>();
ASSERT_EQ(stmt->selectors.Length(), 2u);
EXPECT_EQ(stmt->selectors[0]->value, 1);
EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
EXPECT_EQ(stmt->selectors[1]->value, 2);
ASSERT_TRUE(stmt->selectors[0]->Is<ast::IntLiteralExpression>());
auto* expr = stmt->selectors[0]->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(stmt->selectors[1]->Is<ast::IntLiteralExpression>());
expr = stmt->selectors[1]->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 2);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
}
TEST_F(ParserImplTest, SwitchBody_Case_TrailingComma_WithColon) {
@@ -76,15 +119,23 @@ TEST_F(ParserImplTest, SwitchBody_Case_TrailingComma_WithColon) {
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
auto* stmt = e->As<ast::CaseStatement>();
ASSERT_EQ(stmt->selectors.Length(), 2u);
EXPECT_EQ(stmt->selectors[0]->value, 1);
EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
EXPECT_EQ(stmt->selectors[1]->value, 2);
ASSERT_TRUE(stmt->selectors[0]->Is<ast::IntLiteralExpression>());
auto* expr = stmt->selectors[0]->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(stmt->selectors[1]->Is<ast::IntLiteralExpression>());
expr = stmt->selectors[1]->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 2);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
}
TEST_F(ParserImplTest, SwitchBody_Case_InvalidConstLiteral) {
auto p = parser("case a == 4: { a = 4; }");
TEST_F(ParserImplTest, SwitchBody_Case_Invalid) {
auto p = parser("case if: { a = 4; }");
auto e = p->switch_body();
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(e.errored);
@@ -93,16 +144,6 @@ TEST_F(ParserImplTest, SwitchBody_Case_InvalidConstLiteral) {
EXPECT_EQ(p->error(), "1:6: unable to parse case selectors");
}
TEST_F(ParserImplTest, SwitchBody_Case_InvalidSelector_bool) {
auto p = parser("case true: { a = 4; }");
auto e = p->switch_body();
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:6: invalid case selector must be an integer value");
}
TEST_F(ParserImplTest, SwitchBody_Case_MissingConstLiteral) {
auto p = parser("case: { a = 4; }");
auto e = p->switch_body();
@@ -164,10 +205,16 @@ TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectors) {
EXPECT_FALSE(e->IsDefault());
ASSERT_EQ(e->body->statements.Length(), 0u);
ASSERT_EQ(e->selectors.Length(), 2u);
ASSERT_EQ(e->selectors[0]->value, 1);
EXPECT_EQ(e->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_EQ(e->selectors[1]->value, 2);
EXPECT_EQ(e->selectors[1]->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(e->selectors[0]->Is<ast::IntLiteralExpression>());
auto* expr = e->selectors[0]->As<ast::IntLiteralExpression>();
ASSERT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(e->selectors[1]->Is<ast::IntLiteralExpression>());
expr = e->selectors[1]->As<ast::IntLiteralExpression>();
ASSERT_EQ(expr->value, 2);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
}
TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectors_WithColon) {
@@ -181,10 +228,16 @@ TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectors_WithColon) {
EXPECT_FALSE(e->IsDefault());
ASSERT_EQ(e->body->statements.Length(), 0u);
ASSERT_EQ(e->selectors.Length(), 2u);
ASSERT_EQ(e->selectors[0]->value, 1);
EXPECT_EQ(e->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_EQ(e->selectors[1]->value, 2);
EXPECT_EQ(e->selectors[1]->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(e->selectors[0]->Is<ast::IntLiteralExpression>());
auto* expr = e->selectors[0]->As<ast::IntLiteralExpression>();
ASSERT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(e->selectors[1]->Is<ast::IntLiteralExpression>());
expr = e->selectors[1]->As<ast::IntLiteralExpression>();
ASSERT_EQ(expr->value, 2);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
}
TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsMissingComma) {