[metal-writer] Add basic type emission.

This CL adds the start of type emission for the Metal backend. A few
types like pointers and structs aren't complete yet.

Bug: tint:8
Change-Id: I648e9275ef1b9dc6fa63b6ab328fe018a5f620ea
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/23701
Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
dan sinclair 2020-06-23 17:48:53 +00:00
parent 2a59901483
commit 5dd37b2e6c
5 changed files with 310 additions and 1 deletions

View File

@ -884,7 +884,10 @@ source_set("tint_unittests_wgsl_writer_src") {
} }
source_set("tint_unittests_msl_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 += [ configs += [
":tint_common_config", ":tint_common_config",

View File

@ -494,6 +494,7 @@ endif()
if(${TINT_BUILD_MSL_WRITER}) if(${TINT_BUILD_MSL_WRITER})
list(APPEND TINT_TEST_SRCS list(APPEND TINT_TEST_SRCS
writer/msl/generator_impl_test.cc writer/msl/generator_impl_test.cc
writer/msl/generator_impl_type_test.cc
) )
endif() endif()

View File

@ -14,6 +14,18 @@
#include "src/writer/msl/generator_impl.h" #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 tint {
namespace writer { namespace writer {
namespace msl { namespace msl {
@ -26,6 +38,91 @@ bool GeneratorImpl::Generate(const ast::Module&) {
return true; 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 msl
} // namespace writer } // namespace writer
} // namespace tint } // namespace tint

View File

@ -36,6 +36,12 @@ class GeneratorImpl : public TextGenerator {
/// @param module the module to generate /// @param module the module to generate
/// @returns true on successful generation; false otherwise /// @returns true on successful generation; false otherwise
bool Generate(const ast::Module& module); 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 } // namespace msl

View File

@ -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<ast::StructMember>(
"a", &i32, ast::StructMemberDecorationList{}));
ast::StructMemberDecorationList b_deco;
b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
auto str = std::make_unique<ast::Struct>();
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<ast::StructMember>(
"a", &i32, ast::StructMemberDecorationList{}));
ast::StructMemberDecorationList b_deco;
b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
auto str = std::make_unique<ast::Struct>();
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