Move functions for building modules outside of the C++ interface.

This commit is contained in:
Lei Zhang 2016-09-09 14:45:18 -04:00
parent 869440ebd4
commit b54686d017
12 changed files with 151 additions and 75 deletions

View File

@ -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

View File

@ -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<ir::IrLoader*>(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<ir::IrLoader*>(builder)->AddInstruction(inst);
return SPV_SUCCESS;
};
} // annoymous namespace
std::unique_ptr<ir::Module> BuildModule(spv_target_env env,
MessageConsumer consumer,
const std::vector<uint32_t>& binary) {
auto context = spvContextCreate(env);
SetContextMessageConsumer(context, consumer);
auto module = MakeUnique<ir::Module>();
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<ir::Module> BuildModule(spv_target_env env,
MessageConsumer consumer,
const std::string& text) {
SpvTools t(env);
t.SetMessageConsumer(consumer);
std::vector<uint32_t> binary;
if (t.Assemble(text, &binary) != SPV_SUCCESS) return nullptr;
return BuildModule(env, consumer, binary);
}
} // namespace spvtools

44
source/opt/build_module.h Normal file
View File

@ -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 <memory>
#include <string>
#include <vector>
#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<ir::Module> BuildModule(spv_target_env env,
MessageConsumer consumer,
const std::vector<uint32_t>& 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<ir::Module> BuildModule(spv_target_env env,
MessageConsumer consumer,
const std::string& text);
} // namespace spvtools
#endif // SPIRV_TOOLS_OPT_BUILD_MODULE_H_

View File

@ -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<ir::IrLoader*>(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<ir::IrLoader*>(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<uint32_t>& binary,
return status;
}
std::unique_ptr<ir::Module> SpvTools::BuildModule(
const std::vector<uint32_t>& binary) {
spv_diagnostic diagnostic = nullptr;
auto module = MakeUnique<ir::Module>();
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<ir::Module> SpvTools::BuildModule(const std::string& text) {
std::vector<uint32_t> binary;
if (Assemble(text, &binary) != SPV_SUCCESS) return nullptr;
return BuildModule(binary);
}
} // namespace spvtools

View File

@ -15,12 +15,10 @@
#ifndef SPIRV_TOOLS_LIBSPIRV_HPP_
#define SPIRV_TOOLS_LIBSPIRV_HPP_
#include <memory>
#include <string>
#include <vector>
#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<ir::Module> BuildModule(const std::vector<uint32_t>& binary);
// Builds and returns a Module from the given SPIR-V assembly |text|.
std::unique_ptr<ir::Module> BuildModule(const std::string& text);
private:
// Context for the current invocation. Thread-safety of this class depends on
// the constness of this field.

View File

@ -15,6 +15,7 @@
#include <gtest/gtest.h>
#include "opt/libspirv.hpp"
#include "spirv/1.1/spirv.h"
namespace {

View File

@ -22,6 +22,7 @@
#include <gtest/gtest.h>
#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<std::string, bool> OptimizeAndDisassemble(
opt::Pass* pass, const std::string& original, bool skip_nop) {
std::unique_ptr<ir::Module> module = tools_.BuildModule(original);
std::unique_ptr<ir::Module> 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<ir::Module> module = tools_.BuildModule(original);
std::unique_ptr<ir::Module> module =
BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, original);
ASSERT_NE(nullptr, module);
manager_->Run(module.get());

View File

@ -18,6 +18,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#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<const char*> text = {tc.text};
std::unique_ptr<ir::Module> 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<const char*> text = {tc.before};
std::unique_ptr<ir::Module> 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<const char*> text = {tc.before};
std::unique_ptr<ir::Module> 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<ir::Module> 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<ir::Module> 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<ir::Module> 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<ir::Module> 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

View File

@ -15,6 +15,7 @@
#include <gtest/gtest.h>
#include <algorithm>
#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<ir::Module> module = t.BuildModule(text);
std::unique_ptr<ir::Module> module =
BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, text);
ASSERT_NE(nullptr, module) << "Failed to assemble\n" << text;
std::vector<uint32_t> binary;
@ -209,7 +211,8 @@ TEST(IrBuilder, OpUndefOutsideFunction) {
// clang-format on
SpvTools t(SPV_ENV_UNIVERSAL_1_1);
std::unique_ptr<ir::Module> module = t.BuildModule(text);
std::unique_ptr<ir::Module> module =
BuildModule(SPV_ENV_UNIVERSAL_1_1, IgnoreMessage, text);
ASSERT_NE(nullptr, module);
const auto opundef_count = std::count_if(

View File

@ -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<Module> BuildModule(std::string text) {
spvtools::SpvTools t(SPV_ENV_UNIVERSAL_1_1);
return t.BuildModule(text);
inline std::unique_ptr<Module> 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

View File

@ -15,8 +15,8 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#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<ir::Module> 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<ir::Module> 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<ir::Module> 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<ir::Module> 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());

View File

@ -17,8 +17,8 @@
#include <vector>
#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<ir::Module> module = SpvTools(target_env).BuildModule(source);
std::unique_ptr<ir::Module> module =
BuildModule(target_env, pass_manager.consumer(), source);
pass_manager.Run(module.get());
std::vector<uint32_t> target;