From b54686d0170cc72b889e9bdc45f9c173f26e3467 Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Fri, 9 Sep 2016 14:45:18 -0400 Subject: [PATCH] Move functions for building modules outside of the C++ interface. --- source/opt/CMakeLists.txt | 2 + source/opt/build_module.cpp | 74 ++++++++++++++++++++++++++++++++++ source/opt/build_module.h | 44 ++++++++++++++++++++ source/opt/libspirv.cpp | 45 --------------------- source/opt/libspirv.hpp | 8 ---- test/cpp_interface.cpp | 1 + test/opt/pass_fixture.h | 7 +++- test/opt/test_def_use.cpp | 15 +++---- test/opt/test_ir_loader.cpp | 7 +++- test/opt/test_module.cpp | 8 ++-- test/opt/test_type_manager.cpp | 10 ++--- tools/opt/opt.cpp | 5 ++- 12 files changed, 151 insertions(+), 75 deletions(-) create mode 100644 source/opt/build_module.cpp create mode 100644 source/opt/build_module.h diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index 431f2d189..b9a586fc0 100644 --- a/source/opt/CMakeLists.txt +++ b/source/opt/CMakeLists.txt @@ -13,6 +13,7 @@ # limitations under the License. add_library(SPIRV-Tools-opt basic_block.h + build_module.h constants.h def_use_manager.h eliminate_dead_constant_pass.h @@ -35,6 +36,7 @@ add_library(SPIRV-Tools-opt type_manager.h unify_const_pass.h + build_module.cpp def_use_manager.cpp eliminate_dead_constant_pass.cpp function.cpp diff --git a/source/opt/build_module.cpp b/source/opt/build_module.cpp new file mode 100644 index 000000000..56862752f --- /dev/null +++ b/source/opt/build_module.cpp @@ -0,0 +1,74 @@ +// Copyright (c) 2016 Google Inc. +// +// 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 "build_module.h" + +#include "ir_loader.h" +#include "libspirv.hpp" +#include "make_unique.h" +#include "table.h" + +namespace spvtools { + +namespace { + +// Sets the module header for IrLoader. Meets the interface requirement of +// spvBinaryParse(). +spv_result_t SetSpvHeader(void* builder, spv_endianness_t, uint32_t magic, + uint32_t version, uint32_t generator, + uint32_t id_bound, uint32_t reserved) { + reinterpret_cast(builder)->SetModuleHeader( + magic, version, generator, id_bound, reserved); + return SPV_SUCCESS; +}; + +// Processes a parsed instruction for IrLoader. Meets the interface requirement +// of spvBinaryParse(). +spv_result_t SetSpvInst(void* builder, const spv_parsed_instruction_t* inst) { + reinterpret_cast(builder)->AddInstruction(inst); + return SPV_SUCCESS; +}; + +} // annoymous namespace + +std::unique_ptr BuildModule(spv_target_env env, + MessageConsumer consumer, + const std::vector& binary) { + auto context = spvContextCreate(env); + SetContextMessageConsumer(context, consumer); + + auto module = MakeUnique(); + ir::IrLoader loader(context->consumer, module.get()); + + spv_result_t status = + spvBinaryParse(context, &loader, binary.data(), binary.size(), + SetSpvHeader, SetSpvInst, nullptr); + loader.EndModule(); + + spvContextDestroy(context); + + return status == SPV_SUCCESS ? std::move(module) : nullptr; +} + +std::unique_ptr BuildModule(spv_target_env env, + MessageConsumer consumer, + const std::string& text) { + SpvTools t(env); + t.SetMessageConsumer(consumer); + std::vector binary; + if (t.Assemble(text, &binary) != SPV_SUCCESS) return nullptr; + return BuildModule(env, consumer, binary); +} + +} // namespace spvtools diff --git a/source/opt/build_module.h b/source/opt/build_module.h new file mode 100644 index 000000000..65d510721 --- /dev/null +++ b/source/opt/build_module.h @@ -0,0 +1,44 @@ +// Copyright (c) 2016 Google Inc. +// +// 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. + +#ifndef SPIRV_TOOLS_OPT_BUILD_MODULE_H_ +#define SPIRV_TOOLS_OPT_BUILD_MODULE_H_ + +#include +#include +#include + +#include "message.h" +#include "module.h" +#include "spirv-tools/libspirv.h" + +namespace spvtools { + +// Builds and returns an ir::Module from the given SPIR-V |binary|. The |binary| +// will be decoded according to the given target |env|. Returns nullptr if erors +// occur and sends the errors to |consumer|. +std::unique_ptr BuildModule(spv_target_env env, + MessageConsumer consumer, + const std::vector& binary); + +// Builds and returns an ir::Module from the given SPIR-V assembly |text|. +// The |text| will be encoded according to the given target |env|. Returns +// nullptr if erors occur and sends the errors to |consumer|. +std::unique_ptr BuildModule(spv_target_env env, + MessageConsumer consumer, + const std::string& text); + +} // namespace spvtools + +#endif // SPIRV_TOOLS_OPT_BUILD_MODULE_H_ diff --git a/source/opt/libspirv.cpp b/source/opt/libspirv.cpp index 47be681e4..2b7850b21 100644 --- a/source/opt/libspirv.cpp +++ b/source/opt/libspirv.cpp @@ -20,26 +20,6 @@ namespace spvtools { -namespace { - -// Sets the module header. Meets the interface requirement of spvBinaryParse(). -spv_result_t SetSpvHeader(void* builder, spv_endianness_t, uint32_t magic, - uint32_t version, uint32_t generator, - uint32_t id_bound, uint32_t reserved) { - reinterpret_cast(builder) - ->SetModuleHeader(magic, version, generator, id_bound, reserved); - return SPV_SUCCESS; -}; - -// Processes a parsed instruction. Meets the interface requirement of -// spvBinaryParse(). -spv_result_t SetSpvInst(void* builder, const spv_parsed_instruction_t* inst) { - reinterpret_cast(builder)->AddInstruction(inst); - return SPV_SUCCESS; -}; - -} // annoymous namespace - void SpvTools::SetMessageConsumer(MessageConsumer consumer) { SetContextMessageConsumer(context_, std::move(consumer)); } @@ -78,29 +58,4 @@ spv_result_t SpvTools::Disassemble(const std::vector& binary, return status; } -std::unique_ptr SpvTools::BuildModule( - const std::vector& binary) { - spv_diagnostic diagnostic = nullptr; - - auto module = MakeUnique(); - ir::IrLoader loader(context_->consumer, module.get()); - - spv_result_t status = - spvBinaryParse(context_, &loader, binary.data(), binary.size(), - SetSpvHeader, SetSpvInst, &diagnostic); - - spvDiagnosticDestroy(diagnostic); - - loader.EndModule(); - - if (status == SPV_SUCCESS) return module; - return nullptr; -} - -std::unique_ptr SpvTools::BuildModule(const std::string& text) { - std::vector binary; - if (Assemble(text, &binary) != SPV_SUCCESS) return nullptr; - return BuildModule(binary); -} - } // namespace spvtools diff --git a/source/opt/libspirv.hpp b/source/opt/libspirv.hpp index e645fcc6a..fed408a1b 100644 --- a/source/opt/libspirv.hpp +++ b/source/opt/libspirv.hpp @@ -15,12 +15,10 @@ #ifndef SPIRV_TOOLS_LIBSPIRV_HPP_ #define SPIRV_TOOLS_LIBSPIRV_HPP_ -#include #include #include #include "message.h" -#include "module.h" #include "spirv-tools/libspirv.h" namespace spvtools { @@ -53,12 +51,6 @@ class SpvTools { uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); - // Builds and returns a Module from the given SPIR-V |binary|. - std::unique_ptr BuildModule(const std::vector& binary); - - // Builds and returns a Module from the given SPIR-V assembly |text|. - std::unique_ptr BuildModule(const std::string& text); - private: // Context for the current invocation. Thread-safety of this class depends on // the constness of this field. diff --git a/test/cpp_interface.cpp b/test/cpp_interface.cpp index 9fc796bc6..104958d37 100644 --- a/test/cpp_interface.cpp +++ b/test/cpp_interface.cpp @@ -15,6 +15,7 @@ #include #include "opt/libspirv.hpp" +#include "spirv/1.1/spirv.h" namespace { diff --git a/test/opt/pass_fixture.h b/test/opt/pass_fixture.h index 436ed42af..df41ad507 100644 --- a/test/opt/pass_fixture.h +++ b/test/opt/pass_fixture.h @@ -22,6 +22,7 @@ #include +#include "opt/build_module.h" #include "opt/libspirv.hpp" #include "opt/make_unique.h" #include "opt/pass_manager.h" @@ -49,7 +50,8 @@ class PassTest : public TestT { // and the boolean value returned from pass Process() function. std::tuple OptimizeAndDisassemble( opt::Pass* pass, const std::string& original, bool skip_nop) { - std::unique_ptr module = tools_.BuildModule(original); + std::unique_ptr module = + BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer_, original); EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" << original << std::endl; if (!module) { @@ -110,7 +112,8 @@ class PassTest : public TestT { void RunAndCheck(const std::string& original, const std::string& expected) { assert(manager_->NumPasses()); - std::unique_ptr module = tools_.BuildModule(original); + std::unique_ptr module = + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, original); ASSERT_NE(nullptr, module); manager_->Run(module.get()); diff --git a/test/opt/test_def_use.cpp b/test/opt/test_def_use.cpp index 412bf6488..9d9089cc9 100644 --- a/test/opt/test_def_use.cpp +++ b/test/opt/test_def_use.cpp @@ -18,6 +18,7 @@ #include #include +#include "opt/build_module.h" #include "opt/def_use_manager.h" #include "opt/libspirv.hpp" #include "pass_utils.h" @@ -128,7 +129,7 @@ TEST_P(ParseDefUseTest, Case) { // Build module. const std::vector text = {tc.text}; std::unique_ptr module = - SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(JoinAllInsts(text)); + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, JoinAllInsts(text)); ASSERT_NE(nullptr, module); // Analyze def and use. @@ -509,7 +510,7 @@ TEST_P(ReplaceUseTest, Case) { // Build module. const std::vector text = {tc.before}; std::unique_ptr module = - SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(JoinAllInsts(text)); + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, JoinAllInsts(text)); ASSERT_NE(nullptr, module); // Analyze def and use. @@ -811,7 +812,7 @@ TEST_P(KillDefTest, Case) { // Build module. const std::vector text = {tc.before}; std::unique_ptr module = - SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(JoinAllInsts(text)); + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, JoinAllInsts(text)); ASSERT_NE(nullptr, module); // Analyze def and use. @@ -1061,7 +1062,7 @@ TEST(DefUseTest, OpSwitch) { " OpFunctionEnd"; std::unique_ptr module = - SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(original_text); + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, original_text); ASSERT_NE(nullptr, module); // Analyze def and use. @@ -1184,7 +1185,7 @@ TEST_P(AnalyzeInstDefUseTest, Case) { // Build module. std::unique_ptr module = - SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(tc.module_text); + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, tc.module_text); ASSERT_NE(nullptr, module); // Analyze the instructions. @@ -1307,7 +1308,7 @@ TEST_P(KillInstTest, Case) { // Build module. std::unique_ptr module = - SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(tc.before); + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, tc.before); ASSERT_NE(nullptr, module); // KillInst @@ -1415,7 +1416,7 @@ TEST_P(GetAnnotationsTest, Case) { // Build module. std::unique_ptr module = - SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(tc.code); + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, tc.code); ASSERT_NE(nullptr, module); // Get annotations diff --git a/test/opt/test_ir_loader.cpp b/test/opt/test_ir_loader.cpp index 03c441572..27860c7be 100644 --- a/test/opt/test_ir_loader.cpp +++ b/test/opt/test_ir_loader.cpp @@ -15,6 +15,7 @@ #include #include +#include "opt/build_module.h" #include "opt/libspirv.hpp" namespace { @@ -23,7 +24,8 @@ using namespace spvtools; void DoRoundTripCheck(const std::string& text) { SpvTools t(SPV_ENV_UNIVERSAL_1_1); - std::unique_ptr module = t.BuildModule(text); + std::unique_ptr module = + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, text); ASSERT_NE(nullptr, module) << "Failed to assemble\n" << text; std::vector binary; @@ -209,7 +211,8 @@ TEST(IrBuilder, OpUndefOutsideFunction) { // clang-format on SpvTools t(SPV_ENV_UNIVERSAL_1_1); - std::unique_ptr module = t.BuildModule(text); + std::unique_ptr module = + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, text); ASSERT_NE(nullptr, module); const auto opundef_count = std::count_if( diff --git a/test/opt/test_module.cpp b/test/opt/test_module.cpp index 0056c96a9..e76817b98 100644 --- a/test/opt/test_module.cpp +++ b/test/opt/test_module.cpp @@ -17,6 +17,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "opt/build_module.h" #include "opt/libspirv.hpp" #include "opt/module.h" @@ -42,9 +43,9 @@ TEST(ModuleTest, SetIdBound) { // Returns a module formed by assembling the given text, // then loading the result. -std::unique_ptr BuildModule(std::string text) { - spvtools::SpvTools t(SPV_ENV_UNIVERSAL_1_1); - return t.BuildModule(text); +inline std::unique_ptr BuildModule(std::string text) { + return spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, spvtools::IgnoreMessage, + text); } TEST(ModuleTest, ComputeIdBound) { @@ -69,4 +70,3 @@ TEST(ModuleTest, ComputeIdBound) { } } // anonymous namespace - diff --git a/test/opt/test_type_manager.cpp b/test/opt/test_type_manager.cpp index 1fb2776cd..b493d9871 100644 --- a/test/opt/test_type_manager.cpp +++ b/test/opt/test_type_manager.cpp @@ -15,8 +15,8 @@ #include #include +#include "opt/build_module.h" #include "opt/instruction.h" -#include "opt/libspirv.hpp" #include "opt/type_manager.h" namespace { @@ -89,7 +89,7 @@ TEST(TypeManager, TypeStrings) { }; std::unique_ptr module = - SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(text); + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, text); opt::analysis::TypeManager manager(IgnoreMessage, *module); EXPECT_EQ(type_id_strs.size(), manager.NumTypes()); @@ -119,7 +119,7 @@ TEST(Struct, DecorationOnStruct) { %struct7 = OpTypeStruct %f32 ; no decoration )"; std::unique_ptr module = - SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(text); + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, text); opt::analysis::TypeManager manager(IgnoreMessage, *module); ASSERT_EQ(7u, manager.NumTypes()); @@ -169,7 +169,7 @@ TEST(Struct, DecorationOnMember) { %struct10 = OpTypeStruct %u32 %f32 ; no member decoration )"; std::unique_ptr module = - SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(text); + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, text); opt::analysis::TypeManager manager(IgnoreMessage, *module); ASSERT_EQ(10u, manager.NumTypes()); @@ -207,7 +207,7 @@ TEST(Types, DecorationEmpty) { %struct5 = OpTypeStruct %f32 )"; std::unique_ptr module = - SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(text); + BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, text); opt::analysis::TypeManager manager(IgnoreMessage, *module); ASSERT_EQ(5u, manager.NumTypes()); diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index d5784e19a..d15b27c41 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -17,8 +17,8 @@ #include #include "message.h" +#include "source/opt/build_module.h" #include "source/opt/ir_loader.h" -#include "source/opt/libspirv.hpp" #include "source/opt/pass_manager.h" #include "tools/io.h" @@ -139,7 +139,8 @@ int main(int argc, char** argv) { spvDiagnosticDestroy(diagnostic); spvContextDestroy(context); - std::unique_ptr module = SpvTools(target_env).BuildModule(source); + std::unique_ptr module = + BuildModule(target_env, pass_manager.consumer(), source); pass_manager.Run(module.get()); std::vector target;