[spirv-reader] Get decorations

Bug: tint:3
Change-Id: Idfd49c5bfc8629c17f42f954d65c881865548b8a
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/18140
Reviewed-by: dan sinclair <dsinclair@google.com>
This commit is contained in:
David Neto 2020-03-30 21:09:59 +00:00
parent 8ae34868cf
commit 4da4c696e2
4 changed files with 205 additions and 0 deletions

View File

@ -324,6 +324,7 @@ if(${TINT_BUILD_SPV_READER})
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_get_decorations_test.cc
reader/spirv/parser_impl_import_test.cc
reader/spirv/parser_impl_user_name_test.cc
reader/spirv/parser_impl_test.cc

View File

@ -21,6 +21,7 @@
#include <utility>
#include "source/opt/build_module.h"
#include "source/opt/decoration_manager.h"
#include "source/opt/instruction.h"
#include "source/opt/module.h"
#include "source/opt/type_manager.h"
@ -252,6 +253,42 @@ ast::type::Type* ParserImpl::ConvertType(uint32_t type_id) {
return result;
}
DecorationList ParserImpl::GetDecorationsFor(uint32_t id) const {
DecorationList result;
const auto& decorations = deco_mgr_->GetDecorationsFor(id, true);
for (const auto* inst : decorations) {
if (inst->opcode() != SpvOpDecorate) {
continue;
}
// Example: OpDecorate %struct_id Block
// Example: OpDecorate %array_ty ArrayStride 16
std::vector<uint32_t> inst_as_words;
inst->ToBinaryWithoutAttachedDebugInsts(&inst_as_words);
Decoration d(inst_as_words.begin() + 2, inst_as_words.end());
result.push_back(d);
}
return result;
}
DecorationList ParserImpl::GetDecorationsForMember(
uint32_t id,
uint32_t member_index) const {
DecorationList result;
const auto& decorations = deco_mgr_->GetDecorationsFor(id, true);
for (const auto* inst : decorations) {
if ((inst->opcode() != SpvOpMemberDecorate) ||
(inst->GetSingleWordInOperand(1) != member_index)) {
continue;
}
// Example: OpMemberDecorate %struct_id 2 Offset 24
std::vector<uint32_t> inst_as_words;
inst->ToBinaryWithoutAttachedDebugInsts(&inst_as_words);
Decoration d(inst_as_words.begin() + 3, inst_as_words.end());
result.push_back(d);
}
return result;
}
bool ParserImpl::BuildInternalModule() {
tools_.SetMessageConsumer(message_consumer_);

View File

@ -41,6 +41,13 @@ namespace tint {
namespace reader {
namespace spirv {
/// The binary representation of a SPIR-V decoration enum followed by its
/// operands, if any.
/// Example: { SpvDecorationBlock }
/// Example: { SpvDecorationArrayStride, 16 }
using Decoration = std::vector<uint32_t>;
using DecorationList = std::vector<Decoration>;
/// Parser implementation for SPIR-V.
class ParserImpl : Reader {
public:
@ -95,6 +102,22 @@ class ParserImpl : Reader {
/// @returns the namer object
Namer& namer() { return namer_; }
/// Gets the list of decorations for a SPIR-V result ID. Returns an empty
/// vector if the ID is not a result ID, or if no decorations target that ID.
/// The internal representation must have already been built.
/// @param id SPIR-V ID
/// @returns the list of decorations on the given ID
DecorationList GetDecorationsFor(uint32_t id) const;
/// Gets the list of decorations for the member of a struct. Returns an empty
/// list if the |id| is not the ID of a struct, or if the member index is out
/// of range, or if the target member has no decorations.
/// The internal representation must have already been built.
/// @param id SPIR-V ID of a struct
/// @param member_index the member within the struct
/// @returns the list of decorations on the member
DecorationList GetDecorationsForMember(uint32_t id,
uint32_t member_index) const;
private:
/// Builds the internal representation of the SPIR-V module.
/// Assumes the module is somewhat well-formed. Normally you

View File

@ -0,0 +1,144 @@
// 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 "gmock/gmock.h"
#include "spirv/unified1/spirv.h"
#include "src/reader/spirv/parser_impl.h"
#include "src/reader/spirv/parser_impl_test_helper.h"
#include "src/reader/spirv/spirv_tools_helpers_test.h"
namespace tint {
namespace reader {
namespace spirv {
namespace {
using ::testing::Eq;
using ::testing::UnorderedElementsAre;
TEST_F(SpvParserTest, GetDecorationsFor_NotAnId) {
auto p = parser(test::Assemble(""));
EXPECT_TRUE(p->BuildAndParseInternalModule());
auto decorations = p->GetDecorationsFor(42);
EXPECT_TRUE(decorations.empty());
EXPECT_TRUE(p->error().empty());
}
TEST_F(SpvParserTest, GetDecorationsFor_NoDecorations) {
auto p = parser(test::Assemble("%1 = OpTypeVoid"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
auto decorations = p->GetDecorationsFor(1);
EXPECT_TRUE(decorations.empty());
EXPECT_TRUE(p->error().empty());
}
TEST_F(SpvParserTest, GetDecorationsFor_OneDecoration) {
auto p = parser(test::Assemble(R"(
OpDecorate %10 Block
%float = OpTypeFloat 32
%10 = OpTypeStruct %float
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
auto decorations = p->GetDecorationsFor(10);
EXPECT_THAT(decorations,
UnorderedElementsAre(Decoration{SpvDecorationBlock}));
EXPECT_TRUE(p->error().empty());
}
TEST_F(SpvParserTest, GetDecorationsFor_MultiDecoration) {
auto p = parser(test::Assemble(R"(
OpDecorate %5 RelaxedPrecision
OpDecorate %5 Location 7 ; Invalid case made up for test
%float = OpTypeFloat 32
%5 = OpConstant %float 3.14
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
auto decorations = p->GetDecorationsFor(5);
EXPECT_THAT(decorations,
UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision},
Decoration{SpvDecorationLocation, 7}));
EXPECT_TRUE(p->error().empty());
}
TEST_F(SpvParserTest, GetDecorationsForMember_NotAnId) {
auto p = parser(test::Assemble(""));
EXPECT_TRUE(p->BuildAndParseInternalModule());
auto decorations = p->GetDecorationsForMember(42, 9);
EXPECT_TRUE(decorations.empty());
EXPECT_TRUE(p->error().empty());
}
TEST_F(SpvParserTest, GetDecorationsForMember_NotAStruct) {
auto p = parser(test::Assemble("%1 = OpTypeVoid"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
auto decorations = p->GetDecorationsFor(1);
EXPECT_TRUE(decorations.empty());
EXPECT_TRUE(p->error().empty());
}
TEST_F(SpvParserTest, GetDecorationsForMember_MemberWithoutDecoration) {
auto p = parser(test::Assemble(R"(
%uint = OpTypeInt 32 0
%10 = OpTypeStruct %uint
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
auto decorations = p->GetDecorationsForMember(10, 0);
EXPECT_TRUE(decorations.empty());
EXPECT_TRUE(p->error().empty());
}
TEST_F(SpvParserTest, GetDecorationsForMember_OneDecoration) {
auto p = parser(test::Assemble(R"(
OpMemberDecorate %10 1 ArrayStride 12
%uint = OpTypeInt 32 0
%uint_2 = OpConstant %uint 2
%arr = OpTypeArray %uint %uint_2
%10 = OpTypeStruct %uint %arr
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
auto decorations = p->GetDecorationsForMember(10, 1);
EXPECT_THAT(decorations,
UnorderedElementsAre(Decoration{SpvDecorationArrayStride, 12}));
EXPECT_TRUE(p->error().empty());
}
TEST_F(SpvParserTest, GetDecorationsForMember_MultiDecoration) {
auto p = parser(test::Assemble(R"(
OpMemberDecorate %50 1 RelaxedPrecision
OpMemberDecorate %50 2 ArrayStride 16
OpMemberDecorate %50 2 MatrixStride 8
OpMemberDecorate %50 2 ColMajor
%float = OpTypeFloat 32
%vec = OpTypeVector %float 2
%mat = OpTypeMatrix %vec 2
%uint = OpTypeInt 32 0
%uint_2 = OpConstant %uint 2
%arr = OpTypeArray %mat %uint_2
%50 = OpTypeStruct %uint %float %arr
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_TRUE(p->GetDecorationsForMember(50, 0).empty());
EXPECT_THAT(p->GetDecorationsForMember(50, 1),
UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision}));
EXPECT_THAT(p->GetDecorationsForMember(50, 2),
UnorderedElementsAre(Decoration{SpvDecorationColMajor},
Decoration{SpvDecorationMatrixStride, 8},
Decoration{SpvDecorationArrayStride, 16}));
EXPECT_TRUE(p->error().empty());
}
} // namespace
} // namespace spirv
} // namespace reader
} // namespace tint