reader/wgsl: Tail-call optimize expression methods

Fixes stack overflows in complex arithmetic expressions

Fixed: chromium:1182709
Change-Id: I5f5470cf59525725a437f26672904e9653b447a7
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/43940
Reviewed-by: David Neto <dneto@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2021-03-04 22:52:05 +00:00 committed by Commit Bot service account
parent d1781fd0af
commit dee7d36f8a
1 changed files with 187 additions and 161 deletions

View File

@ -2256,32 +2256,34 @@ Maybe<ast::Expression*> ParserImpl::unary_expression() {
// | MODULO unary_expression multiplicative_expr // | MODULO unary_expression multiplicative_expr
Expect<ast::Expression*> ParserImpl::expect_multiplicative_expr( Expect<ast::Expression*> ParserImpl::expect_multiplicative_expr(
ast::Expression* lhs) { ast::Expression* lhs) {
auto t = peek(); while (synchronized_) {
auto t = peek();
ast::BinaryOp op = ast::BinaryOp::kNone; ast::BinaryOp op = ast::BinaryOp::kNone;
if (t.IsStar()) if (t.IsStar())
op = ast::BinaryOp::kMultiply; op = ast::BinaryOp::kMultiply;
else if (t.IsForwardSlash()) else if (t.IsForwardSlash())
op = ast::BinaryOp::kDivide; op = ast::BinaryOp::kDivide;
else if (t.IsMod()) else if (t.IsMod())
op = ast::BinaryOp::kModulo; op = ast::BinaryOp::kModulo;
else else
return lhs; return lhs;
auto source = t.source(); auto source = t.source();
auto name = t.to_name(); auto name = t.to_name();
next(); // Consume the peek next(); // Consume the peek
auto rhs = unary_expression(); auto rhs = unary_expression();
if (rhs.errored) if (rhs.errored)
return Failure::kErrored; return Failure::kErrored;
if (!rhs.matched) { if (!rhs.matched) {
return add_error(peek(), return add_error(peek(),
"unable to parse right side of " + name + " expression"); "unable to parse right side of " + name + " expression");
}
lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
} }
return Failure::kErrored;
return expect_multiplicative_expr(
create<ast::BinaryExpression>(source, op, lhs, rhs.value));
} }
// multiplicative_expression // multiplicative_expression
@ -2302,27 +2304,29 @@ Maybe<ast::Expression*> ParserImpl::multiplicative_expression() {
// | MINUS multiplicative_expression additive_expr // | MINUS multiplicative_expression additive_expr
Expect<ast::Expression*> ParserImpl::expect_additive_expr( Expect<ast::Expression*> ParserImpl::expect_additive_expr(
ast::Expression* lhs) { ast::Expression* lhs) {
auto t = peek(); while (synchronized_) {
auto t = peek();
ast::BinaryOp op = ast::BinaryOp::kNone; ast::BinaryOp op = ast::BinaryOp::kNone;
if (t.IsPlus()) if (t.IsPlus())
op = ast::BinaryOp::kAdd; op = ast::BinaryOp::kAdd;
else if (t.IsMinus()) else if (t.IsMinus())
op = ast::BinaryOp::kSubtract; op = ast::BinaryOp::kSubtract;
else else
return lhs; return lhs;
auto source = t.source(); auto source = t.source();
next(); // Consume the peek next(); // Consume the peek
auto rhs = multiplicative_expression(); auto rhs = multiplicative_expression();
if (rhs.errored) if (rhs.errored)
return Failure::kErrored; return Failure::kErrored;
if (!rhs.matched) if (!rhs.matched)
return add_error(peek(), "unable to parse right side of + expression"); return add_error(peek(), "unable to parse right side of + expression");
return expect_additive_expr( lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
create<ast::BinaryExpression>(source, op, lhs, rhs.value)); }
return Failure::kErrored;
} }
// additive_expression // additive_expression
@ -2342,33 +2346,36 @@ Maybe<ast::Expression*> ParserImpl::additive_expression() {
// | SHIFT_LEFT additive_expression shift_expr // | SHIFT_LEFT additive_expression shift_expr
// | SHIFT_RIGHT additive_expression shift_expr // | SHIFT_RIGHT additive_expression shift_expr
Expect<ast::Expression*> ParserImpl::expect_shift_expr(ast::Expression* lhs) { Expect<ast::Expression*> ParserImpl::expect_shift_expr(ast::Expression* lhs) {
auto t = peek(); while (synchronized_) {
auto source = t.source(); auto t = peek();
auto source = t.source();
auto* name = ""; auto* name = "";
ast::BinaryOp op = ast::BinaryOp::kNone; ast::BinaryOp op = ast::BinaryOp::kNone;
if (t.IsShiftLeft()) { if (t.IsShiftLeft()) {
next(); // Consume the peek next(); // Consume the peek
op = ast::BinaryOp::kShiftLeft; op = ast::BinaryOp::kShiftLeft;
name = "<<"; name = "<<";
} else if (t.IsShiftRight()) { } else if (t.IsShiftRight()) {
next(); // Consume the peek next(); // Consume the peek
op = ast::BinaryOp::kShiftRight; op = ast::BinaryOp::kShiftRight;
name = ">>"; name = ">>";
} else { } else {
return lhs; return lhs;
} }
auto rhs = additive_expression(); auto rhs = additive_expression();
if (rhs.errored) if (rhs.errored)
return Failure::kErrored; return Failure::kErrored;
if (!rhs.matched) { if (!rhs.matched) {
return add_error(peek(), std::string("unable to parse right side of ") + return add_error(peek(), std::string("unable to parse right side of ") +
name + " expression"); name + " expression");
}
return lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
} }
return expect_shift_expr( return Failure::kErrored;
create<ast::BinaryExpression>(source, op, lhs, rhs.value)); }
} // namespace wgsl
// shift_expression // shift_expression
// : additive_expression shift_expr // : additive_expression shift_expr
@ -2390,33 +2397,35 @@ Maybe<ast::Expression*> ParserImpl::shift_expression() {
// | GREATER_THAN_EQUAL shift_expression relational_expr // | GREATER_THAN_EQUAL shift_expression relational_expr
Expect<ast::Expression*> ParserImpl::expect_relational_expr( Expect<ast::Expression*> ParserImpl::expect_relational_expr(
ast::Expression* lhs) { ast::Expression* lhs) {
auto t = peek(); while (synchronized_) {
ast::BinaryOp op = ast::BinaryOp::kNone; auto t = peek();
if (t.IsLessThan()) ast::BinaryOp op = ast::BinaryOp::kNone;
op = ast::BinaryOp::kLessThan; if (t.IsLessThan())
else if (t.IsGreaterThan()) op = ast::BinaryOp::kLessThan;
op = ast::BinaryOp::kGreaterThan; else if (t.IsGreaterThan())
else if (t.IsLessThanEqual()) op = ast::BinaryOp::kGreaterThan;
op = ast::BinaryOp::kLessThanEqual; else if (t.IsLessThanEqual())
else if (t.IsGreaterThanEqual()) op = ast::BinaryOp::kLessThanEqual;
op = ast::BinaryOp::kGreaterThanEqual; else if (t.IsGreaterThanEqual())
else op = ast::BinaryOp::kGreaterThanEqual;
return lhs; else
return lhs;
auto source = t.source(); auto source = t.source();
auto name = t.to_name(); auto name = t.to_name();
next(); // Consume the peek next(); // Consume the peek
auto rhs = shift_expression(); auto rhs = shift_expression();
if (rhs.errored) if (rhs.errored)
return Failure::kErrored; return Failure::kErrored;
if (!rhs.matched) { if (!rhs.matched) {
return add_error(peek(), return add_error(peek(),
"unable to parse right side of " + name + " expression"); "unable to parse right side of " + name + " expression");
}
lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
} }
return Failure::kErrored;
return expect_relational_expr(
create<ast::BinaryExpression>(source, op, lhs, rhs.value));
} }
// relational_expression // relational_expression
@ -2437,29 +2446,31 @@ Maybe<ast::Expression*> ParserImpl::relational_expression() {
// | NOT_EQUAL relational_expression equality_expr // | NOT_EQUAL relational_expression equality_expr
Expect<ast::Expression*> ParserImpl::expect_equality_expr( Expect<ast::Expression*> ParserImpl::expect_equality_expr(
ast::Expression* lhs) { ast::Expression* lhs) {
auto t = peek(); while (synchronized_) {
ast::BinaryOp op = ast::BinaryOp::kNone; auto t = peek();
if (t.IsEqualEqual()) ast::BinaryOp op = ast::BinaryOp::kNone;
op = ast::BinaryOp::kEqual; if (t.IsEqualEqual())
else if (t.IsNotEqual()) op = ast::BinaryOp::kEqual;
op = ast::BinaryOp::kNotEqual; else if (t.IsNotEqual())
else op = ast::BinaryOp::kNotEqual;
return lhs; else
return lhs;
auto source = t.source(); auto source = t.source();
auto name = t.to_name(); auto name = t.to_name();
next(); // Consume the peek next(); // Consume the peek
auto rhs = relational_expression(); auto rhs = relational_expression();
if (rhs.errored) if (rhs.errored)
return Failure::kErrored; return Failure::kErrored;
if (!rhs.matched) { if (!rhs.matched) {
return add_error(peek(), return add_error(peek(),
"unable to parse right side of " + name + " expression"); "unable to parse right side of " + name + " expression");
}
lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
} }
return Failure::kErrored;
return expect_equality_expr(
create<ast::BinaryExpression>(source, op, lhs, rhs.value));
} }
// equality_expression // equality_expression
@ -2478,21 +2489,24 @@ Maybe<ast::Expression*> ParserImpl::equality_expression() {
// : // :
// | AND equality_expression and_expr // | AND equality_expression and_expr
Expect<ast::Expression*> ParserImpl::expect_and_expr(ast::Expression* lhs) { Expect<ast::Expression*> ParserImpl::expect_and_expr(ast::Expression* lhs) {
auto t = peek(); while (synchronized_) {
if (!t.IsAnd()) auto t = peek();
return lhs; if (!t.IsAnd())
return lhs;
auto source = t.source(); auto source = t.source();
next(); // Consume the peek next(); // Consume the peek
auto rhs = equality_expression(); auto rhs = equality_expression();
if (rhs.errored) if (rhs.errored)
return Failure::kErrored; return Failure::kErrored;
if (!rhs.matched) if (!rhs.matched)
return add_error(peek(), "unable to parse right side of & expression"); return add_error(peek(), "unable to parse right side of & expression");
return expect_and_expr(create<ast::BinaryExpression>( lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kAnd, lhs,
source, ast::BinaryOp::kAnd, lhs, rhs.value)); rhs.value);
}
return Failure::kErrored;
} }
// and_expression // and_expression
@ -2512,18 +2526,21 @@ Maybe<ast::Expression*> ParserImpl::and_expression() {
// | XOR and_expression exclusive_or_expr // | XOR and_expression exclusive_or_expr
Expect<ast::Expression*> ParserImpl::expect_exclusive_or_expr( Expect<ast::Expression*> ParserImpl::expect_exclusive_or_expr(
ast::Expression* lhs) { ast::Expression* lhs) {
Source source; while (synchronized_) {
if (!match(Token::Type::kXor, &source)) Source source;
return lhs; if (!match(Token::Type::kXor, &source))
return lhs;
auto rhs = and_expression(); auto rhs = and_expression();
if (rhs.errored) if (rhs.errored)
return Failure::kErrored; return Failure::kErrored;
if (!rhs.matched) if (!rhs.matched)
return add_error(peek(), "unable to parse right side of ^ expression"); return add_error(peek(), "unable to parse right side of ^ expression");
return expect_exclusive_or_expr(create<ast::BinaryExpression>( lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kXor, lhs,
source, ast::BinaryOp::kXor, lhs, rhs.value)); rhs.value);
}
return Failure::kErrored;
} }
// exclusive_or_expression // exclusive_or_expression
@ -2543,18 +2560,21 @@ Maybe<ast::Expression*> ParserImpl::exclusive_or_expression() {
// | OR exclusive_or_expression inclusive_or_expr // | OR exclusive_or_expression inclusive_or_expr
Expect<ast::Expression*> ParserImpl::expect_inclusive_or_expr( Expect<ast::Expression*> ParserImpl::expect_inclusive_or_expr(
ast::Expression* lhs) { ast::Expression* lhs) {
Source source; while (synchronized_) {
if (!match(Token::Type::kOr)) Source source;
return lhs; if (!match(Token::Type::kOr))
return lhs;
auto rhs = exclusive_or_expression(); auto rhs = exclusive_or_expression();
if (rhs.errored) if (rhs.errored)
return Failure::kErrored; return Failure::kErrored;
if (!rhs.matched) if (!rhs.matched)
return add_error(peek(), "unable to parse right side of | expression"); return add_error(peek(), "unable to parse right side of | expression");
return expect_inclusive_or_expr(create<ast::BinaryExpression>( lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kOr, lhs,
source, ast::BinaryOp::kOr, lhs, rhs.value)); rhs.value);
}
return Failure::kErrored;
} }
// inclusive_or_expression // inclusive_or_expression
@ -2574,21 +2594,24 @@ Maybe<ast::Expression*> ParserImpl::inclusive_or_expression() {
// | AND_AND inclusive_or_expression logical_and_expr // | AND_AND inclusive_or_expression logical_and_expr
Expect<ast::Expression*> ParserImpl::expect_logical_and_expr( Expect<ast::Expression*> ParserImpl::expect_logical_and_expr(
ast::Expression* lhs) { ast::Expression* lhs) {
auto t = peek(); while (synchronized_) {
if (!t.IsAndAnd()) auto t = peek();
return lhs; if (!t.IsAndAnd())
return lhs;
auto source = t.source(); auto source = t.source();
next(); // Consume the peek next(); // Consume the peek
auto rhs = inclusive_or_expression(); auto rhs = inclusive_or_expression();
if (rhs.errored) if (rhs.errored)
return Failure::kErrored; return Failure::kErrored;
if (!rhs.matched) if (!rhs.matched)
return add_error(peek(), "unable to parse right side of && expression"); return add_error(peek(), "unable to parse right side of && expression");
return expect_logical_and_expr(create<ast::BinaryExpression>( lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kLogicalAnd, lhs,
source, ast::BinaryOp::kLogicalAnd, lhs, rhs.value)); rhs.value);
}
return Failure::kErrored;
} }
// logical_and_expression // logical_and_expression
@ -2608,18 +2631,21 @@ Maybe<ast::Expression*> ParserImpl::logical_and_expression() {
// | OR_OR logical_and_expression logical_or_expr // | OR_OR logical_and_expression logical_or_expr
Expect<ast::Expression*> ParserImpl::expect_logical_or_expr( Expect<ast::Expression*> ParserImpl::expect_logical_or_expr(
ast::Expression* lhs) { ast::Expression* lhs) {
Source source; while (synchronized_) {
if (!match(Token::Type::kOrOr)) Source source;
return lhs; if (!match(Token::Type::kOrOr))
return lhs;
auto rhs = logical_and_expression(); auto rhs = logical_and_expression();
if (rhs.errored) if (rhs.errored)
return Failure::kErrored; return Failure::kErrored;
if (!rhs.matched) if (!rhs.matched)
return add_error(peek(), "unable to parse right side of || expression"); return add_error(peek(), "unable to parse right side of || expression");
return expect_logical_or_expr(create<ast::BinaryExpression>( lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kLogicalOr, lhs,
source, ast::BinaryOp::kLogicalOr, lhs, rhs.value)); rhs.value);
}
return Failure::kErrored;
} }
// logical_or_expression // logical_or_expression