From 5b853eebc6cc851cd6b621e34baf5defd169661c Mon Sep 17 00:00:00 2001 From: dan sinclair Date: Mon, 22 Jun 2020 20:44:27 +0000 Subject: [PATCH] Support the zero initializer syntax. This Cl updates the system to allow zero initializers. This allows: ``` var a : vec3 = vec3(); ``` Bug: tint:34 Change-Id: I84d6b431914c4ddf112ed375fae028d912f4a080 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/23660 Reviewed-by: David Neto --- src/ast/type_constructor_expression.cc | 2 +- src/ast/type_constructor_expression_test.cc | 16 ++++---- src/reader/wgsl/parser_impl.cc | 12 ++++-- .../parser_impl_primary_expression_test.cc | 12 ++++++ src/writer/spirv/builder.cc | 6 +++ src/writer/spirv/builder_assign_test.cc | 39 +++++++++++++++++++ .../builder_constructor_expression_test.cc | 24 ++++++++++++ test/simple.wgsl | 1 + 8 files changed, 99 insertions(+), 13 deletions(-) diff --git a/src/ast/type_constructor_expression.cc b/src/ast/type_constructor_expression.cc index e53b87dbbc..e29e620d3a 100644 --- a/src/ast/type_constructor_expression.cc +++ b/src/ast/type_constructor_expression.cc @@ -40,7 +40,7 @@ bool TypeConstructorExpression::IsTypeConstructor() const { bool TypeConstructorExpression::IsValid() const { if (values_.empty()) { - return false; + return true; } if (type_ == nullptr) { return false; diff --git a/src/ast/type_constructor_expression_test.cc b/src/ast/type_constructor_expression_test.cc index 28b3608aae..c223fb5e07 100644 --- a/src/ast/type_constructor_expression_test.cc +++ b/src/ast/type_constructor_expression_test.cc @@ -66,6 +66,14 @@ TEST_F(TypeConstructorExpressionTest, IsValid) { EXPECT_TRUE(t.IsValid()); } +TEST_F(TypeConstructorExpressionTest, IsValid_EmptyValue) { + type::F32Type f32; + ExpressionList expr; + + TypeConstructorExpression t(&f32, std::move(expr)); + EXPECT_TRUE(t.IsValid()); +} + TEST_F(TypeConstructorExpressionTest, IsValid_NullType) { ExpressionList expr; expr.push_back(std::make_unique("expr")); @@ -94,14 +102,6 @@ TEST_F(TypeConstructorExpressionTest, IsValid_InvalidValue) { EXPECT_FALSE(t.IsValid()); } -TEST_F(TypeConstructorExpressionTest, IsValid_EmptyValue) { - type::F32Type f32; - ExpressionList expr; - - TypeConstructorExpression t(&f32, std::move(expr)); - EXPECT_FALSE(t.IsValid()); -} - TEST_F(TypeConstructorExpressionTest, ToStr) { type::F32Type f32; type::VectorType vec(&f32, 3); diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index 1886d62ddb..63e426bd0d 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc @@ -1943,7 +1943,7 @@ ast::StatementList ParserImpl::continuing_stmt() { // primary_expression // : (IDENT NAMESPACE)* IDENT -// | type_decl PAREN_LEFT argument_expression_list PAREN_RIGHT +// | type_decl PAREN_LEFT argument_expression_list* PAREN_RIGHT // | const_literal // | paren_rhs_stmt // | CAST LESS_THAN type_decl GREATER_THAN paren_rhs_stmt @@ -2043,9 +2043,13 @@ std::unique_ptr ParserImpl::primary_expression() { return nullptr; } - auto params = argument_expression_list(); - if (has_error()) - return nullptr; + t = peek(); + ast::ExpressionList params; + if (!t.IsParenRight() && !t.IsEof()) { + params = argument_expression_list(); + if (has_error()) + return nullptr; + } t = next(); if (!t.IsParenRight()) { diff --git a/src/reader/wgsl/parser_impl_primary_expression_test.cc b/src/reader/wgsl/parser_impl_primary_expression_test.cc index a5fd1d98f8..c2558e92f3 100644 --- a/src/reader/wgsl/parser_impl_primary_expression_test.cc +++ b/src/reader/wgsl/parser_impl_primary_expression_test.cc @@ -98,6 +98,18 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) { EXPECT_EQ(ident->literal()->AsSint()->value(), 4); } +TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_ZeroConstructor) { + auto* p = parser("vec4()"); + auto e = p->primary_expression(); + ASSERT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e, nullptr); + ASSERT_TRUE(e->IsConstructor()); + ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor()); + auto* ty = e->AsConstructor()->AsTypeConstructor(); + + ASSERT_EQ(ty->values().size(), 0u); +} + TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) { auto* p = parser("vec4(2., 3., 4., 5.)"); auto e = p->primary_expression(); diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index 0157837cc3..0a81e8eb03 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc @@ -940,6 +940,12 @@ uint32_t Builder::GenerateTypeConstructorExpression( return 0; } + // Generate the zero initializer if there are no values provided. + if (init->values().empty()) { + ast::NullLiteral nl(init->type()->UnwrapPtrIfNeeded()); + return GenerateLiteralIfNeeded(&nl); + } + auto* result_type = init->type()->UnwrapPtrIfNeeded(); if (result_type->IsVector()) { result_type = result_type->AsVector()->type(); diff --git a/src/writer/spirv/builder_assign_test.cc b/src/writer/spirv/builder_assign_test.cc index ad98cc3b79..d81af3b084 100644 --- a/src/writer/spirv/builder_assign_test.cc +++ b/src/writer/spirv/builder_assign_test.cc @@ -78,6 +78,45 @@ TEST_F(BuilderTest, Assign_Var) { )"); } +TEST_F(BuilderTest, Assign_Var_ZeroConstructor) { + ast::type::F32Type f32; + ast::type::VectorType vec(&f32, 3); + + ast::Variable v("var", ast::StorageClass::kOutput, &vec); + + auto ident = std::make_unique("var"); + ast::ExpressionList vals; + auto val = + std::make_unique(&vec, std::move(vals)); + + ast::AssignmentStatement assign(std::move(ident), std::move(val)); + + Context ctx; + ast::Module mod; + TypeDeterminer td(&ctx, &mod); + td.RegisterVariableForTesting(&v); + + ASSERT_TRUE(td.DetermineResultType(&assign)) << td.error(); + + Builder b(&mod); + b.push_function(Function{}); + EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error(); + ASSERT_FALSE(b.has_error()) << b.error(); + + EXPECT_TRUE(b.GenerateAssignStatement(&assign)) << b.error(); + EXPECT_FALSE(b.has_error()); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 +%3 = OpTypeVector %4 3 +%2 = OpTypePointer Output %3 +%5 = OpConstantNull %3 +%1 = OpVariable %2 Output %5 +)"); + + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %1 %5 +)"); +} + TEST_F(BuilderTest, Assign_Var_Complex_ConstructorWithExtract) { ast::type::F32Type f32; ast::type::VectorType vec3(&f32, 3); diff --git a/src/writer/spirv/builder_constructor_expression_test.cc b/src/writer/spirv/builder_constructor_expression_test.cc index df0c21905e..3a16281fef 100644 --- a/src/writer/spirv/builder_constructor_expression_test.cc +++ b/src/writer/spirv/builder_constructor_expression_test.cc @@ -82,6 +82,30 @@ TEST_F(BuilderTest, Constructor_Type) { )"); } +TEST_F(BuilderTest, Constructor_Type_ZeroInit) { + ast::type::F32Type f32; + ast::type::VectorType vec(&f32, 2); + + ast::ExpressionList vals; + ast::TypeConstructorExpression t(&vec, std::move(vals)); + + Context ctx; + ast::Module mod; + TypeDeterminer td(&ctx, &mod); + EXPECT_TRUE(td.DetermineResultType(&t)) << td.error(); + + Builder b(&mod); + b.push_function(Function{}); + + EXPECT_EQ(b.GenerateConstructorExpression(&t, false), 3u); + ASSERT_FALSE(b.has_error()) << b.error(); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32 +%1 = OpTypeVector %2 2 +%3 = OpConstantNull %1 +)"); +} + TEST_F(BuilderTest, Constructor_Type_NonConstructorParam) { ast::type::F32Type f32; ast::type::VectorType vec(&f32, 2); diff --git a/test/simple.wgsl b/test/simple.wgsl index da941a267b..e60ec1dd49 100644 --- a/test/simple.wgsl +++ b/test/simple.wgsl @@ -15,6 +15,7 @@ [[location 0]] var gl_FragColor : vec4; fn main() -> void { + var a : vec2 = vec2(); gl_FragColor = vec4(0.4, 0.4, 0.8, 1.0); return; }