From 989c3a18117fe9f051e456f19563f5c7169777e1 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Thu, 17 Jun 2021 15:48:39 +0000 Subject: [PATCH] reader/wgsl: Parse atomic types Bug: tint:892 Change-Id: Ib6338ee78fccfca339f53c9074671f89bae1537f Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/54645 Kokoro: Kokoro Reviewed-by: James Price --- src/reader/wgsl/lexer.cc | 2 + src/reader/wgsl/parser_impl.cc | 18 +++++- src/reader/wgsl/parser_impl.h | 1 + src/reader/wgsl/parser_impl_error_msg_test.cc | 14 +++++ src/reader/wgsl/parser_impl_type_decl_test.cc | 62 +++++++++++++++++++ src/reader/wgsl/token.cc | 2 + src/reader/wgsl/token.h | 2 + src/transform/renamer_test.cc | 2 +- 8 files changed, 101 insertions(+), 2 deletions(-) diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc index e021118d9c..f07daeb2af 100644 --- a/src/reader/wgsl/lexer.cc +++ b/src/reader/wgsl/lexer.cc @@ -474,6 +474,8 @@ Token Lexer::try_punctuation() { Token Lexer::check_keyword(const Source& source, const std::string& str) { if (str == "array") return {Token::Type::kArray, source, "array"}; + if (str == "atomic") + return {Token::Type::kAtomic, source, "atomic"}; if (str == "bitcast") return {Token::Type::kBitcast, source, "bitcast"}; if (str == "bool") diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index 2259faf3be..77c7f9bed7 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc @@ -1063,8 +1063,13 @@ Maybe ParserImpl::type_decl(ast::DecorationList& decos) { return expect_type_decl_vector(t); } - if (match(Token::Type::kPtr)) + if (match(Token::Type::kPtr)) { return expect_type_decl_pointer(t); + } + + if (match(Token::Type::kAtomic)) { + return expect_type_decl_atomic(t); + } if (match(Token::Type::kArray, &source)) { return expect_type_decl_array(t, std::move(decos)); @@ -1136,6 +1141,17 @@ Expect ParserImpl::expect_type_decl_pointer(Token t) { storage_class, access); } +Expect ParserImpl::expect_type_decl_atomic(Token t) { + const char* use = "atomic declaration"; + + auto subtype = expect_lt_gt_block(use, [&] { return expect_type(use); }); + if (subtype.errored) { + return Failure::kErrored; + } + + return builder_.ty.atomic(make_source_range_from(t.source()), subtype.value); +} + Expect ParserImpl::expect_type_decl_vector(Token t) { uint32_t count = 2; if (t.IsVec3()) diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h index adeced48f9..0fa277350f 100644 --- a/src/reader/wgsl/parser_impl.h +++ b/src/reader/wgsl/parser_impl.h @@ -843,6 +843,7 @@ class ParserImpl { bool expect_decorations_consumed(const ast::DecorationList& list); Expect expect_type_decl_pointer(Token t); + Expect expect_type_decl_atomic(Token t); Expect expect_type_decl_vector(Token t); Expect expect_type_decl_array(Token t, ast::DecorationList decos); Expect expect_type_decl_matrix(Token t); diff --git a/src/reader/wgsl/parser_impl_error_msg_test.cc b/src/reader/wgsl/parser_impl_error_msg_test.cc index 1e65e6338a..800e573349 100644 --- a/src/reader/wgsl/parser_impl_error_msg_test.cc +++ b/src/reader/wgsl/parser_impl_error_msg_test.cc @@ -1023,6 +1023,20 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingType) { " ^\n"); } +TEST_F(ParserImplErrorTest, GlobalDeclVarAtomicMissingLessThan) { + EXPECT("var i : atomic;", + "test.wgsl:1:15 error: expected '<' for atomic declaration\n" + "var i : atomic;\n" + " ^\n"); +} + +TEST_F(ParserImplErrorTest, GlobalDeclVarAtomicMissingGreaterThan) { + EXPECT("var i : atomic' for atomic declaration\n" + "var i : atomic i : i32", "test.wgsl:1:5 error: invalid storage class for variable declaration\n" diff --git a/src/reader/wgsl/parser_impl_type_decl_test.cc b/src/reader/wgsl/parser_impl_type_decl_test.cc index 3a2c2fc0de..68812c3d5e 100644 --- a/src/reader/wgsl/parser_impl_type_decl_test.cc +++ b/src/reader/wgsl/parser_impl_type_decl_test.cc @@ -378,6 +378,68 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_BadAccess) { ASSERT_EQ(p->error(), "1:20: invalid value for access control"); } +TEST_F(ParserImplTest, TypeDecl_Atomic) { + auto p = parser("atomic"); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); + ASSERT_FALSE(p->has_error()); + ASSERT_TRUE(t.value->Is()); + + auto* atomic = t.value->As(); + ASSERT_TRUE(atomic->type()->Is()); + EXPECT_EQ(t.value->source().range, (Source::Range{{1u, 1u}, {1u, 12u}})); +} + +TEST_F(ParserImplTest, TypeDecl_Atomic_ToVec) { + auto p = parser("atomic>"); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); + ASSERT_FALSE(p->has_error()); + ASSERT_TRUE(t.value->Is()); + + auto* atomic = t.value->As(); + ASSERT_TRUE(atomic->type()->Is()); + + auto* vec = atomic->type()->As(); + ASSERT_EQ(vec->size(), 2u); + ASSERT_TRUE(vec->type()->Is()); + EXPECT_EQ(t.value->source().range, (Source::Range{{1u, 1u}, {1u, 18u}})); +} + +TEST_F(ParserImplTest, TypeDecl_Atomic_MissingLessThan) { + auto p = parser("atomic f32>"); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); + ASSERT_TRUE(p->has_error()); + ASSERT_EQ(p->error(), "1:8: expected '<' for atomic declaration"); +} + +TEST_F(ParserImplTest, TypeDecl_Atomic_MissingGreaterThan) { + auto p = parser("atomictype_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); + ASSERT_TRUE(p->has_error()); + ASSERT_EQ(p->error(), "1:11: expected '>' for atomic declaration"); +} + +TEST_F(ParserImplTest, TypeDecl_Atomic_MissingType) { + auto p = parser("atomic<>"); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); + ASSERT_TRUE(p->has_error()); + ASSERT_EQ(p->error(), "1:8: invalid type for atomic declaration"); +} + TEST_F(ParserImplTest, TypeDecl_Array) { auto p = parser("array"); auto t = p->type_decl(); diff --git a/src/reader/wgsl/token.cc b/src/reader/wgsl/token.cc index 88fb346d40..50dc51075e 100644 --- a/src/reader/wgsl/token.cc +++ b/src/reader/wgsl/token.cc @@ -109,6 +109,8 @@ std::string Token::TypeToName(Type type) { case Token::Type::kArray: return "array"; + case Token::Type::kAtomic: + return "atomic"; case Token::Type::kBitcast: return "bitcast"; case Token::Type::kBool: diff --git a/src/reader/wgsl/token.h b/src/reader/wgsl/token.h index bbceb6f6ed..ffbdd8c83f 100644 --- a/src/reader/wgsl/token.h +++ b/src/reader/wgsl/token.h @@ -117,6 +117,8 @@ class Token { /// A 'array' kArray, + /// A 'atomic' + kAtomic, /// A 'bitcast' kBitcast, /// A 'bool' diff --git a/src/transform/renamer_test.cc b/src/transform/renamer_test.cc index f73708f58f..5707c88ce8 100644 --- a/src/transform/renamer_test.cc +++ b/src/transform/renamer_test.cc @@ -943,7 +943,7 @@ INSTANTIATE_TEST_SUITE_P(RenamerTestMsl, // "array", // Also used in WGSL "array_ref", "as_type", - "atomic", + // "atomic", // Also used in WGSL "atomic_bool", "atomic_int", "atomic_uint",