diff --git a/BUILD.gn b/BUILD.gn index a8f0c6a3ed..e9439511c6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -884,7 +884,10 @@ source_set("tint_unittests_wgsl_writer_src") { } source_set("tint_unittests_msl_writer_src") { - sources = [ "src/writer/msl/generator_impl_test.cc" ] + sources = [ + "src/writer/msl/generator_impl_test.cc", + "src/writer/msl/generator_impl_type_test.cc", + ] configs += [ ":tint_common_config", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aca6b5a7d8..424a4c3e07 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -494,6 +494,7 @@ endif() if(${TINT_BUILD_MSL_WRITER}) list(APPEND TINT_TEST_SRCS writer/msl/generator_impl_test.cc + writer/msl/generator_impl_type_test.cc ) endif() diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc index eb8c8ba146..cb2a173e0c 100644 --- a/src/writer/msl/generator_impl.cc +++ b/src/writer/msl/generator_impl.cc @@ -14,6 +14,18 @@ #include "src/writer/msl/generator_impl.h" +#include "src/ast/type/alias_type.h" +#include "src/ast/type/array_type.h" +#include "src/ast/type/bool_type.h" +#include "src/ast/type/f32_type.h" +#include "src/ast/type/i32_type.h" +#include "src/ast/type/matrix_type.h" +#include "src/ast/type/pointer_type.h" +#include "src/ast/type/struct_type.h" +#include "src/ast/type/u32_type.h" +#include "src/ast/type/vector_type.h" +#include "src/ast/type/void_type.h" + namespace tint { namespace writer { namespace msl { @@ -26,6 +38,91 @@ bool GeneratorImpl::Generate(const ast::Module&) { return true; } +bool GeneratorImpl::EmitType(ast::type::Type* type, const std::string& name) { + if (type->IsAlias()) { + auto* alias = type->AsAlias(); + out_ << alias->name(); + } else if (type->IsArray()) { + auto* ary = type->AsArray(); + + if (!EmitType(ary->type(), "")) { + return false; + } + if (!name.empty()) { + out_ << " " << name; + } + out_ << "["; + if (ary->IsRuntimeArray()) { + out_ << "1"; + } else { + out_ << std::to_string(ary->size()); + } + + out_ << "]"; + } else if (type->IsBool()) { + out_ << "bool"; + } else if (type->IsF32()) { + out_ << "float"; + } else if (type->IsI32()) { + out_ << "int"; + } else if (type->IsMatrix()) { + auto* mat = type->AsMatrix(); + if (!EmitType(mat->type(), "")) { + return false; + } + out_ << mat->columns() << "x" << mat->rows(); + } else if (type->IsPointer()) { + auto* ptr = type->AsPointer(); + // TODO(dsinclair): Storage class? + if (!EmitType(ptr->type(), "")) { + return false; + } + out_ << "*"; + } else if (type->IsStruct()) { + auto* str = type->AsStruct()->impl(); + // TODO(dsinclair): Block decoration? + // if (str->decoration() != ast::StructDecoration::kNone) { + // } + out_ << "struct {" << std::endl; + + increment_indent(); + for (const auto& mem : str->members()) { + make_indent(); + // TODO(dsinclair): Member decorations? + // if (!mem->decorations().empty()) { + // } + + if (!EmitType(mem->type(), mem->name())) { + return false; + } + // Array member name will be output with the type + if (!mem->type()->IsArray()) { + out_ << mem->name(); + } + out_ << ";" << std::endl; + } + decrement_indent(); + make_indent(); + + out_ << "}"; + } else if (type->IsU32()) { + out_ << "uint"; + } else if (type->IsVector()) { + auto* vec = type->AsVector(); + if (!EmitType(vec->type(), "")) { + return false; + } + out_ << vec->size(); + } else if (type->IsVoid()) { + out_ << "void"; + } else { + error_ = "unknown type in EmitType"; + return false; + } + + return true; +} + } // namespace msl } // namespace writer } // namespace tint diff --git a/src/writer/msl/generator_impl.h b/src/writer/msl/generator_impl.h index e71c703623..befa305118 100644 --- a/src/writer/msl/generator_impl.h +++ b/src/writer/msl/generator_impl.h @@ -36,6 +36,12 @@ class GeneratorImpl : public TextGenerator { /// @param module the module to generate /// @returns true on successful generation; false otherwise bool Generate(const ast::Module& module); + + /// Handles generating type + /// @param type the type to generate + /// @param name the name of the variable, only used for array emission + /// @returns true if the type is emitted + bool EmitType(ast::type::Type* type, const std::string& name); }; } // namespace msl diff --git a/src/writer/msl/generator_impl_type_test.cc b/src/writer/msl/generator_impl_type_test.cc new file mode 100644 index 0000000000..786ebed849 --- /dev/null +++ b/src/writer/msl/generator_impl_type_test.cc @@ -0,0 +1,202 @@ +// 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 "gtest/gtest.h" +#include "src/ast/struct.h" +#include "src/ast/struct_decoration.h" +#include "src/ast/struct_member.h" +#include "src/ast/struct_member_decoration.h" +#include "src/ast/struct_member_offset_decoration.h" +#include "src/ast/type/array_type.h" +#include "src/ast/type/bool_type.h" +#include "src/ast/type/f32_type.h" +#include "src/ast/type/i32_type.h" +#include "src/ast/type/matrix_type.h" +#include "src/ast/type/pointer_type.h" +#include "src/ast/type/struct_type.h" +#include "src/ast/type/u32_type.h" +#include "src/ast/type/vector_type.h" +#include "src/ast/type/void_type.h" +#include "src/writer/msl/generator_impl.h" + +namespace tint { +namespace writer { +namespace msl { +namespace { + +using MslGeneratorImplTest = testing::Test; + +TEST_F(MslGeneratorImplTest, EmitType_Alias) { + ast::type::F32Type f32; + ast::type::AliasType alias("alias", &f32); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&alias, "")) << g.error(); + EXPECT_EQ(g.result(), "alias"); +} + +TEST_F(MslGeneratorImplTest, EmitType_Array) { + ast::type::BoolType b; + ast::type::ArrayType a(&b, 4); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&a, "ary")) << g.error(); + EXPECT_EQ(g.result(), "bool ary[4]"); +} + +TEST_F(MslGeneratorImplTest, EmitType_Array_WithoutName) { + ast::type::BoolType b; + ast::type::ArrayType a(&b, 4); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&a, "")) << g.error(); + EXPECT_EQ(g.result(), "bool[4]"); +} + +TEST_F(MslGeneratorImplTest, EmitType_RuntimeArray) { + ast::type::BoolType b; + ast::type::ArrayType a(&b); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&a, "ary")) << g.error(); + EXPECT_EQ(g.result(), "bool ary[1]"); +} + +TEST_F(MslGeneratorImplTest, EmitType_Bool) { + ast::type::BoolType b; + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&b, "")) << g.error(); + EXPECT_EQ(g.result(), "bool"); +} + +TEST_F(MslGeneratorImplTest, EmitType_F32) { + ast::type::F32Type f32; + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&f32, "")) << g.error(); + EXPECT_EQ(g.result(), "float"); +} + +TEST_F(MslGeneratorImplTest, EmitType_I32) { + ast::type::I32Type i32; + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&i32, "")) << g.error(); + EXPECT_EQ(g.result(), "int"); +} + +TEST_F(MslGeneratorImplTest, EmitType_Matrix) { + ast::type::F32Type f32; + ast::type::MatrixType m(&f32, 3, 2); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&m, "")) << g.error(); + EXPECT_EQ(g.result(), "float2x3"); +} + +// TODO(dsinclair): How to annotate as workgroup? +TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Pointer) { + ast::type::F32Type f32; + ast::type::PointerType p(&f32, ast::StorageClass::kWorkgroup); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&p, "")) << g.error(); + EXPECT_EQ(g.result(), "float*"); +} + +// TODO(dsinclair): How to translate offsets? +TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Struct) { + ast::type::I32Type i32; + ast::type::F32Type f32; + + ast::StructMemberList members; + members.push_back(std::make_unique( + "a", &i32, ast::StructMemberDecorationList{})); + + ast::StructMemberDecorationList b_deco; + b_deco.push_back(std::make_unique(4)); + members.push_back( + std::make_unique("b", &f32, std::move(b_deco))); + + auto str = std::make_unique(); + str->set_members(std::move(members)); + + ast::type::StructType s(std::move(str)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&s, "")) << g.error(); + EXPECT_EQ(g.result(), R"(struct { + int a; + float b; +})"); +} + +// TODO(dsinclair): How to translate [[block]] +TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Struct_WithDecoration) { + ast::type::I32Type i32; + ast::type::F32Type f32; + + ast::StructMemberList members; + members.push_back(std::make_unique( + "a", &i32, ast::StructMemberDecorationList{})); + + ast::StructMemberDecorationList b_deco; + b_deco.push_back(std::make_unique(4)); + members.push_back( + std::make_unique("b", &f32, std::move(b_deco))); + + auto str = std::make_unique(); + str->set_members(std::move(members)); + str->set_decoration(ast::StructDecoration::kBlock); + + ast::type::StructType s(std::move(str)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&s, "")) << g.error(); + EXPECT_EQ(g.result(), R"(struct { + int a; + float b; +})"); +} + +TEST_F(MslGeneratorImplTest, EmitType_U32) { + ast::type::U32Type u32; + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&u32, "")) << g.error(); + EXPECT_EQ(g.result(), "uint"); +} + +TEST_F(MslGeneratorImplTest, EmitType_Vector) { + ast::type::F32Type f32; + ast::type::VectorType v(&f32, 3); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&v, "")) << g.error(); + EXPECT_EQ(g.result(), "float3"); +} + +TEST_F(MslGeneratorImplTest, EmitType_Void) { + ast::type::VoidType v; + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&v, "")) << g.error(); + EXPECT_EQ(g.result(), "void"); +} + +} // namespace +} // namespace msl +} // namespace writer +} // namespace tint