Add reader::spirv::ParserImpl::ConvertType

For now, it only handles scalar types

Bug: tint:3
Change-Id: Ic20e18a4f80790e6cd10d4c06dd2abfd8f67a304
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/17700
Reviewed-by: dan sinclair <dsinclair@google.com>
This commit is contained in:
David Neto 2020-03-24 21:42:16 +00:00 committed by dan sinclair
parent 69b9c1b8e0
commit 71e1d81654
4 changed files with 229 additions and 0 deletions

View File

@ -319,6 +319,7 @@ if(${TINT_BUILD_SPV_READER})
reader/spirv/enum_converter_test.cc
reader/spirv/fail_stream_test.cc
reader/spirv/namer_test.cc
reader/spirv/parser_impl_convert_type_test.cc
reader/spirv/parser_impl_entry_point_test.cc
reader/spirv/parser_impl_import_test.cc
reader/spirv/parser_impl_user_name_test.cc

View File

@ -15,13 +15,22 @@
#include "src/reader/spirv/parser_impl.h"
#include <cstring>
#include <memory>
#include <string>
#include <utility>
#include "source/opt/build_module.h"
#include "source/opt/instruction.h"
#include "source/opt/module.h"
#include "source/opt/type_manager.h"
#include "spirv-tools/libspirv.hpp"
#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/type.h"
#include "src/ast/type/u32_type.h"
#include "src/ast/type/void_type.h"
#include "src/type_manager.h"
namespace tint {
namespace reader {
@ -92,6 +101,77 @@ ast::Module ParserImpl::module() {
return std::move(ast_module_);
}
const ast::type::Type* ParserImpl::ConvertType(uint32_t type_id) {
if (!success_) {
return nullptr;
}
if (type_mgr_ == nullptr) {
Fail() << "ConvertType called when the internal module has not been built.";
return nullptr;
}
auto where = id_to_type_.find(type_id);
if (where != id_to_type_.end()) {
return where->second;
}
auto* spirv_type = type_mgr_->GetType(type_id);
if (spirv_type == nullptr) {
Fail() << "ID is not a SPIR-V type: " << type_id;
return nullptr;
}
const ast::type::Type* result = nullptr;
TypeManager* tint_tm = TypeManager::Instance();
switch (spirv_type->kind()) {
case spvtools::opt::analysis::Type::kVoid:
result = tint_tm->Get(std::make_unique<ast::type::VoidType>());
break;
case spvtools::opt::analysis::Type::kBool:
result = tint_tm->Get(std::make_unique<ast::type::BoolType>());
break;
case spvtools::opt::analysis::Type::kInteger: {
const auto* int_ty = spirv_type->AsInteger();
if (int_ty->width() == 32) {
if (int_ty->IsSigned()) {
result = tint_tm->Get(std::make_unique<ast::type::I32Type>());
} else {
result = tint_tm->Get(std::make_unique<ast::type::U32Type>());
}
} else {
Fail() << "unhandled integer width: " << int_ty->width();
}
break;
}
case spvtools::opt::analysis::Type::kFloat: {
const auto* float_ty = spirv_type->AsFloat();
if (float_ty->width() == 32) {
result = tint_tm->Get(std::make_unique<ast::type::F32Type>());
} else {
Fail() << "unhandled float width: " << float_ty->width();
}
break;
}
default:
// The error diagnostic will be generated below because result is still
// nullptr.
break;
}
if (result == nullptr) {
if (success_) {
// Only emit a new diagnostic if we haven't already emitted a more
// specific one.
Fail() << "unknown SPIR-V type: " << type_id;
}
} else {
id_to_type_[type_id] = result;
}
return result;
}
bool ParserImpl::BuildInternalModule() {
tools_.SetMessageConsumer(message_consumer_);

View File

@ -31,6 +31,7 @@
#include "spirv-tools/libspirv.hpp"
#include "src/ast/import.h"
#include "src/ast/module.h"
#include "src/ast/type/type.h"
#include "src/reader/reader.h"
#include "src/reader/spirv/enum_converter.h"
#include "src/reader/spirv/fail_stream.h"
@ -82,6 +83,14 @@ class ParserImpl : Reader {
return glsl_std_450_imports_;
}
/// Converts a SPIR-V type to a Tint type.
/// On failure, logs an error and returns null.
/// This should only be called after the internal
/// representation of the module has been built.
/// @param type_id the SPIR-V ID of a type.
/// @returns a Tint type, or nullptr
const ast::type::Type* ConvertType(uint32_t type_id);
/// @returns the namer object
Namer& namer() { return namer_; }
@ -147,6 +156,9 @@ class ParserImpl : Reader {
// The set of IDs that are imports of the GLSL.std.450 extended instruction
// sets.
std::unordered_set<uint32_t> glsl_std_450_imports_;
// Maps a SPIR-V type ID to a Tint type.
std::unordered_map<uint32_t, const ast::type::Type*> id_to_type_;
};
} // namespace spirv

View File

@ -0,0 +1,136 @@
// 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/reader/spirv/parser_impl.h"
#include <cstdint>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "src/reader/spirv/spirv_tools_helpers_test.h"
namespace tint {
namespace reader {
namespace spirv {
namespace {
using ::testing::Eq;
using SpvParserTest_ConvertType = ::testing::Test;
TEST_F(SpvParserTest_ConvertType, PreservesExistingFailure) {
ParserImpl p(std::vector<uint32_t>{});
p.Fail() << "boing";
const auto* type = p.ConvertType(10);
EXPECT_EQ(type, nullptr);
EXPECT_THAT(p.error(), Eq("boing"));
}
TEST_F(SpvParserTest_ConvertType, NotAnId) {
ParserImpl p(test::Assemble("%1 = OpExtInstImport \"GLSL.std.450\""));
EXPECT_TRUE(p.BuildAndParseInternalModule()) << p.error();
const auto* type = p.ConvertType(10);
EXPECT_EQ(type, nullptr);
EXPECT_EQ(nullptr, type);
EXPECT_THAT(p.error(), Eq("ID is not a SPIR-V type: 10"));
}
TEST_F(SpvParserTest_ConvertType, IdExistsButIsNotAType) {
ParserImpl p(test::Assemble("%1 = OpExtInstImport \"GLSL.std.450\""));
EXPECT_TRUE(p.BuildAndParseInternalModule());
const auto* type = p.ConvertType(1);
EXPECT_EQ(nullptr, type);
EXPECT_THAT(p.error(), Eq("ID is not a SPIR-V type: 1"));
}
TEST_F(SpvParserTest_ConvertType, UnhandledType) {
// Pipes are an OpenCL type. Tint doesn't support them.
ParserImpl p(test::Assemble("%70 = OpTypePipe WriteOnly"));
EXPECT_TRUE(p.BuildAndParseInternalModule());
const auto* type = p.ConvertType(70);
EXPECT_EQ(nullptr, type);
EXPECT_THAT(p.error(), Eq("unknown SPIR-V type: 70"));
}
TEST_F(SpvParserTest_ConvertType, Void) {
ParserImpl p(test::Assemble("%1 = OpTypeVoid"));
EXPECT_TRUE(p.BuildAndParseInternalModule());
const auto* type = p.ConvertType(1);
EXPECT_TRUE(type->IsVoid());
EXPECT_TRUE(p.error().empty());
}
TEST_F(SpvParserTest_ConvertType, Bool) {
ParserImpl p(test::Assemble("%100 = OpTypeBool"));
EXPECT_TRUE(p.BuildAndParseInternalModule());
const auto* type = p.ConvertType(100);
EXPECT_TRUE(type->IsBool());
EXPECT_TRUE(p.error().empty());
}
TEST_F(SpvParserTest_ConvertType, I32) {
ParserImpl p(test::Assemble("%2 = OpTypeInt 32 1"));
EXPECT_TRUE(p.BuildAndParseInternalModule());
const auto* type = p.ConvertType(2);
EXPECT_TRUE(type->IsI32());
EXPECT_TRUE(p.error().empty());
}
TEST_F(SpvParserTest_ConvertType, U32) {
ParserImpl p(test::Assemble("%3 = OpTypeInt 32 0"));
EXPECT_TRUE(p.BuildAndParseInternalModule());
const auto* type = p.ConvertType(3);
EXPECT_TRUE(type->IsU32());
EXPECT_TRUE(p.error().empty());
}
TEST_F(SpvParserTest_ConvertType, F32) {
ParserImpl p(test::Assemble("%4 = OpTypeFloat 32"));
EXPECT_TRUE(p.BuildAndParseInternalModule());
const auto* type = p.ConvertType(4);
EXPECT_TRUE(type->IsF32());
EXPECT_TRUE(p.error().empty());
}
TEST_F(SpvParserTest_ConvertType, BadIntWidth) {
ParserImpl p(test::Assemble("%5 = OpTypeInt 17 1"));
EXPECT_TRUE(p.BuildAndParseInternalModule());
const auto* type = p.ConvertType(5);
EXPECT_EQ(type, nullptr);
EXPECT_THAT(p.error(), Eq("unhandled integer width: 17"));
}
TEST_F(SpvParserTest_ConvertType, BadFloatWidth) {
ParserImpl p(test::Assemble("%6 = OpTypeFloat 19"));
EXPECT_TRUE(p.BuildAndParseInternalModule());
const auto* type = p.ConvertType(6);
EXPECT_EQ(type, nullptr);
EXPECT_THAT(p.error(), Eq("unhandled float width: 19"));
}
} // namespace
} // namespace spirv
} // namespace reader
} // namespace tint