[wgsl-reader] Parse stage decoration
This CL adds parsing of the stage decoration to the WGSL parser. The
decoration is not hooked up yet so it's effectively ignored.
Change-Id: I8d86c55cee189f993c10b6da31a9c388ba452021
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/28664
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index f54e12a..fffbd2a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -301,6 +301,8 @@
"src/ast/set_decoration.h",
"src/ast/sint_literal.cc",
"src/ast/sint_literal.h",
+ "src/ast/stage_decoration.cc",
+ "src/ast/stage_decoration.h",
"src/ast/statement.cc",
"src/ast/statement.h",
"src/ast/storage_class.cc",
@@ -721,6 +723,7 @@
"src/ast/scalar_constructor_expression_test.cc",
"src/ast/set_decoration_test.cc",
"src/ast/sint_literal_test.cc",
+ "src/ast/stage_decoration_test.cc",
"src/ast/struct_member_offset_decoration_test.cc",
"src/ast/struct_member_test.cc",
"src/ast/struct_test.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c87bd64..fdc2fdf 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -122,6 +122,8 @@
ast/set_decoration.h
ast/sint_literal.cc
ast/sint_literal.h
+ ast/stage_decoration.cc
+ ast/stage_decoration.h
ast/statement.cc
ast/statement.h
ast/storage_class.cc
@@ -331,6 +333,7 @@
ast/scalar_constructor_expression_test.cc
ast/set_decoration_test.cc
ast/sint_literal_test.cc
+ ast/stage_decoration_test.cc
ast/struct_member_test.cc
ast/struct_member_offset_decoration_test.cc
ast/struct_test.cc
diff --git a/src/ast/function_decoration.cc b/src/ast/function_decoration.cc
index c246b97..d94c2c1 100644
--- a/src/ast/function_decoration.cc
+++ b/src/ast/function_decoration.cc
@@ -16,6 +16,7 @@
#include <assert.h>
+#include "src/ast/stage_decoration.h"
#include "src/ast/workgroup_decoration.h"
namespace tint {
@@ -25,10 +26,19 @@
FunctionDecoration::~FunctionDecoration() = default;
+bool FunctionDecoration::IsStage() const {
+ return false;
+}
+
bool FunctionDecoration::IsWorkgroup() const {
return false;
}
+const StageDecoration* FunctionDecoration::AsStage() const {
+ assert(IsStage());
+ return static_cast<const StageDecoration*>(this);
+}
+
const WorkgroupDecoration* FunctionDecoration::AsWorkgroup() const {
assert(IsWorkgroup());
return static_cast<const WorkgroupDecoration*>(this);
diff --git a/src/ast/function_decoration.h b/src/ast/function_decoration.h
index 461a037..fb1e3bb 100644
--- a/src/ast/function_decoration.h
+++ b/src/ast/function_decoration.h
@@ -22,6 +22,7 @@
namespace tint {
namespace ast {
+class StageDecoration;
class WorkgroupDecoration;
/// A decoration attached to a function
@@ -29,9 +30,13 @@
public:
virtual ~FunctionDecoration();
+ /// @returns true if this is a stage decoration
+ virtual bool IsStage() const;
/// @returns true if this is a workgroup decoration
virtual bool IsWorkgroup() const;
+ /// @returns the decoration as a stage decoration
+ const StageDecoration* AsStage() const;
/// @returns the decoration as a workgroup decoration
const WorkgroupDecoration* AsWorkgroup() const;
diff --git a/src/ast/stage_decoration.cc b/src/ast/stage_decoration.cc
new file mode 100644
index 0000000..f1882de
--- /dev/null
+++ b/src/ast/stage_decoration.cc
@@ -0,0 +1,33 @@
+// 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/ast/stage_decoration.h"
+
+namespace tint {
+namespace ast {
+
+StageDecoration::StageDecoration(ast::PipelineStage stage) : stage_(stage) {}
+
+StageDecoration::~StageDecoration() = default;
+
+bool StageDecoration::IsStage() const {
+ return true;
+}
+
+void StageDecoration::to_str(std::ostream& out) const {
+ out << "StageDecoration{" << stage_ << "}" << std::endl;
+}
+
+} // namespace ast
+} // namespace tint
diff --git a/src/ast/stage_decoration.h b/src/ast/stage_decoration.h
new file mode 100644
index 0000000..516acb0
--- /dev/null
+++ b/src/ast/stage_decoration.h
@@ -0,0 +1,49 @@
+// 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_AST_STAGE_DECORATION_H_
+#define SRC_AST_STAGE_DECORATION_H_
+
+#include "src/ast/function_decoration.h"
+#include "src/ast/pipeline_stage.h"
+
+namespace tint {
+namespace ast {
+
+/// A workgroup decoration
+class StageDecoration : public FunctionDecoration {
+ public:
+ /// constructor
+ /// @param stage the pipeline stage
+ explicit StageDecoration(ast::PipelineStage stage);
+ ~StageDecoration() override;
+
+ /// @returns true if this is a stage decoration
+ bool IsStage() const override;
+
+ /// @returns the stage
+ ast::PipelineStage value() const { return stage_; }
+
+ /// Outputs the decoration to the given stream
+ /// @param out the stream to output too
+ void to_str(std::ostream& out) const override;
+
+ private:
+ ast::PipelineStage stage_ = ast::PipelineStage::kNone;
+};
+
+} // namespace ast
+} // namespace tint
+
+#endif // SRC_AST_STAGE_DECORATION_H_
diff --git a/src/ast/stage_decoration_test.cc b/src/ast/stage_decoration_test.cc
new file mode 100644
index 0000000..ce6f340
--- /dev/null
+++ b/src/ast/stage_decoration_test.cc
@@ -0,0 +1,48 @@
+// 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/ast/stage_decoration.h"
+
+#include <sstream>
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+namespace {
+
+using StageDecorationTest = testing::Test;
+
+TEST_F(StageDecorationTest, Creation_1param) {
+ StageDecoration d{ast::PipelineStage::kFragment};
+ EXPECT_EQ(d.value(), ast::PipelineStage::kFragment);
+}
+
+TEST_F(StageDecorationTest, Is) {
+ StageDecoration d{ast::PipelineStage::kFragment};
+ EXPECT_FALSE(d.IsWorkgroup());
+ EXPECT_TRUE(d.IsStage());
+}
+
+TEST_F(StageDecorationTest, ToStr) {
+ StageDecoration d{ast::PipelineStage::kFragment};
+ std::ostringstream out;
+ d.to_str(out);
+ EXPECT_EQ(out.str(), R"(StageDecoration{fragment}
+)");
+}
+
+} // namespace
+} // namespace ast
+} // namespace tint
diff --git a/src/ast/workgroup_decoration_test.cc b/src/ast/workgroup_decoration_test.cc
index 750d351..7b4936b 100644
--- a/src/ast/workgroup_decoration_test.cc
+++ b/src/ast/workgroup_decoration_test.cc
@@ -59,6 +59,7 @@
TEST_F(WorkgroupDecorationTest, Is) {
WorkgroupDecoration d{2, 4, 6};
EXPECT_TRUE(d.IsWorkgroup());
+ EXPECT_FALSE(d.IsStage());
}
TEST_F(WorkgroupDecorationTest, ToStr) {
diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc
index 4d2a184..9a825b2 100644
--- a/src/reader/wgsl/lexer.cc
+++ b/src/reader/wgsl/lexer.cc
@@ -637,6 +637,8 @@
return {Token::Type::kComparisonSampler, source, "sampler_comparison"};
if (str == "set")
return {Token::Type::kSet, source, "set"};
+ if (str == "stage")
+ return {Token::Type::kStage, source, "stage"};
if (str == "storage_buffer")
return {Token::Type::kStorageBuffer, source, "storage_buffer"};
if (str == "stride")
diff --git a/src/reader/wgsl/lexer_test.cc b/src/reader/wgsl/lexer_test.cc
index b722246..0254824 100644
--- a/src/reader/wgsl/lexer_test.cc
+++ b/src/reader/wgsl/lexer_test.cc
@@ -496,6 +496,7 @@
TokenData{"sampler", Token::Type::kSampler},
TokenData{"sampler_comparison", Token::Type::kComparisonSampler},
TokenData{"set", Token::Type::kSet},
+ TokenData{"stage", Token::Type::kStage},
TokenData{"storage_buffer", Token::Type::kStorageBuffer},
TokenData{"stride", Token::Type::kStride},
TokenData{"struct", Token::Type::kStruct},
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 27ffa72..cff1b50 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -41,6 +41,7 @@
#include "src/ast/scalar_constructor_expression.h"
#include "src/ast/set_decoration.h"
#include "src/ast/sint_literal.h"
+#include "src/ast/stage_decoration.h"
#include "src/ast/struct_member_offset_decoration.h"
#include "src/ast/switch_statement.h"
#include "src/ast/type/alias_type.h"
@@ -113,7 +114,7 @@
}
bool IsFunctionDecoration(Token t) {
- return t.IsWorkgroupSize();
+ return t.IsWorkgroupSize() || t.IsStage();
}
} // namespace
@@ -1837,7 +1838,7 @@
}
// function_decoration
-// : TODO(dsinclair) STAGE PAREN_LEFT pipeline_stage PAREN_RIGHT
+// : STAGE PAREN_LEFT pipeline_stage PAREN_RIGHT
// | WORKGROUP_SIZE PAREN_LEFT INT_LITERAL
// (COMMA INT_LITERAL (COMMA INT_LITERAL)?)? PAREN_RIGHT
std::unique_ptr<ast::FunctionDecoration> ParserImpl::function_decoration() {
@@ -1905,6 +1906,31 @@
return std::make_unique<ast::WorkgroupDecoration>(uint32_t(x), uint32_t(y),
uint32_t(z));
}
+ if (t.IsStage()) {
+ next(); // Consume the peek
+
+ t = next();
+ if (!t.IsParenLeft()) {
+ set_error(t, "missing ( for stage decoration");
+ return nullptr;
+ }
+
+ auto stage = pipeline_stage();
+ if (has_error()) {
+ return nullptr;
+ }
+ if (stage == ast::PipelineStage::kNone) {
+ set_error(peek(), "invalid value for stage decoration");
+ return nullptr;
+ }
+
+ t = next();
+ if (!t.IsParenRight()) {
+ set_error(t, "missing ) for stage decoration");
+ return nullptr;
+ }
+ return std::make_unique<ast::StageDecoration>(stage);
+ }
return nullptr;
}
diff --git a/src/reader/wgsl/parser_impl_function_decoration_test.cc b/src/reader/wgsl/parser_impl_function_decoration_test.cc
index c7acb60..d8661a3 100644
--- a/src/reader/wgsl/parser_impl_function_decoration_test.cc
+++ b/src/reader/wgsl/parser_impl_function_decoration_test.cc
@@ -13,6 +13,7 @@
// limitations under the License.
#include "gtest/gtest.h"
+#include "src/ast/stage_decoration.h"
#include "src/ast/workgroup_decoration.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
@@ -190,6 +191,47 @@
EXPECT_EQ(p->error(), "1:22: missing z value for workgroup_size");
}
+TEST_F(ParserImplTest, FunctionDecoration_Stage) {
+ auto* p = parser("stage(compute)");
+ auto deco = p->function_decoration();
+ ASSERT_NE(deco, nullptr);
+ ASSERT_FALSE(p->has_error());
+ ASSERT_TRUE(deco->IsStage());
+ EXPECT_EQ(deco->AsStage()->value(), ast::PipelineStage::kCompute);
+}
+
+TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingValue) {
+ auto* p = parser("stage()");
+ auto deco = p->function_decoration();
+ ASSERT_EQ(deco, nullptr);
+ ASSERT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:7: invalid value for stage decoration");
+}
+
+TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingInvalid) {
+ auto* p = parser("stage(nan)");
+ auto deco = p->function_decoration();
+ ASSERT_EQ(deco, nullptr);
+ ASSERT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:7: invalid value for stage decoration");
+}
+
+TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingLeftParen) {
+ auto* p = parser("stage compute)");
+ auto deco = p->function_decoration();
+ ASSERT_EQ(deco, nullptr);
+ ASSERT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:7: missing ( for stage decoration");
+}
+
+TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingRightParen) {
+ auto* p = parser("stage(compute");
+ auto deco = p->function_decoration();
+ ASSERT_EQ(deco, nullptr);
+ ASSERT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:14: missing ) for stage decoration");
+}
+
} // namespace
} // namespace wgsl
} // namespace reader
diff --git a/src/reader/wgsl/token.cc b/src/reader/wgsl/token.cc
index ed90e8a..a5dbea5 100644
--- a/src/reader/wgsl/token.cc
+++ b/src/reader/wgsl/token.cc
@@ -277,6 +277,8 @@
return "storage_buffer";
case Token::Type::kStride:
return "stride";
+ case Token::Type::kStage:
+ return "stage";
case Token::Type::kStruct:
return "struct";
case Token::Type::kSwitch:
diff --git a/src/reader/wgsl/token.h b/src/reader/wgsl/token.h
index 0967cd7..0f5f531 100644
--- a/src/reader/wgsl/token.h
+++ b/src/reader/wgsl/token.h
@@ -286,6 +286,8 @@
kSet,
/// A 'storage_buffer'
kStorageBuffer,
+ /// A 'stage'
+ kStage,
/// A 'stride'
kStride,
/// A 'struct'
@@ -511,6 +513,8 @@
bool IsCase() const { return type_ == Type::kCase; }
/// @returns true if token is a 'cast'
bool IsCast() const { return type_ == Type::kCast; }
+ /// @returns true if token is a 'sampler_comparison'
+ bool IsComparisonSampler() const { return type_ == Type::kComparisonSampler; }
/// @returns true if token is a 'compute'
bool IsCompute() const { return type_ == Type::kCompute; }
/// @returns true if token is a 'const'
@@ -665,10 +669,10 @@
bool IsReturn() const { return type_ == Type::kReturn; }
/// @returns true if token is a 'sampler'
bool IsSampler() const { return type_ == Type::kSampler; }
- /// @returns true if token is a 'sampler_comparison'
- bool IsComparisonSampler() const { return type_ == Type::kComparisonSampler; }
/// @returns true if token is a 'set'
bool IsSet() const { return type_ == Type::kSet; }
+ /// @returns true if token is a 'stage'
+ bool IsStage() const { return type_ == Type::kStage; }
/// @returns true if token is a 'storage_buffer'
bool IsStorageBuffer() const { return type_ == Type::kStorageBuffer; }
/// @returns true if token is a 'stride'
diff --git a/test/function.wgsl b/test/function.wgsl
index b7060fb..d1c92d0 100644
--- a/test/function.wgsl
+++ b/test/function.wgsl
@@ -16,6 +16,7 @@
return ((2. * 3.) - 4.) / 5.;
}
+[[stage(compute)]]
[[workgroup_size(2)]]
fn ep() -> void {
return;