From 1131d31761671e9e87baf57da0ec1fe5c925a61d Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Fri, 10 Feb 2023 19:24:24 +0000 Subject: [PATCH] tint/ast: Remove ast::StorageTexture Instead use ast::TypeName. Also improve the validation and diagnostics around providing template arguments to types that do not accept them. Bug: tint:1810 Change-Id: I4241d50ce0425ab721157686889e918993482876 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/119284 Reviewed-by: Dan Sinclair Reviewed-by: James Price Kokoro: Kokoro Commit-Queue: Ben Clayton --- src/tint/BUILD.gn | 21 +- src/tint/CMakeLists.txt | 3 - src/tint/ast/multisampled_texture_test.cc | 2 - src/tint/ast/sampled_texture_test.cc | 1 - src/tint/ast/storage_texture.cc | 84 ------- src/tint/ast/storage_texture.h | 77 ------- src/tint/ast/storage_texture_test.cc | 91 -------- src/tint/inspector/resource_binding.h | 2 +- src/tint/intrinsics.def | 5 + src/tint/program_builder.h | 43 ++-- src/tint/reader/spirv/parser_type.h | 3 +- .../wgsl/parser_impl_texture_sampler_test.cc | 15 +- src/tint/resolver/dependency_graph.cc | 64 +++--- src/tint/resolver/expression_kind_test.cc | 88 ++++---- src/tint/resolver/resolver.cc | 205 ++++++++++++------ src/tint/resolver/resolver.h | 7 +- src/tint/resolver/sem_helper.cc | 48 +++- src/tint/resolver/sem_helper.h | 60 +++-- src/tint/resolver/type_validation_test.cc | 136 ++++++++++-- src/tint/resolver/validator.cc | 17 +- src/tint/resolver/validator.h | 3 +- src/tint/transform/builtin_polyfill.cc | 20 +- src/tint/transform/texture_1d_to_2d.cc | 9 +- src/tint/transform/transform.cc | 3 +- src/tint/type/builtin.cc | 20 ++ src/tint/type/builtin.h | 8 + src/tint/type/builtin_bench.cc | 170 +++++++++------ src/tint/type/builtin_test.cc | 76 ++++--- src/tint/writer/wgsl/generator_impl.cc | 40 ++-- src/tint/writer/wgsl/generator_impl.h | 5 + 30 files changed, 709 insertions(+), 617 deletions(-) delete mode 100644 src/tint/ast/storage_texture.cc delete mode 100644 src/tint/ast/storage_texture.h delete mode 100644 src/tint/ast/storage_texture_test.cc diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index 99d7c9148a..4c851e1c44 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -301,7 +301,6 @@ libtint_source_set("libtint_syntax_tree_src") { "ast/sampled_texture.h", "ast/stage_attribute.h", "ast/statement.h", - "ast/storage_texture.h", "ast/stride_attribute.h", "ast/struct.h", "ast/struct_member.h", @@ -665,8 +664,6 @@ libtint_source_set("libtint_ast_src") { "ast/stage_attribute.h", "ast/statement.cc", "ast/statement.h", - "ast/storage_texture.cc", - "ast/storage_texture.h", "ast/stride_attribute.cc", "ast/stride_attribute.h", "ast/struct.cc", @@ -1279,6 +1276,18 @@ if (tint_build_unittests) { } } + tint_unittests_source_set("libtint_unittests_ast_helper") { + sources = [ + "ast/test_helper.h", + "ast/test_helper_test.cc", + ] + deps = [ + ":libtint_ast_src", + ":libtint_base_src", + ":libtint_syntax_tree_src", + ] + } + tint_unittests_source_set("tint_unittests_ast_src") { sources = [ "ast/alias_test.cc", @@ -1333,7 +1342,6 @@ if (tint_build_unittests) { "ast/return_statement_test.cc", "ast/sampled_texture_test.cc", "ast/stage_attribute_test.cc", - "ast/storage_texture_test.cc", "ast/stride_attribute_test.cc", "ast/struct_member_align_attribute_test.cc", "ast/struct_member_offset_attribute_test.cc", @@ -1342,8 +1350,6 @@ if (tint_build_unittests) { "ast/struct_test.cc", "ast/switch_statement_test.cc", "ast/templated_identifier_test.cc", - "ast/test_helper.h", - "ast/test_helper_test.cc", "ast/texture_test.cc", "ast/traverse_expressions_test.cc", "ast/type_name_test.cc", @@ -1358,6 +1364,7 @@ if (tint_build_unittests) { ":libtint_ast_src", ":libtint_base_src", ":libtint_transform_src", + ":libtint_unittests_ast_helper", ] if (tint_build_wgsl_reader && tint_build_wgsl_writer) { @@ -1797,6 +1804,7 @@ if (tint_build_unittests) { deps = [ ":libtint_base_src", + ":libtint_unittests_ast_helper", ":libtint_wgsl_reader_src", ] } @@ -1993,6 +2001,7 @@ if (tint_build_unittests) { deps = [ ":libtint_base_src", + ":libtint_unittests_ast_helper", ":tint_unittests_ast_src", ] } diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index d3d3097b67..e80e1f8598 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -201,8 +201,6 @@ list(APPEND TINT_LIB_SRCS ast/stage_attribute.h ast/statement.cc ast/statement.h - ast/storage_texture.cc - ast/storage_texture.h ast/stride_attribute.cc ast/stride_attribute.h ast/struct_member_align_attribute.cc @@ -856,7 +854,6 @@ if(TINT_BUILD_TESTS) ast/return_statement_test.cc ast/sampled_texture_test.cc ast/stage_attribute_test.cc - ast/storage_texture_test.cc ast/stride_attribute_test.cc ast/struct_member_align_attribute_test.cc ast/struct_member_offset_attribute_test.cc diff --git a/src/tint/ast/multisampled_texture_test.cc b/src/tint/ast/multisampled_texture_test.cc index 2b81a0a29d..6b8125c903 100644 --- a/src/tint/ast/multisampled_texture_test.cc +++ b/src/tint/ast/multisampled_texture_test.cc @@ -19,7 +19,6 @@ #include "src/tint/ast/matrix.h" #include "src/tint/ast/pointer.h" #include "src/tint/ast/sampled_texture.h" -#include "src/tint/ast/storage_texture.h" #include "src/tint/ast/struct.h" #include "src/tint/ast/test_helper.h" #include "src/tint/ast/texture.h" @@ -35,7 +34,6 @@ TEST_F(AstMultisampledTextureTest, IsTexture) { Texture* t = create(type::TextureDimension::kCube, ty.f32()); EXPECT_TRUE(t->Is()); EXPECT_FALSE(t->Is()); - EXPECT_FALSE(t->Is()); } TEST_F(AstMultisampledTextureTest, Dim) { diff --git a/src/tint/ast/sampled_texture_test.cc b/src/tint/ast/sampled_texture_test.cc index 506b259e3d..01d7b656a9 100644 --- a/src/tint/ast/sampled_texture_test.cc +++ b/src/tint/ast/sampled_texture_test.cc @@ -24,7 +24,6 @@ using AstSampledTextureTest = TestHelper; TEST_F(AstSampledTextureTest, IsTexture) { Texture* t = create(type::TextureDimension::kCube, ty.f32()); EXPECT_TRUE(t->Is()); - EXPECT_FALSE(t->Is()); } TEST_F(AstSampledTextureTest, Dim) { diff --git a/src/tint/ast/storage_texture.cc b/src/tint/ast/storage_texture.cc deleted file mode 100644 index cb2cee7cf7..0000000000 --- a/src/tint/ast/storage_texture.cc +++ /dev/null @@ -1,84 +0,0 @@ -// 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/tint/ast/storage_texture.h" - -#include "src/tint/program_builder.h" - -TINT_INSTANTIATE_TYPEINFO(tint::ast::StorageTexture); - -namespace tint::ast { - -StorageTexture::StorageTexture(ProgramID pid, - NodeID nid, - const Source& src, - type::TextureDimension d, - type::TexelFormat fmt, - const Type* subtype, - type::Access ac) - : Base(pid, nid, src, d), format(fmt), type(subtype), access(ac) {} - -StorageTexture::StorageTexture(StorageTexture&&) = default; - -StorageTexture::~StorageTexture() = default; - -std::string StorageTexture::FriendlyName(const SymbolTable&) const { - std::ostringstream out; - out << "texture_storage_" << dim << "<" << format << ", " << access << ">"; - return out.str(); -} - -const StorageTexture* StorageTexture::Clone(CloneContext* ctx) const { - // Clone arguments outside of create() call to have deterministic ordering - auto src = ctx->Clone(source); - auto* ty = ctx->Clone(type); - return ctx->dst->create(src, dim, format, ty, access); -} - -const Type* StorageTexture::SubtypeFor(type::TexelFormat format, ProgramBuilder& builder) { - switch (format) { - case type::TexelFormat::kR32Uint: - case type::TexelFormat::kRgba8Uint: - case type::TexelFormat::kRg32Uint: - case type::TexelFormat::kRgba16Uint: - case type::TexelFormat::kRgba32Uint: { - return builder.ty.u32(); - } - - case type::TexelFormat::kR32Sint: - case type::TexelFormat::kRgba8Sint: - case type::TexelFormat::kRg32Sint: - case type::TexelFormat::kRgba16Sint: - case type::TexelFormat::kRgba32Sint: { - return builder.ty.i32(); - } - - case type::TexelFormat::kBgra8Unorm: - case type::TexelFormat::kRgba8Unorm: - case type::TexelFormat::kRgba8Snorm: - case type::TexelFormat::kR32Float: - case type::TexelFormat::kRg32Float: - case type::TexelFormat::kRgba16Float: - case type::TexelFormat::kRgba32Float: { - return builder.ty.f32(); - } - - case type::TexelFormat::kUndefined: - break; - } - - return nullptr; -} - -} // namespace tint::ast diff --git a/src/tint/ast/storage_texture.h b/src/tint/ast/storage_texture.h deleted file mode 100644 index 646bca0524..0000000000 --- a/src/tint/ast/storage_texture.h +++ /dev/null @@ -1,77 +0,0 @@ -// 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_TINT_AST_STORAGE_TEXTURE_H_ -#define SRC_TINT_AST_STORAGE_TEXTURE_H_ - -#include - -#include "src/tint/ast/texture.h" -#include "src/tint/type/access.h" -#include "src/tint/type/texel_format.h" -#include "src/tint/type/texture_dimension.h" - -namespace tint::ast { - -/// A storage texture type. -class StorageTexture final : public Castable { - public: - /// Constructor - /// @param pid the identifier of the program that owns this node - /// @param nid the unique node identifier - /// @param src the source of this node - /// @param dim the dimensionality of the texture - /// @param format the image format of the texture - /// @param subtype the storage subtype. Use SubtypeFor() to calculate this. - /// @param access_control the access control for the texture. - StorageTexture(ProgramID pid, - NodeID nid, - const Source& src, - type::TextureDimension dim, - type::TexelFormat format, - const Type* subtype, - type::Access access_control); - - /// Move constructor - StorageTexture(StorageTexture&&); - ~StorageTexture() override; - - /// @param symbols the program's symbol table - /// @returns the name for this type that closely resembles how it would be - /// declared in WGSL. - std::string FriendlyName(const SymbolTable& symbols) const override; - - /// Clones this type and all transitive types using the `CloneContext` `ctx`. - /// @param ctx the clone context - /// @return the newly cloned type - const StorageTexture* Clone(CloneContext* ctx) const override; - - /// @param format the storage texture image format - /// @param builder the ProgramBuilder used to build the returned type - /// @returns the storage texture subtype for the given TexelFormat - static const Type* SubtypeFor(type::TexelFormat format, ProgramBuilder& builder); - - /// The image format - const type::TexelFormat format; - - /// The storage subtype - const Type* const type; - - /// The access control - const type::Access access; -}; - -} // namespace tint::ast - -#endif // SRC_TINT_AST_STORAGE_TEXTURE_H_ diff --git a/src/tint/ast/storage_texture_test.cc b/src/tint/ast/storage_texture_test.cc deleted file mode 100644 index e03c4b328f..0000000000 --- a/src/tint/ast/storage_texture_test.cc +++ /dev/null @@ -1,91 +0,0 @@ -// 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/tint/ast/storage_texture.h" - -#include "src/tint/ast/test_helper.h" - -namespace tint::ast { -namespace { - -using AstStorageTextureTest = TestHelper; - -TEST_F(AstStorageTextureTest, IsTexture) { - auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Float, *this); - Texture* ty = - create(type::TextureDimension::k2dArray, type::TexelFormat::kRgba32Float, - subtype, type::Access::kRead); - EXPECT_FALSE(ty->Is()); - EXPECT_TRUE(ty->Is()); -} - -TEST_F(AstStorageTextureTest, Dim) { - auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Float, *this); - auto* s = create(type::TextureDimension::k2dArray, - type::TexelFormat::kRgba32Float, subtype, type::Access::kRead); - EXPECT_EQ(s->dim, type::TextureDimension::k2dArray); -} - -TEST_F(AstStorageTextureTest, Format) { - auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Float, *this); - auto* s = create(type::TextureDimension::k2dArray, - type::TexelFormat::kRgba32Float, subtype, type::Access::kRead); - EXPECT_EQ(s->format, type::TexelFormat::kRgba32Float); -} - -TEST_F(AstStorageTextureTest, FriendlyName) { - auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Float, *this); - auto* s = create(type::TextureDimension::k2dArray, - type::TexelFormat::kRgba32Float, subtype, type::Access::kRead); - EXPECT_EQ(s->FriendlyName(Symbols()), "texture_storage_2d_array"); -} - -TEST_F(AstStorageTextureTest, F32) { - auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Float, *this); - Type* s = create(type::TextureDimension::k2dArray, - type::TexelFormat::kRgba32Float, subtype, type::Access::kRead); - - ASSERT_TRUE(s->Is()); - ASSERT_TRUE(s->Is()); - ASSERT_TRUE(s->As()->type->Is()); - EXPECT_EQ(Symbols().NameFor(s->As()->type->As()->name->symbol), - "f32"); -} - -TEST_F(AstStorageTextureTest, U32) { - auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRg32Uint, *this); - Type* s = create(type::TextureDimension::k2dArray, type::TexelFormat::kRg32Uint, - subtype, type::Access::kRead); - - ASSERT_TRUE(s->Is()); - ASSERT_TRUE(s->Is()); - ASSERT_TRUE(s->As()->type->Is()); - EXPECT_EQ(Symbols().NameFor(s->As()->type->As()->name->symbol), - "u32"); -} - -TEST_F(AstStorageTextureTest, I32) { - auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Sint, *this); - Type* s = create(type::TextureDimension::k2dArray, - type::TexelFormat::kRgba32Sint, subtype, type::Access::kRead); - - ASSERT_TRUE(s->Is()); - ASSERT_TRUE(s->Is()); - ASSERT_TRUE(s->As()->type->Is()); - EXPECT_EQ(Symbols().NameFor(s->As()->type->As()->name->symbol), - "i32"); -} - -} // namespace -} // namespace tint::ast diff --git a/src/tint/inspector/resource_binding.h b/src/tint/inspector/resource_binding.h index d9686048ce..4c1e0c7a96 100644 --- a/src/tint/inspector/resource_binding.h +++ b/src/tint/inspector/resource_binding.h @@ -17,7 +17,7 @@ #include -#include "src/tint/ast/storage_texture.h" +#include "src/tint/type/texel_format.h" #include "src/tint/type/texture_dimension.h" #include "src/tint/type/type.h" diff --git a/src/tint/intrinsics.def b/src/tint/intrinsics.def index db589a1961..c49048263b 100644 --- a/src/tint/intrinsics.def +++ b/src/tint/intrinsics.def @@ -176,6 +176,11 @@ enum builtin_type { texture_depth_cube texture_depth_cube_array texture_depth_multisampled_2d + // https://www.w3.org/TR/WGSL/#texture-storage + texture_storage_1d + texture_storage_2d + texture_storage_2d_array + texture_storage_3d // https://www.w3.org/TR/WGSL/#external-texture-type texture_external } diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h index c24dc25cb6..0541511e15 100644 --- a/src/tint/program_builder.h +++ b/src/tint/program_builder.h @@ -68,7 +68,6 @@ #include "src/tint/ast/return_statement.h" #include "src/tint/ast/sampled_texture.h" #include "src/tint/ast/stage_attribute.h" -#include "src/tint/ast/storage_texture.h" #include "src/tint/ast/stride_attribute.h" #include "src/tint/ast/struct_member_align_attribute.h" #include "src/tint/ast/struct_member_offset_attribute.h" @@ -1063,25 +1062,41 @@ class ProgramBuilder { /// @param dims the dimensionality of the texture /// @param format the texel format of the texture /// @param access the access control of the texture - /// @returns the storage texture - const ast::StorageTexture* storage_texture(type::TextureDimension dims, - type::TexelFormat format, - type::Access access) const { - auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder); - return builder->create(dims, format, subtype, access); + /// @returns the storage texture typename + const ast::TypeName* storage_texture(type::TextureDimension dims, + type::TexelFormat format, + type::Access access) const { + return storage_texture(builder->source_, dims, format, access); } /// @param source the Source of the node /// @param dims the dimensionality of the texture /// @param format the texel format of the texture /// @param access the access control of the texture - /// @returns the storage texture - const ast::StorageTexture* storage_texture(const Source& source, - type::TextureDimension dims, - type::TexelFormat format, - type::Access access) const { - auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder); - return builder->create(source, dims, format, subtype, access); + /// @returns the storage texture typename + const ast::TypeName* storage_texture(const Source& source, + type::TextureDimension dims, + type::TexelFormat format, + type::Access access) const { + switch (dims) { + case type::TextureDimension::k1d: + return (*this)(source, "texture_storage_1d", utils::ToString(format), + utils::ToString(access)); + case type::TextureDimension::k2d: + return (*this)(source, "texture_storage_2d", utils::ToString(format), + utils::ToString(access)); + case type::TextureDimension::k2dArray: + return (*this)(source, "texture_storage_2d_array", utils::ToString(format), + utils::ToString(access)); + case type::TextureDimension::k3d: + return (*this)(source, "texture_storage_3d", utils::ToString(format), + utils::ToString(access)); + default: + break; + } + TINT_ICE(ProgramBuilder, builder->Diagnostics()) + << "invalid sampled_texture dimensions: " << dims; + return nullptr; } /// @returns the external texture diff --git a/src/tint/reader/spirv/parser_type.h b/src/tint/reader/spirv/parser_type.h index 33f7e05cdc..04c8c67928 100644 --- a/src/tint/reader/spirv/parser_type.h +++ b/src/tint/reader/spirv/parser_type.h @@ -19,11 +19,12 @@ #include #include -#include "src/tint/ast/storage_texture.h" #include "src/tint/castable.h" +#include "src/tint/symbol.h" #include "src/tint/type/access.h" #include "src/tint/type/address_space.h" #include "src/tint/type/sampler_kind.h" +#include "src/tint/type/texel_format.h" #include "src/tint/type/texture_dimension.h" #include "src/tint/utils/block_allocator.h" diff --git a/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc b/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc index 29d62c58b6..37dbd97d55 100644 --- a/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc +++ b/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/tint/ast/test_helper.h" #include "src/tint/reader/wgsl/parser_impl_test_helper.h" #include "src/tint/type/depth_texture.h" #include "src/tint/type/multisampled_texture.h" @@ -195,11 +196,8 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dRg32Float) { EXPECT_FALSE(t.errored); ASSERT_NE(t.value, nullptr); - ASSERT_TRUE(t->Is()); - ASSERT_TRUE(t->Is()); - EXPECT_EQ(t->As()->format, type::TexelFormat::kRg32Float); - EXPECT_EQ(t->As()->access, type::Access::kRead); - EXPECT_EQ(t->As()->dim, type::TextureDimension::k1d); + ast::CheckIdentifier(p->builder().Symbols(), t->As()->name, + ast::Template("texture_storage_1d", "rg32float", "read")); EXPECT_EQ(t->source.range, (Source::Range{{1u, 1u}, {1u, 36u}})); } @@ -211,11 +209,8 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR32Uint) { EXPECT_FALSE(t.errored); ASSERT_NE(t.value, nullptr); - ASSERT_TRUE(t->Is()); - ASSERT_TRUE(t->Is()); - EXPECT_EQ(t->As()->format, type::TexelFormat::kR32Uint); - EXPECT_EQ(t->As()->access, type::Access::kWrite); - EXPECT_EQ(t->As()->dim, type::TextureDimension::k2d); + ast::CheckIdentifier(p->builder().Symbols(), t->As()->name, + ast::Template("texture_storage_2d", "r32uint", "write")); EXPECT_EQ(t->source.range, (Source::Range{{1u, 1u}, {1u, 35u}})); } diff --git a/src/tint/resolver/dependency_graph.cc b/src/tint/resolver/dependency_graph.cc index 9358335a6e..e581b9aa0d 100644 --- a/src/tint/resolver/dependency_graph.cc +++ b/src/tint/resolver/dependency_graph.cc @@ -48,7 +48,6 @@ #include "src/tint/ast/return_statement.h" #include "src/tint/ast/sampled_texture.h" #include "src/tint/ast/stage_attribute.h" -#include "src/tint/ast/storage_texture.h" #include "src/tint/ast/stride_attribute.h" #include "src/tint/ast/struct.h" #include "src/tint/ast/struct_member_align_attribute.h" @@ -338,31 +337,44 @@ class DependencyScanner { } } - /// Traverses the expression, performing symbol resolution and determining - /// global dependencies. + /// Traverses the expression, performing symbol resolution and determining global dependencies. void TraverseExpression(const ast::Expression* root) { if (!root) { return; } - ast::TraverseExpressions(root, diagnostics_, [&](const ast::Expression* expr) { - Switch( - expr, - [&](const ast::IdentifierExpression* ident) { - AddDependency(ident->identifier, ident->identifier->symbol, "identifier", - "references"); - }, - [&](const ast::CallExpression* call) { - if (call->target.name) { - AddDependency(call->target.name, call->target.name->symbol, "function", - "calls"); - } - if (call->target.type) { - TraverseType(call->target.type); - } - }, - [&](const ast::BitcastExpression* cast) { TraverseType(cast->type); }); - return ast::TraverseAction::Descend; - }); + utils::Vector pending{root}; + while (!pending.IsEmpty()) { + ast::TraverseExpressions(pending.Pop(), diagnostics_, [&](const ast::Expression* expr) { + Switch( + expr, + [&](const ast::IdentifierExpression* e) { + AddDependency(e->identifier, e->identifier->symbol, "identifier", + "references"); + if (auto* tmpl_ident = e->identifier->As()) { + for (auto* arg : tmpl_ident->arguments) { + pending.Push(arg); + } + } + }, + [&](const ast::CallExpression* call) { + if (call->target.name) { + AddDependency(call->target.name, call->target.name->symbol, "function", + "calls"); + if (auto* tmpl_ident = + call->target.name->As()) { + for (auto* arg : tmpl_ident->arguments) { + pending.Push(arg); + } + } + } + if (call->target.type) { + TraverseType(call->target.type); + } + }, + [&](const ast::BitcastExpression* cast) { TraverseType(cast->type); }); + return ast::TraverseAction::Descend; + }); + } } /// Traverses the type node, performing symbol resolution and determining @@ -388,6 +400,11 @@ class DependencyScanner { }, [&](const ast::TypeName* tn) { // AddDependency(tn->name, tn->name->symbol, "type", "references"); + if (auto* tmpl_ident = tn->name->As()) { + for (auto* arg : tmpl_ident->arguments) { + TraverseExpression(arg); + } + } }, [&](const ast::Vector* vec) { // TraverseType(vec->type); @@ -398,9 +415,6 @@ class DependencyScanner { [&](const ast::MultisampledTexture* tex) { // TraverseType(tex->type); }, - [&](const ast::StorageTexture* tex) { // - TraverseType(tex->type); - }, [&](Default) { UnhandledNode(diagnostics_, ty); }); } diff --git a/src/tint/resolver/expression_kind_test.cc b/src/tint/resolver/expression_kind_test.cc index 8581560889..773765471c 100644 --- a/src/tint/resolver/expression_kind_test.cc +++ b/src/tint/resolver/expression_kind_test.cc @@ -121,7 +121,7 @@ TEST_P(ResolverExpressionKindTest, Test) { Symbol sym; switch (GetParam().def) { case Def::kAccess: - sym = Sym("read_write"); + sym = Sym("write"); break; case Def::kAddressSpace: sym = Sym("workgroup"); @@ -155,7 +155,8 @@ TEST_P(ResolverExpressionKindTest, Test) { switch (GetParam().use) { case Use::kAccess: - return; // TODO(crbug.com/tint/1810) + GlobalVar("v", ty("texture_storage_2d", "rgba8unorm", sym), Group(0_u), Binding(0_u)); + break; case Use::kAddressSpace: return; // TODO(crbug.com/tint/1810) case Use::kCallExpr: @@ -174,7 +175,8 @@ TEST_P(ResolverExpressionKindTest, Test) { Structure("s", utils::Vector{Member("m", ty(kUseSource, sym))}); break; case Use::kTexelFormat: - return; // TODO(crbug.com/tint/1810) + GlobalVar("v", ty("texture_storage_2d", sym, "write"), Group(0_u), Binding(0_u)); + break; case Use::kValueExpression: GlobalVar("v", type::AddressSpace::kPrivate, Expr(kUseSource, sym)); break; @@ -201,21 +203,18 @@ INSTANTIATE_TEST_SUITE_P( testing::ValuesIn(std::vector{ {Def::kAccess, Use::kAccess, kPass}, {Def::kAccess, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, - {Def::kAccess, Use::kBinaryOp, R"(5:6 error: cannot use access 'read_write' as value)"}, - {Def::kAccess, Use::kCallExpr, - R"(5:6 error: cannot use access 'read_write' as call target)"}, - {Def::kAccess, Use::kCallStmt, - R"(5:6 error: cannot use access 'read_write' as call target)"}, - {Def::kAccess, Use::kFunctionReturnType, - R"(5:6 error: cannot use access 'read_write' as type)"}, - {Def::kAccess, Use::kMemberType, R"(5:6 error: cannot use access 'read_write' as type)"}, - {Def::kAccess, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, - {Def::kAccess, Use::kValueExpression, - R"(5:6 error: cannot use access 'read_write' as value)"}, - {Def::kAccess, Use::kVariableType, R"(5:6 error: cannot use access 'read_write' as type)"}, - {Def::kAccess, Use::kUnaryOp, R"(5:6 error: cannot use access 'read_write' as value)"}, + {Def::kAccess, Use::kBinaryOp, R"(5:6 error: cannot use access 'write' as value)"}, + {Def::kAccess, Use::kCallExpr, R"(5:6 error: cannot use access 'write' as call target)"}, + {Def::kAccess, Use::kCallStmt, R"(5:6 error: cannot use access 'write' as call target)"}, + {Def::kAccess, Use::kFunctionReturnType, R"(5:6 error: cannot use access 'write' as type)"}, + {Def::kAccess, Use::kMemberType, R"(5:6 error: cannot use access 'write' as type)"}, + {Def::kAccess, Use::kTexelFormat, R"(error: cannot use access 'write' as texel format)"}, + {Def::kAccess, Use::kValueExpression, R"(5:6 error: cannot use access 'write' as value)"}, + {Def::kAccess, Use::kVariableType, R"(5:6 error: cannot use access 'write' as type)"}, + {Def::kAccess, Use::kUnaryOp, R"(5:6 error: cannot use access 'write' as value)"}, - {Def::kAddressSpace, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, + {Def::kAddressSpace, Use::kAccess, + R"(error: cannot use address space 'workgroup' as access)"}, {Def::kAddressSpace, Use::kAddressSpace, kPass}, {Def::kAddressSpace, Use::kBinaryOp, R"(5:6 error: cannot use address space 'workgroup' as value)"}, @@ -227,7 +226,8 @@ INSTANTIATE_TEST_SUITE_P( R"(5:6 error: cannot use address space 'workgroup' as type)"}, {Def::kAddressSpace, Use::kMemberType, R"(5:6 error: cannot use address space 'workgroup' as type)"}, - {Def::kAddressSpace, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, + {Def::kAddressSpace, Use::kTexelFormat, + R"(error: cannot use address space 'workgroup' as texel format)"}, {Def::kAddressSpace, Use::kValueExpression, R"(5:6 error: cannot use address space 'workgroup' as value)"}, {Def::kAddressSpace, Use::kVariableType, @@ -235,7 +235,7 @@ INSTANTIATE_TEST_SUITE_P( {Def::kAddressSpace, Use::kUnaryOp, R"(5:6 error: cannot use address space 'workgroup' as value)"}, - {Def::kBuiltinFunction, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, + {Def::kBuiltinFunction, Use::kAccess, R"(error: missing '(' for builtin function call)"}, {Def::kBuiltinFunction, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kBuiltinFunction, Use::kBinaryOp, R"(7:8 error: missing '(' for builtin function call)"}, @@ -244,7 +244,8 @@ INSTANTIATE_TEST_SUITE_P( R"(5:6 error: cannot use builtin function 'workgroupBarrier' as type)"}, {Def::kBuiltinFunction, Use::kMemberType, R"(5:6 error: cannot use builtin function 'workgroupBarrier' as type)"}, - {Def::kBuiltinFunction, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, + {Def::kBuiltinFunction, Use::kTexelFormat, + R"(error: missing '(' for builtin function call)"}, {Def::kBuiltinFunction, Use::kValueExpression, R"(7:8 error: missing '(' for builtin function call)"}, {Def::kBuiltinFunction, Use::kVariableType, @@ -252,7 +253,7 @@ INSTANTIATE_TEST_SUITE_P( {Def::kBuiltinFunction, Use::kUnaryOp, R"(7:8 error: missing '(' for builtin function call)"}, - {Def::kBuiltinType, Use::kAccess, kPass}, + {Def::kBuiltinType, Use::kAccess, R"(error: cannot use type 'vec4' as access)"}, {Def::kBuiltinType, Use::kAddressSpace, kPass}, {Def::kBuiltinType, Use::kBinaryOp, R"(5:6 error: cannot use type 'vec4' as value @@ -260,7 +261,8 @@ INSTANTIATE_TEST_SUITE_P( {Def::kBuiltinType, Use::kCallExpr, kPass}, {Def::kBuiltinType, Use::kFunctionReturnType, kPass}, {Def::kBuiltinType, Use::kMemberType, kPass}, - {Def::kBuiltinType, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, + {Def::kBuiltinType, Use::kTexelFormat, + R"(error: cannot use type 'vec4' as texel format)"}, {Def::kBuiltinType, Use::kValueExpression, R"(5:6 error: cannot use type 'vec4' as value 7:8 note: are you missing '()' for type initializer?)"}, @@ -269,43 +271,44 @@ INSTANTIATE_TEST_SUITE_P( R"(5:6 error: cannot use type 'vec4' as value 7:8 note: are you missing '()' for type initializer?)"}, - {Def::kFunction, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, + {Def::kFunction, Use::kAccess, R"(error: missing '(' for function call)"}, {Def::kFunction, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kFunction, Use::kBinaryOp, R"(7:8 error: missing '(' for function call)"}, {Def::kFunction, Use::kCallExpr, kPass}, {Def::kFunction, Use::kCallStmt, kPass}, {Def::kFunction, Use::kFunctionReturnType, R"(5:6 error: cannot use function 'FUNCTION' as type -1:2 note: 'FUNCTION' declared here)"}, +1:2 note: function 'FUNCTION' declared here)"}, {Def::kFunction, Use::kMemberType, R"(5:6 error: cannot use function 'FUNCTION' as type -1:2 note: 'FUNCTION' declared here)"}, - {Def::kFunction, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, +1:2 note: function 'FUNCTION' declared here)"}, + {Def::kFunction, Use::kTexelFormat, R"(error: missing '(' for function call)"}, {Def::kFunction, Use::kValueExpression, R"(7:8 error: missing '(' for function call)"}, {Def::kFunction, Use::kVariableType, R"(5:6 error: cannot use function 'FUNCTION' as type -1:2 note: 'FUNCTION' declared here)"}, +1:2 note: function 'FUNCTION' declared here)"}, {Def::kFunction, Use::kUnaryOp, R"(7:8 error: missing '(' for function call)"}, - {Def::kStruct, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, + {Def::kStruct, Use::kAccess, R"(error: cannot use type 'STRUCT' as access)"}, {Def::kStruct, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kStruct, Use::kBinaryOp, R"(5:6 error: cannot use type 'STRUCT' as value 7:8 note: are you missing '()' for type initializer? -1:2 note: 'STRUCT' declared here)"}, +1:2 note: struct 'STRUCT' declared here)"}, {Def::kStruct, Use::kFunctionReturnType, kPass}, {Def::kStruct, Use::kMemberType, kPass}, - {Def::kStruct, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, + {Def::kStruct, Use::kTexelFormat, R"(error: cannot use type 'STRUCT' as texel format)"}, {Def::kStruct, Use::kValueExpression, R"(5:6 error: cannot use type 'STRUCT' as value 7:8 note: are you missing '()' for type initializer? -1:2 note: 'STRUCT' declared here)"}, +1:2 note: struct 'STRUCT' declared here)"}, {Def::kStruct, Use::kVariableType, kPass}, {Def::kStruct, Use::kUnaryOp, R"(5:6 error: cannot use type 'STRUCT' as value 7:8 note: are you missing '()' for type initializer? -1:2 note: 'STRUCT' declared here)"}, +1:2 note: struct 'STRUCT' declared here)"}, - {Def::kTexelFormat, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, + {Def::kTexelFormat, Use::kAccess, + R"(error: cannot use texel format 'rgba8unorm' as access)"}, {Def::kTexelFormat, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kTexelFormat, Use::kBinaryOp, R"(5:6 error: cannot use texel format 'rgba8unorm' as value)"}, @@ -325,7 +328,7 @@ INSTANTIATE_TEST_SUITE_P( {Def::kTexelFormat, Use::kUnaryOp, R"(5:6 error: cannot use texel format 'rgba8unorm' as value)"}, - {Def::kTypeAlias, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, + {Def::kTypeAlias, Use::kAccess, R"(error: cannot use type 'i32' as access)"}, {Def::kTypeAlias, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kTypeAlias, Use::kBinaryOp, R"(5:6 error: cannot use type 'i32' as value @@ -333,7 +336,7 @@ INSTANTIATE_TEST_SUITE_P( {Def::kTypeAlias, Use::kCallExpr, kPass}, {Def::kTypeAlias, Use::kFunctionReturnType, kPass}, {Def::kTypeAlias, Use::kMemberType, kPass}, - {Def::kTypeAlias, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, + {Def::kTypeAlias, Use::kTexelFormat, R"(error: cannot use type 'i32' as texel format)"}, {Def::kTypeAlias, Use::kValueExpression, R"(5:6 error: cannot use type 'i32' as value 7:8 note: are you missing '()' for type initializer?)"}, @@ -342,26 +345,27 @@ INSTANTIATE_TEST_SUITE_P( R"(5:6 error: cannot use type 'i32' as value 7:8 note: are you missing '()' for type initializer?)"}, - {Def::kVariable, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, + {Def::kVariable, Use::kAccess, R"(error: cannot use 'VARIABLE' of type 'i32' as access)"}, {Def::kVariable, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kVariable, Use::kBinaryOp, kPass}, {Def::kVariable, Use::kCallStmt, R"(5:6 error: cannot use const 'VARIABLE' as call target -1:2 note: 'VARIABLE' declared here)"}, +1:2 note: const 'VARIABLE' declared here)"}, {Def::kVariable, Use::kCallExpr, R"(5:6 error: cannot use const 'VARIABLE' as call target -1:2 note: 'VARIABLE' declared here)"}, +1:2 note: const 'VARIABLE' declared here)"}, {Def::kVariable, Use::kFunctionReturnType, R"(5:6 error: cannot use const 'VARIABLE' as type -1:2 note: 'VARIABLE' declared here)"}, +1:2 note: const 'VARIABLE' declared here)"}, {Def::kVariable, Use::kMemberType, R"(5:6 error: cannot use const 'VARIABLE' as type -1:2 note: 'VARIABLE' declared here)"}, - {Def::kVariable, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, +1:2 note: const 'VARIABLE' declared here)"}, + {Def::kVariable, Use::kTexelFormat, + R"(error: cannot use 'VARIABLE' of type 'i32' as texel format)"}, {Def::kVariable, Use::kValueExpression, kPass}, {Def::kVariable, Use::kVariableType, R"(5:6 error: cannot use const 'VARIABLE' as type -1:2 note: 'VARIABLE' declared here)"}, +1:2 note: const 'VARIABLE' declared here)"}, {Def::kVariable, Use::kUnaryOp, kPass}, })); diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc index 06b0c184f1..ab1970a499 100644 --- a/src/tint/resolver/resolver.cc +++ b/src/tint/resolver/resolver.cc @@ -40,7 +40,6 @@ #include "src/tint/ast/pointer.h" #include "src/tint/ast/return_statement.h" #include "src/tint/ast/sampled_texture.h" -#include "src/tint/ast/storage_texture.h" #include "src/tint/ast/switch_statement.h" #include "src/tint/ast/traverse_expressions.h" #include "src/tint/ast/type_name.h" @@ -308,22 +307,9 @@ type::Type* Resolver::Type(const ast::Type* ty) { } return nullptr; }, - [&](const ast::StorageTexture* t) -> type::StorageTexture* { - if (auto* el = Type(t->type)) { - if (!validator_.StorageTexture(t)) { - return nullptr; - } - return builder_->create(t->dim, t->format, t->access, el); - } - return nullptr; - }, [&](const ast::TypeName* t) -> type::Type* { Mark(t->name); - if (t->name->Is()) { - TINT_UNREACHABLE(Resolver, diagnostics_) << "TODO(crbug.com/tint/1810)"; - } - auto resolved = dependencies_.resolved_identifiers.Get(t->name); if (!resolved) { TINT_ICE(Resolver, diagnostics_) @@ -338,6 +324,15 @@ type::Type* Resolver::Type(const ast::Type* ty) { ErrorMismatchedResolvedIdentifier(t->source, *resolved, "type"); return nullptr; } + + if (TINT_UNLIKELY(t->name->Is())) { + AddError("type '" + builder_->Symbols().NameFor(t->name->symbol) + + "' does not take template arguments", + t->source); + NoteDeclarationSource(ast_node); + return nullptr; + } + return type; } if (auto b = resolved->BuiltinType(); b != type::Builtin::kUndefined) { @@ -2431,9 +2426,18 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr, return call; } -type::Type* Resolver::BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident) const { +type::Type* Resolver::BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident) { auto& b = *builder_; + auto check_no_tmpl_args = [&](type::Type* ty) -> type::Type* { + if (TINT_UNLIKELY(ident->Is())) { + AddError("type '" + b.Symbols().NameFor(ident->symbol) + + "' does not take template arguments", + ident->source); + return nullptr; + } + return ty; + }; auto f32 = [&] { return b.create(); }; auto i32 = [&] { return b.create(); }; auto u32 = [&] { return b.create(); }; @@ -2446,94 +2450,143 @@ type::Type* Resolver::BuiltinType(type::Builtin builtin_ty, const ast::Identifie auto mat = [&](type::Type* el, uint32_t num_columns, uint32_t num_rows) { return el ? b.create(vec(el, num_rows), num_columns) : nullptr; }; + auto templated_identifier = [&](size_t num_args) -> const ast::TemplatedIdentifier* { + auto* tmpl_ident = ident->As(); + if (TINT_UNLIKELY(!tmpl_ident)) { + AddError("expected '<' for '" + b.Symbols().NameFor(ident->symbol) + "'", + Source{ident->source.range.end}); + return nullptr; + } + if (TINT_UNLIKELY(tmpl_ident->arguments.Length() != num_args)) { + AddError("'" + b.Symbols().NameFor(ident->symbol) + "' requires " + + std::to_string(num_args) + " template arguments", + ident->source); + return nullptr; + } + return tmpl_ident; + }; + auto storage_texture = [&](type::TextureDimension dim) -> type::StorageTexture* { + auto* tmpl_ident = templated_identifier(2); + if (TINT_UNLIKELY(!tmpl_ident)) { + return nullptr; + } + auto* format = sem_.AsTexelFormat(Expression(tmpl_ident->arguments[0])); + if (TINT_UNLIKELY(!format)) { + return nullptr; + } + auto* access = sem_.AsAccess(Expression(tmpl_ident->arguments[1])); + if (TINT_UNLIKELY(!access)) { + return nullptr; + } + auto* subtype = type::StorageTexture::SubtypeFor(format->Value(), builder_->Types()); + auto* tex = b.create(dim, format->Value(), access->Value(), subtype); + if (!validator_.StorageTexture(tex, ident->source)) { + return nullptr; + } + return tex; + }; switch (builtin_ty) { case type::Builtin::kBool: - return b.create(); + return check_no_tmpl_args(b.create()); case type::Builtin::kI32: - return i32(); + return check_no_tmpl_args(i32()); case type::Builtin::kU32: - return u32(); + return check_no_tmpl_args(u32()); case type::Builtin::kF16: - return f16(); + return check_no_tmpl_args(f16()); case type::Builtin::kF32: - return b.create(); + return check_no_tmpl_args(b.create()); case type::Builtin::kMat2X2F: - return mat(f32(), 2u, 2u); + return check_no_tmpl_args(mat(f32(), 2u, 2u)); case type::Builtin::kMat2X3F: - return mat(f32(), 2u, 3u); + return check_no_tmpl_args(mat(f32(), 2u, 3u)); case type::Builtin::kMat2X4F: - return mat(f32(), 2u, 4u); + return check_no_tmpl_args(mat(f32(), 2u, 4u)); case type::Builtin::kMat3X2F: - return mat(f32(), 3u, 2u); + return check_no_tmpl_args(mat(f32(), 3u, 2u)); case type::Builtin::kMat3X3F: - return mat(f32(), 3u, 3u); + return check_no_tmpl_args(mat(f32(), 3u, 3u)); case type::Builtin::kMat3X4F: - return mat(f32(), 3u, 4u); + return check_no_tmpl_args(mat(f32(), 3u, 4u)); case type::Builtin::kMat4X2F: - return mat(f32(), 4u, 2u); + return check_no_tmpl_args(mat(f32(), 4u, 2u)); case type::Builtin::kMat4X3F: - return mat(f32(), 4u, 3u); + return check_no_tmpl_args(mat(f32(), 4u, 3u)); case type::Builtin::kMat4X4F: - return mat(f32(), 4u, 4u); + return check_no_tmpl_args(mat(f32(), 4u, 4u)); case type::Builtin::kMat2X2H: - return mat(f16(), 2u, 2u); + return check_no_tmpl_args(mat(f16(), 2u, 2u)); case type::Builtin::kMat2X3H: - return mat(f16(), 2u, 3u); + return check_no_tmpl_args(mat(f16(), 2u, 3u)); case type::Builtin::kMat2X4H: - return mat(f16(), 2u, 4u); + return check_no_tmpl_args(mat(f16(), 2u, 4u)); case type::Builtin::kMat3X2H: - return mat(f16(), 3u, 2u); + return check_no_tmpl_args(mat(f16(), 3u, 2u)); case type::Builtin::kMat3X3H: - return mat(f16(), 3u, 3u); + return check_no_tmpl_args(mat(f16(), 3u, 3u)); case type::Builtin::kMat3X4H: - return mat(f16(), 3u, 4u); + return check_no_tmpl_args(mat(f16(), 3u, 4u)); case type::Builtin::kMat4X2H: - return mat(f16(), 4u, 2u); + return check_no_tmpl_args(mat(f16(), 4u, 2u)); case type::Builtin::kMat4X3H: - return mat(f16(), 4u, 3u); + return check_no_tmpl_args(mat(f16(), 4u, 3u)); case type::Builtin::kMat4X4H: - return mat(f16(), 4u, 4u); + return check_no_tmpl_args(mat(f16(), 4u, 4u)); case type::Builtin::kVec2F: - return vec(f32(), 2u); + return check_no_tmpl_args(vec(f32(), 2u)); case type::Builtin::kVec3F: - return vec(f32(), 3u); + return check_no_tmpl_args(vec(f32(), 3u)); case type::Builtin::kVec4F: - return vec(f32(), 4u); + return check_no_tmpl_args(vec(f32(), 4u)); case type::Builtin::kVec2H: - return vec(f16(), 2u); + return check_no_tmpl_args(vec(f16(), 2u)); case type::Builtin::kVec3H: - return vec(f16(), 3u); + return check_no_tmpl_args(vec(f16(), 3u)); case type::Builtin::kVec4H: - return vec(f16(), 4u); + return check_no_tmpl_args(vec(f16(), 4u)); case type::Builtin::kVec2I: - return vec(i32(), 2u); + return check_no_tmpl_args(vec(i32(), 2u)); case type::Builtin::kVec3I: - return vec(i32(), 3u); + return check_no_tmpl_args(vec(i32(), 3u)); case type::Builtin::kVec4I: - return vec(i32(), 4u); + return check_no_tmpl_args(vec(i32(), 4u)); case type::Builtin::kVec2U: - return vec(u32(), 2u); + return check_no_tmpl_args(vec(u32(), 2u)); case type::Builtin::kVec3U: - return vec(u32(), 3u); + return check_no_tmpl_args(vec(u32(), 3u)); case type::Builtin::kVec4U: - return vec(u32(), 4u); + return check_no_tmpl_args(vec(u32(), 4u)); case type::Builtin::kSampler: - return builder_->create(type::SamplerKind::kSampler); + return check_no_tmpl_args(builder_->create(type::SamplerKind::kSampler)); case type::Builtin::kSamplerComparison: - return builder_->create(type::SamplerKind::kComparisonSampler); + return check_no_tmpl_args( + builder_->create(type::SamplerKind::kComparisonSampler)); case type::Builtin::kTextureDepth2D: - return builder_->create(type::TextureDimension::k2d); + return check_no_tmpl_args( + builder_->create(type::TextureDimension::k2d)); case type::Builtin::kTextureDepth2DArray: - return builder_->create(type::TextureDimension::k2dArray); + return check_no_tmpl_args( + builder_->create(type::TextureDimension::k2dArray)); case type::Builtin::kTextureDepthCube: - return builder_->create(type::TextureDimension::kCube); + return check_no_tmpl_args( + builder_->create(type::TextureDimension::kCube)); case type::Builtin::kTextureDepthCubeArray: - return builder_->create(type::TextureDimension::kCubeArray); + return check_no_tmpl_args( + builder_->create(type::TextureDimension::kCubeArray)); case type::Builtin::kTextureDepthMultisampled2D: - return builder_->create(type::TextureDimension::k2d); + return check_no_tmpl_args( + builder_->create(type::TextureDimension::k2d)); case type::Builtin::kTextureExternal: - return builder_->create(); + return check_no_tmpl_args(builder_->create()); + case type::Builtin::kTextureStorage1D: + return storage_texture(type::TextureDimension::k1d); + case type::Builtin::kTextureStorage2D: + return storage_texture(type::TextureDimension::k2d); + case type::Builtin::kTextureStorage2DArray: + return storage_texture(type::TextureDimension::k2dArray); + case type::Builtin::kTextureStorage3D: + return storage_texture(type::TextureDimension::k3d); case type::Builtin::kUndefined: break; } @@ -4021,19 +4074,43 @@ void Resolver::ErrorMismatchedResolvedIdentifier(const Source& source, AddError("cannot use " + resolved.String(builder_->Symbols(), diagnostics_) + " as " + std::string(wanted), source); + NoteDeclarationSource(resolved.Node()); +} +void Resolver::NoteDeclarationSource(const ast::Node* node) { Switch( - resolved.Node(), - [&](const ast::TypeDecl* n) { - AddNote("'" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", + node, + [&](const ast::Struct* n) { + AddNote("struct '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", n->source); }, - [&](const ast::Variable* n) { - AddNote("'" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", + [&](const ast::Alias* n) { + AddNote("alias '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", n->source); }, + [&](const ast::Var* n) { + AddNote("var '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", + n->source); + }, + [&](const ast::Let* n) { + AddNote("let '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", + n->source); + }, + [&](const ast::Override* n) { + AddNote("override '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", + n->source); + }, + [&](const ast::Const* n) { + AddNote("const '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", + n->source); + }, + [&](const ast::Parameter* n) { + AddNote( + "parameter '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", + n->source); + }, [&](const ast::Function* n) { - AddNote("'" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", + AddNote("function '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", n->source); }); } diff --git a/src/tint/resolver/resolver.h b/src/tint/resolver/resolver.h index 0d3c879d67..bc8821a576 100644 --- a/src/tint/resolver/resolver.h +++ b/src/tint/resolver/resolver.h @@ -432,6 +432,11 @@ class Resolver { const ResolvedIdentifier& resolved, std::string_view wanted); + /// If @p node is a module-scope type, variable or function declaration, then appends a note + /// diagnostic where this declaration was declared, otherwise the function does nothing. + /// @param node the AST node. + void NoteDeclarationSource(const ast::Node* node); + /// Adds the given error message to the diagnostics void AddError(const std::string& msg, const Source& source) const; @@ -443,7 +448,7 @@ class Resolver { /// @returns the type::Type for the builtin type @p builtin_ty with the identifier @p ident /// @note: Will raise an ICE if @p symbol is not a builtin type. - type::Type* BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident) const; + type::Type* BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident); // ArrayInitializerSig represents a unique array initializer signature. // It is a tuple of the array type, number of arguments provided and earliest evaluation stage. diff --git a/src/tint/resolver/sem_helper.cc b/src/tint/resolver/sem_helper.cc index bb769ab20d..e2887072a6 100644 --- a/src/tint/resolver/sem_helper.cc +++ b/src/tint/resolver/sem_helper.cc @@ -37,30 +37,40 @@ type::Type* SemHelper::TypeOf(const ast::Expression* expr) const { return sem ? const_cast(sem->Type()) : nullptr; } -void SemHelper::ErrorExpectedValueExpr(const sem::Expression* expr) const { +void SemHelper::ErrorUnexpectedExprKind(const sem::Expression* expr, + std::string_view wanted) const { Switch( expr, // + [&](const sem::VariableUser* var_expr) { + auto name = + builder_->Symbols().NameFor(var_expr->Variable()->Declaration()->name->symbol); + auto type = var_expr->Type()->FriendlyName(builder_->Symbols()); + AddError("cannot use '" + name + "' of type '" + type + "' as " + std::string(wanted), + var_expr->Declaration()->source); + }, + [&](const sem::ValueExpression* val_expr) { + auto type = val_expr->Type()->FriendlyName(builder_->Symbols()); + AddError("cannot use expression of type '" + type + "' as " + std::string(wanted), + val_expr->Declaration()->source); + }, [&](const sem::TypeExpression* ty_expr) { auto name = ty_expr->Type()->FriendlyName(builder_->Symbols()); - AddError("cannot use type '" + name + "' as value", ty_expr->Declaration()->source); - if (auto* ident = ty_expr->Declaration()->As()) { - AddNote("are you missing '()' for type initializer?", - Source{{ident->source.range.end}}); - } - if (auto* str = ty_expr->Type()->As()) { - AddNote("'" + name + "' declared here", str->Source()); - } + AddError("cannot use type '" + name + "' as " + std::string(wanted), + ty_expr->Declaration()->source); }, [&](const sem::BuiltinEnumExpression* access) { - AddError("cannot use access '" + utils::ToString(access->Value()) + "' as value", + AddError("cannot use access '" + utils::ToString(access->Value()) + "' as " + + std::string(wanted), access->Declaration()->source); }, [&](const sem::BuiltinEnumExpression* addr) { - AddError("cannot use address space '" + utils::ToString(addr->Value()) + "' as value", + AddError("cannot use address space '" + utils::ToString(addr->Value()) + "' as " + + std::string(wanted), addr->Declaration()->source); }, [&](const sem::BuiltinEnumExpression* fmt) { - AddError("cannot use texel format '" + utils::ToString(fmt->Value()) + "' as value", + AddError("cannot use texel format '" + utils::ToString(fmt->Value()) + "' as " + + std::string(wanted), fmt->Declaration()->source); }, [&](Default) { @@ -69,6 +79,20 @@ void SemHelper::ErrorExpectedValueExpr(const sem::Expression* expr) const { }); } +void SemHelper::ErrorExpectedValueExpr(const sem::Expression* expr) const { + ErrorUnexpectedExprKind(expr, "value"); + if (auto* ty_expr = expr->As()) { + if (auto* ident = ty_expr->Declaration()->As()) { + AddNote("are you missing '()' for type initializer?", + Source{{ident->source.range.end}}); + } + if (auto* str = ty_expr->Type()->As()) { + AddNote("struct '" + str->FriendlyName(builder_->Symbols()) + "' declared here", + str->Source()); + } + } +} + void SemHelper::AddError(const std::string& msg, const Source& source) const { builder_->Diagnostics().add_error(diag::System::Resolver, msg, source); } diff --git a/src/tint/resolver/sem_helper.h b/src/tint/resolver/sem_helper.h index 9c918cd990..db3eda4496 100644 --- a/src/tint/resolver/sem_helper.h +++ b/src/tint/resolver/sem_helper.h @@ -20,6 +20,7 @@ #include "src/tint/diagnostic/diagnostic.h" #include "src/tint/program_builder.h" #include "src/tint/resolver/dependency_graph.h" +#include "src/tint/sem/builtin_enum_expression.h" #include "src/tint/utils/map.h" namespace tint::resolver { @@ -61,25 +62,46 @@ class SemHelper { } /// @param expr the semantic node - /// @returns one of: - /// * nullptr if @p expr is nullptr - /// * @p expr if the static pointer type already derives from sem::ValueExpression - /// * @p expr cast to sem::ValueExpression if the cast is successful - /// * nullptr if @p expr is not a sem::ValueExpression. In this case an error diagnostic is - /// raised. - template - auto* AsValue(EXPR* expr) const { - if constexpr (traits::IsTypeOrDerived) { - return expr; - } else { - if (TINT_LIKELY(expr)) { - if (auto* val = expr->template As(); TINT_LIKELY(val)) { - return val; - } - ErrorExpectedValueExpr(expr); + /// @returns nullptr if @p expr is nullptr, or @p expr cast to sem::ValueExpression if the cast + /// is successful, otherwise an error diagnostic is raised. + sem::ValueExpression* AsValue(sem::Expression* expr) const { + if (TINT_LIKELY(expr)) { + if (auto* val = expr->As(); TINT_LIKELY(val)) { + return val; } - return static_cast(nullptr); + ErrorExpectedValueExpr(expr); } + return nullptr; + } + + /// @param expr the semantic node + /// @returns nullptr if @p expr is nullptr, or @p expr cast to + /// sem::BuiltinEnumExpression if the cast is successful, otherwise an error + /// diagnostic is raised. + sem::BuiltinEnumExpression* AsTexelFormat(sem::Expression* expr) const { + if (TINT_LIKELY(expr)) { + if (auto* val = expr->As>(); + TINT_LIKELY(val)) { + return val; + } + ErrorUnexpectedExprKind(expr, "texel format"); + } + return nullptr; + } + + /// @param expr the semantic node + /// @returns nullptr if @p expr is nullptr, or @p expr cast to + /// sem::BuiltinEnumExpression if the cast is successful, otherwise an error + /// diagnostic is raised. + sem::BuiltinEnumExpression* AsAccess(sem::Expression* expr) const { + if (TINT_LIKELY(expr)) { + if (auto* val = expr->As>(); + TINT_LIKELY(val)) { + return val; + } + ErrorUnexpectedExprKind(expr, "access"); + } + return nullptr; } /// @returns the resolved type of the ast::Expression @p expr @@ -100,6 +122,10 @@ class SemHelper { void ErrorExpectedValueExpr(const sem::Expression* expr) const; private: + /// Raises an error diagnostic that the expression @p got was not of the kind @p wanted. + /// @param expr the expression + void ErrorUnexpectedExprKind(const sem::Expression* expr, std::string_view wanted) const; + /// Adds the given error message to the diagnostics void AddError(const std::string& msg, const Source& source) const; diff --git a/src/tint/resolver/type_validation_test.cc b/src/tint/resolver/type_validation_test.cc index b28cecf541..70b3837553 100644 --- a/src/tint/resolver/type_validation_test.cc +++ b/src/tint/resolver/type_validation_test.cc @@ -1064,26 +1064,26 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest, namespace StorageTextureTests { struct DimensionParams { - type::TextureDimension dim; + const char* name; bool is_valid; }; static constexpr DimensionParams Dimension_cases[] = { - DimensionParams{type::TextureDimension::k1d, true}, - DimensionParams{type::TextureDimension::k2d, true}, - DimensionParams{type::TextureDimension::k2dArray, true}, - DimensionParams{type::TextureDimension::k3d, true}, - DimensionParams{type::TextureDimension::kCube, false}, - DimensionParams{type::TextureDimension::kCubeArray, false}}; + DimensionParams{"texture_storage_1d", true}, + DimensionParams{"texture_storage_2d", true}, + DimensionParams{"texture_storage_2d_array", true}, + DimensionParams{"texture_storage_3d", true}, + DimensionParams{"texture_storage_cube", false}, + DimensionParams{"texture_storage_cube_array", false}}; using StorageTextureDimensionTest = ResolverTestWithParam; TEST_P(StorageTextureDimensionTest, All) { // @group(0) @binding(0) - // var a : texture_storage_*; + // var a : texture_storage_*; auto& params = GetParam(); - auto* st = ty.storage_texture(Source{{12, 34}}, params.dim, type::TexelFormat::kR32Uint, - type::Access::kWrite); + auto* st = ty(Source{{12, 34}}, params.name, utils::ToString(type::TexelFormat::kR32Uint), + utils::ToString(type::Access::kWrite)); GlobalVar("a", st, Group(0_a), Binding(0_a)); @@ -1091,8 +1091,7 @@ TEST_P(StorageTextureDimensionTest, All) { EXPECT_TRUE(r()->Resolve()) << r()->error(); } else { EXPECT_FALSE(r()->Resolve()); - EXPECT_EQ(r()->error(), - "12:34 error: cube dimensions for storage textures are not supported"); + EXPECT_EQ(r()->error(), "12:34 error: unknown type: '" + std::string(params.name) + "'"); } } INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest, @@ -1165,22 +1164,33 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest, using StorageTextureAccessTest = ResolverTest; -TEST_F(StorageTextureAccessTest, MissingAccess_Fail) { +TEST_F(StorageTextureAccessTest, MissingTemplates) { // @group(0) @binding(0) - // var a : texture_storage_1d; + // var a : texture_storage_1d; - auto* st = ty.storage_texture(Source{{12, 34}}, type::TextureDimension::k1d, - type::TexelFormat::kR32Uint, type::Access::kUndefined); + auto* st = ty(Source{{12, 34}}, "texture_storage_1d"); GlobalVar("a", st, Group(0_a), Binding(0_a)); EXPECT_FALSE(r()->Resolve()); - EXPECT_EQ(r()->error(), "12:34 error: storage texture missing access control"); + EXPECT_EQ(r()->error(), "12:34 error: expected '<' for 'texture_storage_1d'"); +} + +TEST_F(StorageTextureAccessTest, MissingAccess_Fail) { + // @group(0) @binding(0) + // var a : texture_storage_1d; + + auto* st = ty(Source{{12, 34}}, "texture_storage_1d", "r32uint"); + + GlobalVar("a", st, Group(0_a), Binding(0_a)); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), R"(12:34 error: 'texture_storage_1d' requires 2 template arguments)"); } TEST_F(StorageTextureAccessTest, RWAccess_Fail) { // @group(0) @binding(0) - // var a : texture_storage_1d; + // var a : texture_storage_1d; auto* st = ty.storage_texture(Source{{12, 34}}, type::TextureDimension::k1d, type::TexelFormat::kR32Uint, type::Access::kReadWrite); @@ -1194,7 +1204,7 @@ TEST_F(StorageTextureAccessTest, RWAccess_Fail) { TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) { // @group(0) @binding(0) - // var a : texture_storage_1d; + // var a : texture_storage_1d; auto* st = ty.storage_texture(Source{{12, 34}}, type::TextureDimension::k1d, type::TexelFormat::kR32Uint, type::Access::kRead); @@ -1208,7 +1218,7 @@ TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) { TEST_F(StorageTextureAccessTest, WriteOnlyAccess_Pass) { // @group(0) @binding(0) - // var a : texture_storage_1d; + // var a : texture_storage_1d; auto* st = ty.storage_texture(type::TextureDimension::k1d, type::TexelFormat::kR32Uint, type::Access::kWrite); @@ -1445,5 +1455,91 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest, } // namespace BuiltinTypeAliasTests +namespace TypeDoesNotTakeTemplateArgs { + +using ResolverUntemplatedTypeUsedWithTemplateArgs = ResolverTestWithParam; + +TEST_P(ResolverUntemplatedTypeUsedWithTemplateArgs, Builtin_UseWithTemplateArgs) { + // enable f16; + // var v : f32; + + Enable(ast::Extension::kF16); + GlobalVar("v", type::AddressSpace::kPrivate, ty(Source{{12, 34}}, GetParam(), true)); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), "12:34 error: type '" + std::string(GetParam()) + + "' does not take template arguments"); +} + +TEST_P(ResolverUntemplatedTypeUsedWithTemplateArgs, BuiltinAlias_UseWithTemplateArgs) { + // enable f16; + // alias A = f32; + // var v : S; + + Enable(ast::Extension::kF16); + Alias(Source{{56, 78}}, "A", ty(GetParam())); + GlobalVar("v", type::AddressSpace::kPrivate, ty(Source{{12, 34}}, "A", true)); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + R"(12:34 error: type 'A' does not take template arguments +56:78 note: alias 'A' declared here)"); +} + +INSTANTIATE_TEST_SUITE_P(BuiltinTypes, + ResolverUntemplatedTypeUsedWithTemplateArgs, + testing::Values("bool", + "f16", + "f32", + "i32", + "u32", + "mat2x2f", + "mat2x2h", + "mat2x3f", + "mat2x3h", + "mat2x4f", + "mat2x4h", + "mat3x2f", + "mat3x2h", + "mat3x3f", + "mat3x3h", + "mat3x4f", + "mat3x4h", + "mat4x2f", + "mat4x2h", + "mat4x3f", + "mat4x3h", + "mat4x4f", + "mat4x4h", + "vec2f", + "vec2h", + "vec2i", + "vec2u", + "vec3f", + "vec3h", + "vec3i", + "vec3u", + "vec4f", + "vec4h", + "vec4i", + "vec4u")); + +TEST_F(ResolverUntemplatedTypeUsedWithTemplateArgs, Struct_UseWithTemplateArgs) { + // struct S { + // i: i32; + // }; + // var v : S; + + Structure(Source{{56, 78}}, "S", utils::Vector{Member("i", ty.i32())}); + GlobalVar("v", type::AddressSpace::kPrivate, ty(Source{{12, 34}}, "S", true)); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + R"(12:34 error: type 'S' does not take template arguments +56:78 note: struct 'S' declared here)"); +} + +} // namespace TypeDoesNotTakeTemplateArgs + } // namespace } // namespace tint::resolver diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc index 24a2bd7b87..71e39af01f 100644 --- a/src/tint/resolver/validator.cc +++ b/src/tint/resolver/validator.cc @@ -37,7 +37,6 @@ #include "src/tint/ast/pointer.h" #include "src/tint/ast/return_statement.h" #include "src/tint/ast/sampled_texture.h" -#include "src/tint/ast/storage_texture.h" #include "src/tint/ast/switch_statement.h" #include "src/tint/ast/traverse_expressions.h" #include "src/tint/ast/type_name.h" @@ -316,28 +315,28 @@ bool Validator::Pointer(const ast::Pointer* a, const type::Pointer* s) const { a->source); } -bool Validator::StorageTexture(const ast::StorageTexture* t) const { - switch (t->access) { +bool Validator::StorageTexture(const type::StorageTexture* t, const Source& source) const { + switch (t->access()) { case type::Access::kWrite: break; case type::Access::kUndefined: - AddError("storage texture missing access control", t->source); + AddError("storage texture missing access control", source); return false; default: - AddError("storage textures currently only support 'write' access control", t->source); + AddError("storage textures currently only support 'write' access control", source); return false; } - if (!IsValidStorageTextureDimension(t->dim)) { - AddError("cube dimensions for storage textures are not supported", t->source); + if (!IsValidStorageTextureDimension(t->dim())) { + AddError("cube dimensions for storage textures are not supported", source); return false; } - if (!IsValidStorageTextureTexelFormat(t->format)) { + if (!IsValidStorageTextureTexelFormat(t->texel_format())) { AddError( "image format must be one of the texel formats specified for storage " "textues in https://gpuweb.github.io/gpuweb/wgsl/#texel-formats", - t->source); + source); return false; } return true; diff --git a/src/tint/resolver/validator.h b/src/tint/resolver/validator.h index 55625d3ab5..9e11f5058b 100644 --- a/src/tint/resolver/validator.h +++ b/src/tint/resolver/validator.h @@ -372,8 +372,9 @@ class Validator { /// Validates a storage texture /// @param t the texture to validate + /// @param source the source of the texture /// @returns true on success, false otherwise - bool StorageTexture(const ast::StorageTexture* t) const; + bool StorageTexture(const type::StorageTexture* t, const Source& source) const; /// Validates a sampled texture /// @param t the texture to validate diff --git a/src/tint/transform/builtin_polyfill.cc b/src/tint/transform/builtin_polyfill.cc index 9924da359d..3d647a745f 100644 --- a/src/tint/transform/builtin_polyfill.cc +++ b/src/tint/transform/builtin_polyfill.cc @@ -22,6 +22,8 @@ #include "src/tint/program_builder.h" #include "src/tint/sem/builtin.h" #include "src/tint/sem/call.h" +#include "src/tint/sem/type_expression.h" +#include "src/tint/type/storage_texture.h" #include "src/tint/type/texture_dimension.h" #include "src/tint/utils/map.h" @@ -1065,13 +1067,17 @@ Transform::ApplyResult BuiltinPolyfill::Apply(const Program* src, break; } }, - [&](const ast::StorageTexture* tex) { - if (polyfill.bgra8unorm && tex->format == type::TexelFormat::kBgra8Unorm) { - ctx.Replace(tex, [&ctx, tex] { - return ctx.dst->ty.storage_texture(tex->dim, type::TexelFormat::kRgba8Unorm, - tex->access); - }); - made_changes = true; + [&](const ast::TypeName* type_name) { + if (polyfill.bgra8unorm) { + if (auto* tex = src->Sem().Get(type_name)) { + if (tex->texel_format() == type::TexelFormat::kBgra8Unorm) { + ctx.Replace(type_name, [&ctx, tex] { + return ctx.dst->ty.storage_texture( + tex->dim(), type::TexelFormat::kRgba8Unorm, tex->access()); + }); + made_changes = true; + } + } } }); } diff --git a/src/tint/transform/texture_1d_to_2d.cc b/src/tint/transform/texture_1d_to_2d.cc index 4561814350..84d480aae7 100644 --- a/src/tint/transform/texture_1d_to_2d.cc +++ b/src/tint/transform/texture_1d_to_2d.cc @@ -83,7 +83,8 @@ struct Texture1DTo2D::State { return SkipTransform; } - auto create_var = [&](const ast::Variable* v, ast::Type* type) -> const ast::Variable* { + auto create_var = [&](const ast::Variable* v, + const ast::Type* type) -> const ast::Variable* { if (v->As()) { return ctx.dst->Param(ctx.Clone(v->name->symbol), type, ctx.Clone(v->attributes)); } else { @@ -105,9 +106,9 @@ struct Texture1DTo2D::State { }, [&](const type::StorageTexture* storage_tex) -> const ast::Variable* { if (storage_tex->dim() == type::TextureDimension::k1d) { - auto* type = ctx.dst->create( - type::TextureDimension::k2d, storage_tex->texel_format(), - CreateASTTypeFor(ctx, storage_tex->type()), storage_tex->access()); + auto* type = ctx.dst->ty.storage_texture(type::TextureDimension::k2d, + storage_tex->texel_format(), + storage_tex->access()); return create_var(v, type); } else { return nullptr; diff --git a/src/tint/transform/transform.cc b/src/tint/transform/transform.cc index 1b5b345db4..a2ae23794b 100644 --- a/src/tint/transform/transform.cc +++ b/src/tint/transform/transform.cc @@ -163,8 +163,7 @@ const ast::Type* Transform::CreateASTTypeFor(CloneContext& ctx, const type::Type return ctx.dst->create(t->dim(), CreateASTTypeFor(ctx, t->type())); } if (auto* t = ty->As()) { - return ctx.dst->create(t->dim(), t->texel_format(), - CreateASTTypeFor(ctx, t->type()), t->access()); + return ctx.dst->ty.storage_texture(t->dim(), t->texel_format(), t->access()); } if (auto* s = ty->As()) { return ctx.dst->ty.sampler(s->kind()); diff --git a/src/tint/type/builtin.cc b/src/tint/type/builtin.cc index e8bf4675bb..b400ccbfb4 100644 --- a/src/tint/type/builtin.cc +++ b/src/tint/type/builtin.cc @@ -118,6 +118,18 @@ Builtin ParseBuiltin(std::string_view str) { if (str == "texture_external") { return Builtin::kTextureExternal; } + if (str == "texture_storage_1d") { + return Builtin::kTextureStorage1D; + } + if (str == "texture_storage_2d") { + return Builtin::kTextureStorage2D; + } + if (str == "texture_storage_2d_array") { + return Builtin::kTextureStorage2DArray; + } + if (str == "texture_storage_3d") { + return Builtin::kTextureStorage3D; + } if (str == "u32") { return Builtin::kU32; } @@ -224,6 +236,14 @@ std::ostream& operator<<(std::ostream& out, Builtin value) { return out << "texture_depth_multisampled_2d"; case Builtin::kTextureExternal: return out << "texture_external"; + case Builtin::kTextureStorage1D: + return out << "texture_storage_1d"; + case Builtin::kTextureStorage2D: + return out << "texture_storage_2d"; + case Builtin::kTextureStorage2DArray: + return out << "texture_storage_2d_array"; + case Builtin::kTextureStorage3D: + return out << "texture_storage_3d"; case Builtin::kU32: return out << "u32"; case Builtin::kVec2F: diff --git a/src/tint/type/builtin.h b/src/tint/type/builtin.h index 8b73461f33..3b57489ffe 100644 --- a/src/tint/type/builtin.h +++ b/src/tint/type/builtin.h @@ -60,6 +60,10 @@ enum class Builtin { kTextureDepthCubeArray, kTextureDepthMultisampled2D, kTextureExternal, + kTextureStorage1D, + kTextureStorage2D, + kTextureStorage2DArray, + kTextureStorage3D, kU32, kVec2F, kVec2H, @@ -116,6 +120,10 @@ constexpr const char* kBuiltinStrings[] = { "texture_depth_cube_array", "texture_depth_multisampled_2d", "texture_external", + "texture_storage_1d", + "texture_storage_2d", + "texture_storage_2d_array", + "texture_storage_3d", "u32", "vec2f", "vec2h", diff --git a/src/tint/type/builtin_bench.cc b/src/tint/type/builtin_bench.cc index 31fa29aa3f..aea57f59f9 100644 --- a/src/tint/type/builtin_bench.cc +++ b/src/tint/type/builtin_bench.cc @@ -241,97 +241,125 @@ void BuiltinParser(::benchmark::State& state) { "textuXe_ZZxtJJrnal", "textuPPe_eternal", "texturc_external", - "ull62", - "93yy", - "u3KK", + "tllxture_storage_P6d", + "tex99ure_yytorag_1d", + "textuKKe_storage_1d", + "texture_storage_1d", + "texture__xorage_d", + "yxKur_storage_1d", + "textureVstorkge_1z", + "texKure_Storqge_2d", + "texture_storage_d", + "teture_storage_VVd", + "texture_storage_2d", + "textureIstoraAUe_2d", + "jextre_storaR_2d", + "extue44storYYge_2", + "textre_storage_2d_array", + "tex9ur_stor11ge_d_xxrray", + "tmmxture_storJe_2d_arrcc", + "texture_storage_2d_array", + "tJJxture_storage_2_array", + "DDCCltufe_storaUe_2d_array", + "tegture_storage_2d_array", + "exture_srageCC3d", + "txture_storage_3d", + "textuIe_sto__age_3d", + "texture_storage_3d", + "texttte_PPorage_3d", + "texture_stora3de_3d", + "exture_Ktoragyy_3d", + "", + "03nn", + "uCnuu", "u32", - "x_", - "K", - "kVz", - "veKSf", - "vc2f", - "ec2VV", - "vec2f", - "IAAc2f", - "jbR", - "veY4", - "ec2h", - "vc911", - "mmcch", - "vec2h", - "vJJch", - "lDDcUfC", - "vec2g", - "CCe", - "ec2i", - "vIc__i", - "vec2i", - "ePPtt", - "v3dc2i", - "vcyyi", - "u2", - "v03nnu", - "Cuuecnv", - "vec2u", - "vX2ll", - "vocppu", - "vwwc2", + "3Xl", + "pp3o", + "uww", "veuug", "vaac", "TRZcccf", - "vec3f", - "vTc3O8", - "vem03f", - "meBB3f", - "Mpp3", - "OOe3h", - "veG3G", - "vec3h", - "11eHH3h", + "vec2f", + "vTc2O8", + "vem02f", + "meBB2f", + "Mpp2", + "OOe2h", + "veG2G", + "vec2h", + "11eHH2h", "veFFe6", - "ve3", - "vKii3l", - "ec3i", - "v993IIv", - "vec3i", + "ve2", + "vKii2l", + "ec2i", + "v992IIv", + "vec2i", "veci", "vechi", "vczllPi", "u", - "vffqq3", - "vJdd3u", - "vec3u", + "vffqq2", + "vJdd2u", + "vec2u", "vecXX", - "ve32", - "Nyyc3u", - "vO4", + "ve22", + "Nyyc2u", + "vO3", "PEruZ", "vlc2edd", - "vec4f", + "vec3f", "ec9f", "ve1II", - "veb4f", + "veb3f", "vi7", - "oec4ii", - "ec4", - "vec4h", + "oec3ii", + "ec3", + "vec3h", "veci", "22ec", - "vGc4C", - "ffec48", - "c4i", + "vGc3C", + "ffec38", + "c3i", "JJecSSi", - "vec4i", - "94i", - "vbbJJ4TT", + "vec3i", + "93i", + "vbbJJ3TT", "e66i", - "u664u", - "vW4u", - "v4u", - "vec4u", + "u663u", + "vW3u", + "v3u", + "vec3u", "vecu", - "rec4u", - "2ec4B", + "rec3u", + "2ec3B", + "vcBBf", + "vRc4f", + "v4LL0", + "vec4f", + "vKOOf", + "vgwcf", + "vLphf", + "eiiEh", + "ec4h", + "UU884", + "vec4h", + "rrecvvh", + "ecmm", + "vec4j", + "vec4X", + "vec48", + "vecvEE", + "vec4i", + "z99ci", + "GGeJJA4i", + "vess4i", + "vPcKu", + "tpc4u", + "vec", + "vec4u", + "MMec4u", + "vJJc40", + "8c", }; for (auto _ : state) { for (auto* str : kStrings) { diff --git a/src/tint/type/builtin_test.cc b/src/tint/type/builtin_test.cc index 97f3164fb0..ebd2cea5d8 100644 --- a/src/tint/type/builtin_test.cc +++ b/src/tint/type/builtin_test.cc @@ -73,6 +73,10 @@ static constexpr Case kValidCases[] = { {"texture_depth_cube_array", Builtin::kTextureDepthCubeArray}, {"texture_depth_multisampled_2d", Builtin::kTextureDepthMultisampled2D}, {"texture_external", Builtin::kTextureExternal}, + {"texture_storage_1d", Builtin::kTextureStorage1D}, + {"texture_storage_2d", Builtin::kTextureStorage2D}, + {"texture_storage_2d_array", Builtin::kTextureStorage2DArray}, + {"texture_storage_3d", Builtin::kTextureStorage3D}, {"u32", Builtin::kU32}, {"vec2f", Builtin::kVec2F}, {"vec2h", Builtin::kVec2H}, @@ -179,45 +183,57 @@ static constexpr Case kInvalidCases[] = { {"texture_exernss77", Builtin::kUndefined}, {"texture_bbxternRRl", Builtin::kUndefined}, {"textureXXexternal", Builtin::kUndefined}, - {"qOOO2", Builtin::kUndefined}, - {"us", Builtin::kUndefined}, - {"u3X", Builtin::kUndefined}, - {"ve2f", Builtin::kUndefined}, - {"qq2", Builtin::kUndefined}, - {"vec222", Builtin::kUndefined}, - {"vezzXy", Builtin::kUndefined}, - {"ieVVP", Builtin::kUndefined}, - {"venCh", Builtin::kUndefined}, - {"vHc2Aq", Builtin::kUndefined}, - {"ve2i", Builtin::kUndefined}, - {"vefK", Builtin::kUndefined}, - {"vgg2", Builtin::kUndefined}, - {"vecu", Builtin::kUndefined}, - {"4TNc2u", Builtin::kUndefined}, + {"CCextOOre_stoage_qOd", Builtin::kUndefined}, + {"txtsre_sturage_1L", Builtin::kUndefined}, + {"texture_stoXage_1d", Builtin::kUndefined}, + {"textue_storage_2d", Builtin::kUndefined}, + {"teuresOorageqq2d", Builtin::kUndefined}, + {"texture_sto22age_2d", Builtin::kUndefined}, + {"exture_syora0e_2d_Xzzrray", Builtin::kUndefined}, + {"texiVVr_storageP2d_array", Builtin::kUndefined}, + {"texturestorage_2nn_arCay", Builtin::kUndefined}, + {"texturHHstorAAe_qqd", Builtin::kUndefined}, + {"textur_storage_3d", Builtin::kUndefined}, + {"texure_sfKorage3d", Builtin::kUndefined}, + {"gg", Builtin::kUndefined}, + {"u3", Builtin::kUndefined}, + {"NT42", Builtin::kUndefined}, {"ppec7l", Builtin::kUndefined}, - {"zNe3f", Builtin::kUndefined}, - {"uXXb3f", Builtin::kUndefined}, - {"vec3", Builtin::kUndefined}, - {"883K", Builtin::kUndefined}, + {"zNe2f", Builtin::kUndefined}, + {"uXXb2f", Builtin::kUndefined}, + {"vec2", Builtin::kUndefined}, + {"882K", Builtin::kUndefined}, {"vq9h", Builtin::kUndefined}, - {"vec311", Builtin::kUndefined}, + {"vec211", Builtin::kUndefined}, {"22ciii", Builtin::kUndefined}, {"ec77i", Builtin::kUndefined}, - {"NN23u", Builtin::kUndefined}, - {"vVVc3u", Builtin::kUndefined}, - {"WW11w3u", Builtin::kUndefined}, + {"NN22u", Builtin::kUndefined}, + {"vVVc2u", Builtin::kUndefined}, + {"WW11w2u", Builtin::kUndefined}, {"vcwwf", Builtin::kUndefined}, - {"vDc4f", Builtin::kUndefined}, + {"vDc3f", Builtin::kUndefined}, {"vecK", Builtin::kUndefined}, - {"f11r4PP", Builtin::kUndefined}, - {"ve4h", Builtin::kUndefined}, - {"vec4YY", Builtin::kUndefined}, + {"f11r3PP", Builtin::kUndefined}, + {"ve3h", Builtin::kUndefined}, + {"vec3YY", Builtin::kUndefined}, {"vkktHH", Builtin::kUndefined}, - {"rrec4i", Builtin::kUndefined}, + {"rrec3i", Builtin::kUndefined}, {"vWWssi", Builtin::kUndefined}, {"veYu", Builtin::kUndefined}, - {"eq4f", Builtin::kUndefined}, - {"u22ec4u", Builtin::kUndefined}, + {"eq3f", Builtin::kUndefined}, + {"u22ec3u", Builtin::kUndefined}, + {"c4f", Builtin::kUndefined}, + {"vec4", Builtin::kUndefined}, + {"vYyc47E", Builtin::kUndefined}, + {"veMoh", Builtin::kUndefined}, + {"ve4MM", Builtin::kUndefined}, + {"55ec4h", Builtin::kUndefined}, + {"N4i", Builtin::kUndefined}, + {"ve33i", Builtin::kUndefined}, + {"3ec4i", Builtin::kUndefined}, + {"mecI", Builtin::kUndefined}, + {"vrnK4u", Builtin::kUndefined}, + {"v4", Builtin::kUndefined}, }; using BuiltinParseTest = testing::TestWithParam; diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc index d99ecde15a..19345d090b 100644 --- a/src/tint/writer/wgsl/generator_impl.cc +++ b/src/tint/writer/wgsl/generator_impl.cc @@ -32,7 +32,6 @@ #include "src/tint/ast/pointer.h" #include "src/tint/ast/sampled_texture.h" #include "src/tint/ast/stage_attribute.h" -#include "src/tint/ast/storage_texture.h" #include "src/tint/ast/stride_attribute.h" #include "src/tint/ast/struct_member_align_attribute.h" #include "src/tint/ast/struct_member_offset_attribute.h" @@ -290,7 +289,23 @@ bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression* } bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) { - out << program_->Symbols().NameFor(expr->identifier->symbol); + return EmitIdentifier(out, expr->identifier); +} + +bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::Identifier* ident) { + out << program_->Symbols().NameFor(ident->symbol); + if (auto* tmpl_ident = ident->As()) { + out << "<"; + TINT_DEFER(out << ">"); + for (auto* expr : tmpl_ident->arguments) { + if (expr != tmpl_ident->arguments.Front()) { + out << ", "; + } + if (!EmitExpression(out, expr)) { + return false; + } + } + } return true; } @@ -462,10 +477,6 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) { out << "multisampled_"; return true; }, - [&](const ast::StorageTexture*) { // - out << "storage_"; - return true; - }, [&](Default) { // diagnostics_.add_error(diag::System::Writer, "unknown texture type"); return false; @@ -516,18 +527,6 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) { out << ">"; return true; }, - [&](const ast::StorageTexture* storage) { // - out << "<"; - if (!EmitImageFormat(out, storage->format)) { - return false; - } - out << ", "; - if (!EmitAccess(out, storage->access)) { - return false; - } - out << ">"; - return true; - }, [&](Default) { // return true; }); @@ -543,10 +542,7 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) { } return true; }, - [&](const ast::TypeName* tn) { - out << program_->Symbols().NameFor(tn->name->symbol); - return true; - }, + [&](const ast::TypeName* tn) { return EmitIdentifier(out, tn->name); }, [&](Default) { diagnostics_.add_error(diag::System::Writer, "unknown type in EmitType: " + std::string(ty->TypeInfo().name)); diff --git a/src/tint/writer/wgsl/generator_impl.h b/src/tint/writer/wgsl/generator_impl.h index c6c74f7b14..cf5d270318 100644 --- a/src/tint/writer/wgsl/generator_impl.h +++ b/src/tint/writer/wgsl/generator_impl.h @@ -142,6 +142,11 @@ class GeneratorImpl : public TextGenerator { /// @param expr the identifier expression /// @returns true if the identifier was emitted bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr); + /// Handles generating an identifier + /// @param out the output of the expression stream + /// @param ident the identifier + /// @returns true if the identifier was emitted + bool EmitIdentifier(std::ostream& out, const ast::Identifier* ident); /// Handles an if statement /// @param stmt the statement to emit /// @returns true if the statement was successfully emitted