Skip to content

Commit

Permalink
Added --compact-ids to /tools/opt
Browse files Browse the repository at this point in the history
The pass remaps ids to a compact set which starts with %1 and
has no gaps.
  • Loading branch information
Andrey Tuganov authored and dneto0 committed Apr 20, 2017
1 parent b173d1c commit 1e309af
Show file tree
Hide file tree
Showing 13 changed files with 337 additions and 16 deletions.
4 changes: 4 additions & 0 deletions include/spirv-tools/optimizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@ Optimizer::PassToken CreateEliminateDeadConstantPass();
// points are not changed.
Optimizer::PassToken CreateInlinePass();

// Creates a compact ids pass.
// The pass remaps result ids to a compact and gapless range starting from %1.
Optimizer::PassToken CreateCompactIdsPass();

} // namespace spvtools

#endif // SPIRV_TOOLS_OPTIMIZER_HPP_
2 changes: 2 additions & 0 deletions source/opt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
add_library(SPIRV-Tools-opt
basic_block.h
build_module.h
compact_ids_pass.h
constants.h
def_use_manager.h
eliminate_dead_constant_pass.h
Expand All @@ -39,6 +40,7 @@ add_library(SPIRV-Tools-opt

basic_block.cpp
build_module.cpp
compact_ids_pass.cpp
def_use_manager.cpp
eliminate_dead_constant_pass.cpp
flatten_decoration_pass.cpp
Expand Down
5 changes: 3 additions & 2 deletions source/opt/build_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,12 @@ std::unique_ptr<ir::Module> BuildModule(spv_target_env env,

std::unique_ptr<ir::Module> BuildModule(spv_target_env env,
MessageConsumer consumer,
const std::string& text) {
const std::string& text,
uint32_t assemble_options) {
SpirvTools t(env);
t.SetMessageConsumer(consumer);
std::vector<uint32_t> binary;
if (!t.Assemble(text, &binary)) return nullptr;
if (!t.Assemble(text, &binary, assemble_options)) return nullptr;
return BuildModule(env, consumer, binary.data(), binary.size());
}

Expand Down
12 changes: 6 additions & 6 deletions source/opt/build_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ namespace spvtools {
// specifies number of words in |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 uint32_t* binary, size_t size);
std::unique_ptr<ir::Module> BuildModule(
spv_target_env env, MessageConsumer consumer, const uint32_t* binary,
size_t size);

// 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);
std::unique_ptr<ir::Module> BuildModule(
spv_target_env env, MessageConsumer consumer, const std::string& text,
uint32_t assemble_options = SpirvTools::kDefaultAssembleOption);

} // namespace spvtools

Expand Down
57 changes: 57 additions & 0 deletions source/opt/compact_ids_pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) 2017 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 "compact_ids_pass.h"

#include <cassert>
#include <unordered_map>

namespace spvtools {
namespace opt {

using ir::Instruction;
using ir::Operand;

Pass::Status CompactIdsPass::Process(ir::Module* module) {
bool modified = false;
std::unordered_map<uint32_t, uint32_t> result_id_mapping;

module->ForEachInst([&result_id_mapping, &modified] (Instruction* inst) {
auto operand = inst->begin();
while (operand != inst->end()) {
if (spvIsIdType(operand->type)) {
assert(operand->words.size() == 1);
uint32_t& id = operand->words[0];
auto it = result_id_mapping.find(id);
if (it == result_id_mapping.end()) {
const uint32_t new_id =
static_cast<uint32_t>(result_id_mapping.size()) + 1;
const auto insertion_result = result_id_mapping.emplace(id, new_id);
it = insertion_result.first;
assert(insertion_result.second);
}
if (id != it->second) {
modified = true;
id = it->second;
}
}
++operand;
}
}, true);

return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}

} // namespace opt
} // namespace spvtools
34 changes: 34 additions & 0 deletions source/opt/compact_ids_pass.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) 2017 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 LIBSPIRV_OPT_COMPACT_IDS_PASS_H_
#define LIBSPIRV_OPT_COMPACT_IDS_PASS_H_

#include "module.h"
#include "pass.h"

namespace spvtools {
namespace opt {

// See optimizer.hpp for documentation.
class CompactIdsPass : public Pass {
public:
const char* name() const override { return "compact-ids"; }
Status Process(ir::Module*) override;
};

} // namespace opt
} // namespace spvtools

#endif // LIBSPIRV_OPT_COMPACT_IDS_PASS_H_
5 changes: 5 additions & 0 deletions source/opt/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,9 @@ Optimizer::PassToken CreateInlinePass() {
return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::InlinePass>());
}

Optimizer::PassToken CreateCompactIdsPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::CompactIdsPass>());
}

} // namespace spvtools
1 change: 1 addition & 0 deletions source/opt/passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

// A single header to include all passes.

#include "compact_ids_pass.h"
#include "eliminate_dead_constant_pass.h"
#include "flatten_decoration_pass.h"
#include "fold_spec_constant_op_and_composite_pass.h"
Expand Down
5 changes: 5 additions & 0 deletions test/opt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ add_spvtools_unittest(TARGET pass_strip_debug_info
LIBS SPIRV-Tools-opt
)

add_spvtools_unittest(TARGET pass_compact_ids
SRCS compact_ids_test.cpp pass_utils.cpp
LIBS SPIRV-Tools-opt
)

add_spvtools_unittest(TARGET pass_flatten_decoration
SRCS flatten_decoration_test.cpp pass_utils.cpp
LIBS SPIRV-Tools-opt
Expand Down
90 changes: 90 additions & 0 deletions test/opt/compact_ids_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright (c) 2017 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 <gmock/gmock.h>

#include "pass_fixture.h"
#include "pass_utils.h"

namespace {

using namespace spvtools;

using CompactIdsTest = PassTest<::testing::Test>;

TEST_F(CompactIdsTest, PassOff) {
const std::string before =
R"(OpCapability Addresses
OpCapability Kernel
OpCapability GenericPointer
OpCapability Linkage
OpMemoryModel Physical32 OpenCL
%99 = OpTypeInt 32 0
%10 = OpTypeVector %99 2
%20 = OpConstant %99 2
%30 = OpTypeArray %99 %20
)";

const std::string after = before;

SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
SinglePassRunAndCheck<opt::NullPass>(before, after, false, false);
}

TEST_F(CompactIdsTest, PassOn) {
const std::string before =
R"(OpCapability Addresses
OpCapability Kernel
OpCapability GenericPointer
OpCapability Linkage
OpMemoryModel Physical32 OpenCL
OpEntryPoint Kernel %3 "simple_kernel"
%99 = OpTypeInt 32 0
%10 = OpTypeVector %99 2
%20 = OpConstant %99 2
%30 = OpTypeArray %99 %20
%40 = OpTypeVoid
%50 = OpTypeFunction %40
%3 = OpFunction %40 None %50
%70 = OpLabel
OpReturn
OpFunctionEnd
)";

const std::string after =
R"(OpCapability Addresses
OpCapability Kernel
OpCapability GenericPointer
OpCapability Linkage
OpMemoryModel Physical32 OpenCL
OpEntryPoint Kernel %1 "simple_kernel"
%2 = OpTypeInt 32 0
%3 = OpTypeVector %2 2
%4 = OpConstant %2 2
%5 = OpTypeArray %2 %4
%6 = OpTypeVoid
%7 = OpTypeFunction %6
%1 = OpFunction %6 None %7
%8 = OpLabel
OpReturn
OpFunctionEnd
)";

SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
SinglePassRunAndCheck<opt::CompactIdsPass>(before, after, false, false);
}

} // anonymous namespace
31 changes: 23 additions & 8 deletions test/opt/pass_fixture.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,17 @@ class PassTest : public TestT {
PassTest()
: consumer_(nullptr),
tools_(SPV_ENV_UNIVERSAL_1_1),
manager_(new opt::PassManager()) {}
manager_(new opt::PassManager()),
assemble_options_(SpirvTools::kDefaultAssembleOption),
disassemble_options_(SpirvTools::kDefaultDisassembleOption) {}

// Runs the given |pass| on the binary assembled from the |original|.
// Returns a tuple of the optimized binary and the boolean value returned
// from pass Process() function.
std::tuple<std::vector<uint32_t>, opt::Pass::Status> OptimizeToBinary(
opt::Pass* pass, const std::string& original, bool skip_nop) {
std::unique_ptr<ir::Module> module =
BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer_, original);
std::unique_ptr<ir::Module> module = BuildModule(
SPV_ENV_UNIVERSAL_1_1, consumer_, original, assemble_options_);
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
<< original << std::endl;
if (!module) {
Expand Down Expand Up @@ -88,7 +90,8 @@ class PassTest : public TestT {
std::tie(optimized_bin, status) = SinglePassRunToBinary<PassT>(
assembly, skip_nop, std::forward<Args>(args)...);
std::string optimized_asm;
EXPECT_TRUE(tools_.Disassemble(optimized_bin, &optimized_asm))
EXPECT_TRUE(tools_.Disassemble(optimized_bin, &optimized_asm,
disassemble_options_))
<< "Disassembling failed for shader:\n"
<< assembly << std::endl;
return std::make_tuple(optimized_asm, status);
Expand Down Expand Up @@ -125,7 +128,8 @@ class PassTest : public TestT {
spvContextDestroy(context);
}
std::string optimized_asm;
EXPECT_TRUE(tools_.Disassemble(optimized_bin, &optimized_asm))
EXPECT_TRUE(tools_.Disassemble(optimized_bin, &optimized_asm,
disassemble_options_))
<< "Disassembling failed for shader:\n"
<< original << std::endl;
EXPECT_EQ(expected, optimized_asm);
Expand Down Expand Up @@ -162,8 +166,8 @@ class PassTest : public TestT {
void RunAndCheck(const std::string& original, const std::string& expected) {
assert(manager_->NumPasses());

std::unique_ptr<ir::Module> module =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, original);
std::unique_ptr<ir::Module> module = BuildModule(
SPV_ENV_UNIVERSAL_1_1, nullptr, original, assemble_options_);
ASSERT_NE(nullptr, module);

manager_->Run(module.get());
Expand All @@ -172,14 +176,25 @@ class PassTest : public TestT {
module->ToBinary(&binary, /* skip_nop = */ false);

std::string optimized;
EXPECT_TRUE(tools_.Disassemble(binary, &optimized));
EXPECT_TRUE(tools_.Disassemble(binary, &optimized,
disassemble_options_));
EXPECT_EQ(expected, optimized);
}

void SetAssembleOptions(uint32_t assemble_options) {
assemble_options_ = assemble_options;
}

void SetDisassembleOptions(uint32_t disassemble_options) {
disassemble_options_ = disassemble_options;
}

private:
MessageConsumer consumer_; // Message consumer.
SpirvTools tools_; // An instance for calling SPIRV-Tools functionalities.
std::unique_ptr<opt::PassManager> manager_; // The pass manager.
uint32_t assemble_options_;
uint32_t disassemble_options_;
};

} // namespace spvtools
Expand Down
Loading

0 comments on commit 1e309af

Please sign in to comment.