mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-26 01:31:06 +00:00
Add RemoveOpNameInstruction reduction pass (#2187)
Add a spirv-reduce pass which removes OpName and OpMemberName instructions. This is useful to enable other reduction passes, e.g. RemoveUnreferencedInstruction may not be able to remove an instruction creating an id whose only usage is an OpName for this id.
This commit is contained in:
parent
8fc8dfe4a5
commit
4aeadc0199
@ -19,6 +19,7 @@ set(SPIRV_TOOLS_REDUCE_SOURCES
|
||||
reduction_opportunity.h
|
||||
reduction_pass.h
|
||||
remove_instruction_reduction_opportunity.h
|
||||
remove_opname_instruction_reduction_pass.h
|
||||
remove_unreferenced_instruction_reduction_pass.h
|
||||
structured_loop_to_selection_reduction_opportunity.h
|
||||
structured_loop_to_selection_reduction_pass.h
|
||||
@ -31,6 +32,7 @@ set(SPIRV_TOOLS_REDUCE_SOURCES
|
||||
reduction_pass.cpp
|
||||
remove_instruction_reduction_opportunity.cpp
|
||||
remove_unreferenced_instruction_reduction_pass.cpp
|
||||
remove_opname_instruction_reduction_pass.cpp
|
||||
structured_loop_to_selection_reduction_opportunity.cpp
|
||||
structured_loop_to_selection_reduction_pass.cpp
|
||||
)
|
||||
|
44
source/reduce/remove_opname_instruction_reduction_pass.cpp
Normal file
44
source/reduce/remove_opname_instruction_reduction_pass.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2018 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 "remove_opname_instruction_reduction_pass.h"
|
||||
#include "remove_instruction_reduction_opportunity.h"
|
||||
#include "source/opcode.h"
|
||||
#include "source/opt/instruction.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
using namespace opt;
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
RemoveOpNameInstructionReductionPass::GetAvailableOpportunities(
|
||||
opt::IRContext* context) const {
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
||||
|
||||
for (auto& inst : context->module()->debugs2()) {
|
||||
if (inst.opcode() == SpvOpName || inst.opcode() == SpvOpMemberName) {
|
||||
result.push_back(
|
||||
MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string RemoveOpNameInstructionReductionPass::GetName() const {
|
||||
return "RemoveOpNameInstructionReductionPass";
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
50
source/reduce/remove_opname_instruction_reduction_pass.h
Normal file
50
source/reduce/remove_opname_instruction_reduction_pass.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2018 Google LLC
|
||||
//
|
||||
// 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 SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_PASS_H_
|
||||
#define SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_PASS_H_
|
||||
|
||||
#include "reduction_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// A reduction pass for removing OpName instructions. As well as making the
|
||||
// module smaller, removing an OpName instruction may create opportunities to
|
||||
// remove the instruction that create the id to which the OpName applies.
|
||||
class RemoveOpNameInstructionReductionPass : public ReductionPass {
|
||||
public:
|
||||
// Creates the reduction pass in the context of the given target environment
|
||||
// |target_env|
|
||||
explicit RemoveOpNameInstructionReductionPass(const spv_target_env target_env)
|
||||
: ReductionPass(target_env) {}
|
||||
|
||||
~RemoveOpNameInstructionReductionPass() override = default;
|
||||
|
||||
// The name of this pass.
|
||||
std::string GetName() const final;
|
||||
|
||||
protected:
|
||||
// Finds all opportunities for removing opName instructions in the
|
||||
// given module.
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||
opt::IRContext* context) const final;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_REMOVE_OpName_INSTRUCTION_REDUCTION_PASS_H_
|
@ -18,6 +18,7 @@ add_spvtools_unittest(TARGET reduce
|
||||
reduce_test_util.cpp
|
||||
reduce_test_util.h
|
||||
reducer_test.cpp
|
||||
remove_opname_instruction_reduction_pass_test.cpp
|
||||
remove_unreferenced_instruction_reduction_pass_test.cpp
|
||||
structured_loop_to_selection_reduction_pass_test.cpp
|
||||
LIBS SPIRV-Tools-reduce
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "source/reduce/operand_to_const_reduction_pass.h"
|
||||
#include "source/reduce/reducer.h"
|
||||
#include "source/reduce/remove_opname_instruction_reduction_pass.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
@ -27,7 +28,7 @@ void NopDiagnostic(spv_message_level_t /*level*/, const char* /*source*/,
|
||||
const spv_position_t& /*position*/,
|
||||
const char* /*message*/) {}
|
||||
|
||||
// This changes is its mind each time IsInteresting is invoked as to whether the
|
||||
// This changes its mind each time IsInteresting is invoked as to whether the
|
||||
// binary is interesting, until some limit is reached after which the binary is
|
||||
// always deemed interesting. This is useful to test that reduction passes
|
||||
// interleave in interesting ways for a while, and then always succeed after
|
||||
@ -238,6 +239,77 @@ TEST(ReducerTest, ExprToConstantAndRemoveUnreferenced) {
|
||||
CheckEqual(env, expected, binary_out);
|
||||
}
|
||||
|
||||
TEST(ReducerTest, RemoveOpnameAndRemoveUnreferenced) {
|
||||
const std::string original = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %2 "main"
|
||||
OpName %3 "a"
|
||||
OpName %4 "this-name-counts-as-usage-for-load-instruction"
|
||||
%5 = OpTypeVoid
|
||||
%6 = OpTypeFunction %5
|
||||
%7 = OpTypeFloat 32
|
||||
%8 = OpTypePointer Function %7
|
||||
%9 = OpConstant %7 1
|
||||
%2 = OpFunction %5 None %6
|
||||
%10 = OpLabel
|
||||
%3 = OpVariable %8 Function
|
||||
%4 = OpLoad %7 %3
|
||||
OpStore %3 %7
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string expected = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%5 = OpTypeVoid
|
||||
%6 = OpTypeFunction %5
|
||||
%7 = OpTypeFloat 32
|
||||
%8 = OpTypePointer Function %7
|
||||
%9 = OpConstant %7 1
|
||||
%2 = OpFunction %5 None %6
|
||||
%10 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
||||
Reducer reducer(env);
|
||||
// Make ping-pong interesting very quickly, as there are not much
|
||||
// opportunities.
|
||||
PingPongInteresting ping_pong_interesting(1);
|
||||
reducer.SetMessageConsumer(NopDiagnostic);
|
||||
reducer.SetInterestingnessFunction(
|
||||
[&](const std::vector<uint32_t>& binary, uint32_t) -> bool {
|
||||
return ping_pong_interesting.IsInteresting(binary);
|
||||
});
|
||||
reducer.AddReductionPass(
|
||||
MakeUnique<RemoveOpNameInstructionReductionPass>(env));
|
||||
reducer.AddReductionPass(
|
||||
MakeUnique<RemoveUnreferencedInstructionReductionPass>(env));
|
||||
|
||||
std::vector<uint32_t> binary_in;
|
||||
SpirvTools t(env);
|
||||
|
||||
ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption));
|
||||
std::vector<uint32_t> binary_out;
|
||||
spvtools::ReducerOptions reducer_options;
|
||||
reducer_options.set_step_limit(500);
|
||||
|
||||
reducer.Run(std::move(binary_in), &binary_out, reducer_options);
|
||||
|
||||
CheckEqual(env, expected, binary_out);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
216
test/reduce/remove_opname_instruction_reduction_pass_test.cpp
Normal file
216
test/reduce/remove_opname_instruction_reduction_pass_test.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
// Copyright (c) 2018 Google LLC
|
||||
//
|
||||
// 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 "reduce_test_util.h"
|
||||
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/reduce/reduction_opportunity.h"
|
||||
#include "source/reduce/remove_opname_instruction_reduction_pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
namespace {
|
||||
|
||||
TEST(RemoveOpnameInstructionReductionPassTest, NothingToRemove) {
|
||||
const std::string source = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, source, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<RemoveOpNameInstructionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(0, ops.size());
|
||||
}
|
||||
|
||||
TEST(RemoveOpnameInstructionReductionPassTest, RemoveSingleOpName) {
|
||||
const std::string prologue = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
)";
|
||||
|
||||
const std::string epilogue = R"(
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string original = prologue + R"(
|
||||
OpName %4 "main"
|
||||
)" + epilogue;
|
||||
|
||||
const std::string expected = prologue + epilogue;
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, original, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<RemoveOpNameInstructionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
|
||||
CheckEqual(env, expected, context.get());
|
||||
}
|
||||
|
||||
TEST(RemoveOpnameInstructionReductionPassTest, TryApplyRemovesAllOpName) {
|
||||
const std::string prologue = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
)";
|
||||
|
||||
const std::string epilogue = R"(
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%11 = OpVariable %7 Function
|
||||
%12 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %9
|
||||
OpStore %11 %9
|
||||
OpStore %12 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string original = prologue + R"(
|
||||
OpName %4 "main"
|
||||
OpName %8 "a"
|
||||
OpName %10 "b"
|
||||
OpName %11 "c"
|
||||
OpName %12 "d"
|
||||
)" + epilogue;
|
||||
|
||||
const std::string expected = prologue + epilogue;
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
auto pass = TestSubclass<RemoveOpNameInstructionReductionPass>(env);
|
||||
|
||||
{
|
||||
// Check the right number of opportunities is detected
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, original, kReduceAssembleOption);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(5, ops.size());
|
||||
}
|
||||
|
||||
{
|
||||
// The reduction should remove all OpName
|
||||
std::vector<uint32_t> binary;
|
||||
SpirvTools t(env);
|
||||
ASSERT_TRUE(t.Assemble(original, &binary, kReduceAssembleOption));
|
||||
auto reduced_binary = pass.TryApplyReduction(binary);
|
||||
CheckEqual(env, expected, reduced_binary);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RemoveOpnameInstructionReductionPassTest,
|
||||
TryApplyRemovesAllOpNameAndOpMemberName) {
|
||||
const std::string prologue = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
)";
|
||||
|
||||
const std::string epilogue = R"(
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypeInt 32 1
|
||||
%8 = OpTypeVector %6 3
|
||||
%9 = OpTypeStruct %6 %7 %8
|
||||
%10 = OpTypePointer Function %9
|
||||
%12 = OpConstant %7 0
|
||||
%13 = OpConstant %6 1
|
||||
%14 = OpTypePointer Function %6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%11 = OpVariable %10 Function
|
||||
%15 = OpAccessChain %14 %11 %12
|
||||
OpStore %15 %13
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string original = prologue + R"(
|
||||
OpName %4 "main"
|
||||
OpName %9 "S"
|
||||
OpMemberName %9 0 "f"
|
||||
OpMemberName %9 1 "i"
|
||||
OpMemberName %9 2 "v"
|
||||
OpName %11 "s"
|
||||
)" + epilogue;
|
||||
|
||||
const std::string expected = prologue + epilogue;
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
auto pass = TestSubclass<RemoveOpNameInstructionReductionPass>(env);
|
||||
|
||||
{
|
||||
// Check the right number of opportunities is detected
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, original, kReduceAssembleOption);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(6, ops.size());
|
||||
}
|
||||
|
||||
{
|
||||
// The reduction should remove all OpName
|
||||
std::vector<uint32_t> binary;
|
||||
SpirvTools t(env);
|
||||
ASSERT_TRUE(t.Assemble(original, &binary, kReduceAssembleOption));
|
||||
auto reduced_binary = pass.TryApplyReduction(binary);
|
||||
CheckEqual(env, expected, reduced_binary);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
@ -23,6 +23,7 @@
|
||||
#include "source/reduce/operand_to_const_reduction_pass.h"
|
||||
#include "source/reduce/operand_to_dominating_id_reduction_pass.h"
|
||||
#include "source/reduce/reducer.h"
|
||||
#include "source/reduce/remove_opname_instruction_reduction_pass.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h"
|
||||
#include "source/reduce/structured_loop_to_selection_reduction_pass.h"
|
||||
#include "source/spirv_reducer_options.h"
|
||||
@ -204,6 +205,8 @@ int main(int argc, const char** argv) {
|
||||
return ExecuteCommand(command);
|
||||
});
|
||||
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<RemoveOpNameInstructionReductionPass>(target_env));
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<OperandToConstReductionPass>(target_env));
|
||||
reducer.AddReductionPass(
|
||||
|
Loading…
Reference in New Issue
Block a user