[reader-spirv] Convert array, runtime array types
Bug: tint:3 Change-Id: If0d7d38cc777bce3d86dfd83669c1572331d4ed6 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/17800 Reviewed-by: dan sinclair <dsinclair@google.com>
This commit is contained in:
parent
a8cd18e9e7
commit
288674904d
|
@ -15,6 +15,7 @@
|
|||
#include "src/reader/spirv/parser_impl.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
@ -24,6 +25,7 @@
|
|||
#include "source/opt/module.h"
|
||||
#include "source/opt/type_manager.h"
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
#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"
|
||||
|
@ -46,6 +48,7 @@ const spv_target_env kTargetEnv = SPV_ENV_WEBGPU_0;
|
|||
|
||||
ParserImpl::ParserImpl(Context* ctx, const std::vector<uint32_t>& spv_binary)
|
||||
: Reader(ctx),
|
||||
ctx_(ctx),
|
||||
spv_binary_(spv_binary),
|
||||
fail_stream_(&success_, &errors_),
|
||||
namer_(fail_stream_),
|
||||
|
@ -180,6 +183,56 @@ ast::type::Type* ParserImpl::ConvertType(uint32_t type_id) {
|
|||
// In the error case, we'll already have emitted a diagnostic.
|
||||
break;
|
||||
}
|
||||
case spvtools::opt::analysis::Type::kRuntimeArray: {
|
||||
const auto* rtarr_ty = spirv_type->AsRuntimeArray();
|
||||
auto* ast_elem_ty =
|
||||
ConvertType(type_mgr_->GetId(rtarr_ty->element_type()));
|
||||
if (ast_elem_ty != nullptr) {
|
||||
result = ctx_.type_mgr->Get(
|
||||
std::make_unique<ast::type::ArrayType>(ast_elem_ty));
|
||||
}
|
||||
// In the error case, we'll already have emitted a diagnostic.
|
||||
break;
|
||||
}
|
||||
case spvtools::opt::analysis::Type::kArray: {
|
||||
const auto* arr_ty = spirv_type->AsArray();
|
||||
auto* ast_elem_ty = ConvertType(type_mgr_->GetId(arr_ty->element_type()));
|
||||
if (ast_elem_ty == nullptr) {
|
||||
// In the error case, we'll already have emitted a diagnostic.
|
||||
break;
|
||||
}
|
||||
const auto& length_info = arr_ty->length_info();
|
||||
if (length_info.words.empty()) {
|
||||
// The internal representation is invalid. The discriminant vector
|
||||
// is mal-formed.
|
||||
Fail() << "internal error: Array length info is invalid";
|
||||
return nullptr;
|
||||
}
|
||||
if (length_info.words[0] !=
|
||||
spvtools::opt::analysis::Array::LengthInfo::kConstant) {
|
||||
Fail() << "Array type " << type_id
|
||||
<< " length is a specialization constant";
|
||||
return nullptr;
|
||||
}
|
||||
const auto* constant =
|
||||
constant_mgr_->FindDeclaredConstant(length_info.id);
|
||||
if (constant == nullptr) {
|
||||
Fail() << "Array type " << type_id << " length ID " << length_info.id
|
||||
<< " does not name an OpConstant";
|
||||
return nullptr;
|
||||
}
|
||||
const uint64_t num_elem = constant->GetZeroExtendedValue();
|
||||
// For now, limit to only 32bits.
|
||||
if (num_elem > std::numeric_limits<uint32_t>::max()) {
|
||||
Fail() << "Array type " << type_id
|
||||
<< " has too many elements (more than can fit in 32 bits): "
|
||||
<< num_elem;
|
||||
return nullptr;
|
||||
}
|
||||
result = ctx_.type_mgr->Get(std::make_unique<ast::type::ArrayType>(
|
||||
ast_elem_ty, static_cast<uint32_t>(num_elem)));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// The error diagnostic will be generated below because result is still
|
||||
// nullptr.
|
||||
|
|
|
@ -122,6 +122,8 @@ class ParserImpl : Reader {
|
|||
/// Emit entry point AST nodes.
|
||||
bool EmitEntryPoints();
|
||||
|
||||
// The Tint context
|
||||
Context ctx_;
|
||||
// The SPIR-V binary we're parsing
|
||||
std::vector<uint32_t> spv_binary_;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "src/ast/type/array_type.h"
|
||||
#include "src/ast/type/matrix_type.h"
|
||||
#include "src/ast/type/vector_type.h"
|
||||
#include "src/reader/spirv/parser_impl.h"
|
||||
|
@ -324,6 +325,96 @@ TEST_F(SpvParserTest, ConvertType_MatrixOverF32) {
|
|||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, ConvertType_RuntimeArray) {
|
||||
auto p = parser(test::Assemble(R"(
|
||||
%uint = OpTypeInt 32 0
|
||||
%10 = OpTypeRuntimeArray %uint
|
||||
)"));
|
||||
EXPECT_TRUE(p->BuildAndParseInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_NE(type, nullptr);
|
||||
EXPECT_TRUE(type->IsArray());
|
||||
auto* arr_type = type->AsArray();
|
||||
EXPECT_TRUE(arr_type->IsRuntimeArray());
|
||||
ASSERT_NE(arr_type, nullptr);
|
||||
ASSERT_EQ(arr_type->size(), 0u);
|
||||
auto* elem_type = arr_type->type();
|
||||
ASSERT_NE(elem_type, nullptr);
|
||||
EXPECT_TRUE(elem_type->IsU32());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, ConvertType_Array) {
|
||||
auto p = parser(test::Assemble(R"(
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_42 = OpConstant %uint 42
|
||||
%10 = OpTypeArray %uint %uint_42
|
||||
)"));
|
||||
EXPECT_TRUE(p->BuildAndParseInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_NE(type, nullptr);
|
||||
EXPECT_TRUE(type->IsArray());
|
||||
auto* arr_type = type->AsArray();
|
||||
EXPECT_FALSE(arr_type->IsRuntimeArray());
|
||||
ASSERT_NE(arr_type, nullptr);
|
||||
ASSERT_EQ(arr_type->size(), 42u);
|
||||
auto* elem_type = arr_type->type();
|
||||
ASSERT_NE(elem_type, nullptr);
|
||||
EXPECT_TRUE(elem_type->IsU32());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, ConvertType_ArrayBadLengthIsSpecConstantValue) {
|
||||
auto p = parser(test::Assemble(R"(
|
||||
OpDecorate %uint_42 SpecId 12
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_42 = OpSpecConstant %uint 42
|
||||
%10 = OpTypeArray %uint %uint_42
|
||||
)"));
|
||||
EXPECT_TRUE(p->BuildAndParseInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_EQ(type, nullptr);
|
||||
EXPECT_THAT(p->error(),
|
||||
Eq("Array type 10 length is a specialization constant"));
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, ConvertType_ArrayBadLengthIsSpecConstantExpr) {
|
||||
auto p = parser(test::Assemble(R"(
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_42 = OpConstant %uint 42
|
||||
%sum = OpSpecConstantOp %uint IAdd %uint_42 %uint_42
|
||||
%10 = OpTypeArray %uint %sum
|
||||
)"));
|
||||
EXPECT_TRUE(p->BuildAndParseInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_EQ(type, nullptr);
|
||||
EXPECT_THAT(p->error(),
|
||||
Eq("Array type 10 length is a specialization constant"));
|
||||
}
|
||||
|
||||
// TODO(dneto): Maybe add a test where the length operand is not a constant.
|
||||
// E.g. it's the ID of a type. That won't validate, and the SPIRV-Tools
|
||||
// optimizer representation doesn't handle it and asserts out instead.
|
||||
|
||||
TEST_F(SpvParserTest, ConvertType_ArrayBadTooBig) {
|
||||
auto p = parser(test::Assemble(R"(
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%uint64_big = OpConstant %uint64 5000000000
|
||||
%10 = OpTypeArray %uint64 %uint64_big
|
||||
)"));
|
||||
EXPECT_TRUE(p->BuildAndParseInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_EQ(type, nullptr);
|
||||
// TODO(dneto): Right now it's rejected earlier in the flow because
|
||||
// we can't even utter the uint64 type.
|
||||
EXPECT_THAT(p->error(), Eq("unhandled integer width: 64"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spirv
|
||||
} // namespace reader
|
||||
|
|
|
@ -42,8 +42,8 @@ class SpvParserTest : public testing::Test {
|
|||
}
|
||||
|
||||
/// Retrieves the parser from the helper
|
||||
/// @param input the string to parse
|
||||
/// @returns the parser implementation
|
||||
/// @param input the SPIR-V binary to parse
|
||||
/// @returns a parser for the given binary
|
||||
ParserImpl* parser(const std::vector<uint32_t>& input) {
|
||||
impl_ = std::make_unique<ParserImpl>(&ctx_, input);
|
||||
return impl_.get();
|
||||
|
|
Loading…
Reference in New Issue