reader::spirv::Parser: register user names
Bug: tint:3
Change-Id: I4391aa733079d24fb19ff2cba9f612406e63a203
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/17580
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 39156b5..a64b78b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -317,6 +317,7 @@
reader/spirv/fail_stream_test.cc
reader/spirv/namer_test.cc
reader/spirv/parser_impl_import_test.cc
+ reader/spirv/parser_impl_user_name_test.cc
reader/spirv/parser_impl_test.cc
reader/spirv/parser_test.cc
reader/spirv/spirv_tools_helpers_test.cc
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index f30d048..6391c15 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -19,6 +19,8 @@
#include <utility>
#include "source/opt/build_module.h"
+#include "source/opt/instruction.h"
+#include "source/opt/module.h"
#include "spirv-tools/libspirv.hpp"
namespace tint {
@@ -35,6 +37,7 @@
: Reader(),
spv_binary_(spv_binary),
fail_stream_(&success_, &errors_),
+ namer_(fail_stream_),
tools_context_(kTargetEnv),
tools_(kTargetEnv) {
// Create a message consumer to propagate error messages from SPIRV-Tools
@@ -120,7 +123,7 @@
}
bool ParserImpl::ParseInternalModule() {
- return RegisterExtendedInstructionImports();
+ return RegisterExtendedInstructionImports() && RegisterUserNames();
// TODO(dneto): fill in the rest
}
@@ -146,6 +149,35 @@
return true;
}
+bool ParserImpl::RegisterUserNames() {
+ // Register names from OpName and OpMemberName
+ for (const auto& inst : module_->debugs2()) {
+ switch (inst.opcode()) {
+ case SpvOpName:
+ namer_.SuggestSanitizedName(inst.GetSingleWordInOperand(0),
+ inst.GetInOperand(1).AsString());
+ break;
+ case SpvOpMemberName:
+ namer_.SuggestSanitizedMemberName(inst.GetSingleWordInOperand(0),
+ inst.GetSingleWordInOperand(1),
+ inst.GetInOperand(2).AsString());
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Fill in struct member names, and disambiguate them.
+ for (const auto* type_inst : module_->GetTypes()) {
+ if (type_inst->opcode() == SpvOpTypeStruct) {
+ namer_.ResolveMemberNamesForStruct(type_inst->result_id(),
+ type_inst->NumInOperands());
+ }
+ }
+
+ return true;
+}
+
} // namespace spirv
} // namespace reader
} // namespace tint
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index 3c1b921..573292b 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -33,6 +33,7 @@
#include "src/ast/module.h"
#include "src/reader/reader.h"
#include "src/reader/spirv/fail_stream.h"
+#include "src/reader/spirv/namer.h"
namespace tint {
namespace reader {
@@ -80,6 +81,9 @@
return glsl_std_450_imports_;
}
+ /// @returns the namer object
+ Namer& namer() { return namer_; }
+
private:
/// Builds the internal representation of the SPIR-V module.
/// Assumes the module is somewhat well-formed. Normally you
@@ -99,6 +103,11 @@
/// Registers extended instruction imports. Only "GLSL.std.450" is supported.
bool RegisterExtendedInstructionImports();
+ /// Registers user names for SPIR-V objects, from OpName, and OpMemberName.
+ /// Also synthesizes struct field names. Ensures uniqueness for names for
+ /// SPIR-V IDs, and uniqueness of names of fields within any single struct.
+ bool RegisterUserNames();
+
// The SPIR-V binary we're parsing
std::vector<uint32_t> spv_binary_;
@@ -112,6 +121,9 @@
FailStream fail_stream_;
spvtools::MessageConsumer message_consumer_;
+ // An object used to store and generate names for SPIR-V objects.
+ Namer namer_;
+
// The internal representation of the SPIR-V module and its context.
spvtools::Context tools_context_;
spvtools::SpirvTools tools_;
diff --git a/src/reader/spirv/parser_impl_user_name_test.cc b/src/reader/spirv/parser_impl_user_name_test.cc
new file mode 100644
index 0000000..b20c021
--- /dev/null
+++ b/src/reader/spirv/parser_impl_user_name_test.cc
@@ -0,0 +1,92 @@
+// 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 <memory>
+#include <sstream>
+
+#include "gmock/gmock.h"
+#include "src/reader/spirv/parser_impl.h"
+#include "src/reader/spirv/spirv_tools_helpers_test.h"
+
+namespace tint {
+namespace reader {
+namespace spirv {
+namespace {
+
+using ::testing::Eq;
+
+using SpvParseUserNameTest = ::testing::Test;
+
+TEST_F(SpvParseUserNameTest, RespectOpName) {
+ ParserImpl p(test::Assemble(R"(
+ OpName %1 "the_void_type"
+ %1 = OpTypeVoid
+ )"));
+ EXPECT_TRUE(p.BuildAndParseInternalModule());
+ EXPECT_THAT(p.namer().GetName(1), Eq("the_void_type"));
+}
+
+TEST_F(SpvParseUserNameTest, DistinguishDuplicateSuggestion) {
+ ParserImpl p(test::Assemble(R"(
+ OpName %1 "vanilla"
+ OpName %2 "vanilla"
+ %1 = OpTypeVoid
+ %2 = OpTypeInt 32 0
+ )"));
+ EXPECT_TRUE(p.BuildAndParseInternalModule());
+ EXPECT_THAT(p.namer().GetName(1), Eq("vanilla"));
+ EXPECT_THAT(p.namer().GetName(2), Eq("vanilla_1"));
+}
+
+TEST_F(SpvParseUserNameTest, RespectOpMemberName) {
+ ParserImpl p(test::Assemble(R"(
+ OpMemberName %3 0 "strawberry"
+ OpMemberName %3 1 "vanilla"
+ OpMemberName %3 2 "chocolate"
+ %2 = OpTypeInt 32 0
+ %3 = OpTypeStruct %2 %2 %2
+ )"));
+ EXPECT_TRUE(p.BuildAndParseInternalModule());
+ EXPECT_THAT(p.namer().GetMemberName(3, 0), Eq("strawberry"));
+ EXPECT_THAT(p.namer().GetMemberName(3, 1), Eq("vanilla"));
+ EXPECT_THAT(p.namer().GetMemberName(3, 2), Eq("chocolate"));
+}
+
+TEST_F(SpvParseUserNameTest, SynthesizeMemberNames) {
+ ParserImpl p(test::Assemble(R"(
+ %2 = OpTypeInt 32 0
+ %3 = OpTypeStruct %2 %2 %2
+ )"));
+ EXPECT_TRUE(p.BuildAndParseInternalModule());
+ EXPECT_THAT(p.namer().GetMemberName(3, 0), Eq("field0"));
+ EXPECT_THAT(p.namer().GetMemberName(3, 1), Eq("field1"));
+ EXPECT_THAT(p.namer().GetMemberName(3, 2), Eq("field2"));
+}
+
+TEST_F(SpvParseUserNameTest, MemberNamesMixUserAndSynthesized) {
+ ParserImpl p(test::Assemble(R"(
+ OpMemberName %3 1 "vanilla"
+ %2 = OpTypeInt 32 0
+ %3 = OpTypeStruct %2 %2 %2
+ )"));
+ EXPECT_TRUE(p.BuildAndParseInternalModule());
+ EXPECT_THAT(p.namer().GetMemberName(3, 0), Eq("field0"));
+ EXPECT_THAT(p.namer().GetMemberName(3, 1), Eq("vanilla"));
+ EXPECT_THAT(p.namer().GetMemberName(3, 2), Eq("field2"));
+}
+
+} // namespace
+} // namespace spirv
+} // namespace reader
+} // namespace tint