mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
* Fixes #2358. Added to the reducer the ability to remove a function that is not directly called. Factored out some code from the optimizer to help with this.
This commit is contained in:
parent
10a7def6c0
commit
34c5ac614c
@ -98,6 +98,7 @@ SPVTOOLS_OPT_SRC_FILES := \
|
||||
source/opt/dominator_tree.cpp \
|
||||
source/opt/eliminate_dead_constant_pass.cpp \
|
||||
source/opt/eliminate_dead_functions_pass.cpp \
|
||||
source/opt/eliminate_dead_functions_util.cpp \
|
||||
source/opt/feature_manager.cpp \
|
||||
source/opt/flatten_decoration_pass.cpp \
|
||||
source/opt/fold.cpp \
|
||||
|
2
BUILD.gn
2
BUILD.gn
@ -496,6 +496,8 @@ static_library("spvtools_opt") {
|
||||
"source/opt/eliminate_dead_constant_pass.h",
|
||||
"source/opt/eliminate_dead_functions_pass.cpp",
|
||||
"source/opt/eliminate_dead_functions_pass.h",
|
||||
"source/opt/eliminate_dead_functions_util.cpp",
|
||||
"source/opt/eliminate_dead_functions_util.h",
|
||||
"source/opt/feature_manager.cpp",
|
||||
"source/opt/feature_manager.h",
|
||||
"source/opt/flatten_decoration_pass.cpp",
|
||||
|
@ -37,6 +37,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
|
||||
dominator_tree.h
|
||||
eliminate_dead_constant_pass.h
|
||||
eliminate_dead_functions_pass.h
|
||||
eliminate_dead_functions_util.h
|
||||
feature_manager.h
|
||||
flatten_decoration_pass.h
|
||||
fold.h
|
||||
@ -131,6 +132,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
|
||||
dominator_tree.cpp
|
||||
eliminate_dead_constant_pass.cpp
|
||||
eliminate_dead_functions_pass.cpp
|
||||
eliminate_dead_functions_util.cpp
|
||||
feature_manager.cpp
|
||||
flatten_decoration_pass.cpp
|
||||
fold.cpp
|
||||
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/opt/eliminate_dead_functions_pass.h"
|
||||
#include "source/opt/eliminate_dead_functions_util.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
@ -36,8 +37,8 @@ Pass::Status EliminateDeadFunctionsPass::Process() {
|
||||
funcIter != get_module()->end();) {
|
||||
if (live_function_set.count(&*funcIter) == 0) {
|
||||
modified = true;
|
||||
EliminateFunction(&*funcIter);
|
||||
funcIter = funcIter.Erase();
|
||||
funcIter =
|
||||
eliminatedeadfunctionsutil::EliminateFunction(context(), &funcIter);
|
||||
} else {
|
||||
++funcIter;
|
||||
}
|
||||
@ -47,10 +48,5 @@ Pass::Status EliminateDeadFunctionsPass::Process() {
|
||||
: Pass::Status::SuccessWithoutChange;
|
||||
}
|
||||
|
||||
void EliminateDeadFunctionsPass::EliminateFunction(Function* func) {
|
||||
// Remove all of the instruction in the function body
|
||||
func->ForEachInst([this](Instruction* inst) { context()->KillInst(inst); },
|
||||
true);
|
||||
}
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
32
source/opt/eliminate_dead_functions_util.cpp
Normal file
32
source/opt/eliminate_dead_functions_util.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2019 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 "eliminate_dead_functions_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
namespace eliminatedeadfunctionsutil {
|
||||
|
||||
Module::iterator EliminateFunction(IRContext* context,
|
||||
Module::iterator* func_iter) {
|
||||
(*func_iter)
|
||||
->ForEachInst([context](Instruction* inst) { context->KillInst(inst); },
|
||||
true);
|
||||
return func_iter->Erase();
|
||||
}
|
||||
|
||||
} // namespace eliminatedeadfunctionsutil
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
36
source/opt/eliminate_dead_functions_util.h
Normal file
36
source/opt/eliminate_dead_functions_util.h
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2019 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_OPT_ELIMINATE_DEAD_FUNCTIONS_UTIL_H_
|
||||
#define SOURCE_OPT_ELIMINATE_DEAD_FUNCTIONS_UTIL_H_
|
||||
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
// Provides functionality for eliminating functions that are not needed, for use
|
||||
// by various analyses and passes.
|
||||
namespace eliminatedeadfunctionsutil {
|
||||
|
||||
// Removes all of the function's instructions, removes the function from the
|
||||
// module, and returns the next iterator.
|
||||
Module::iterator EliminateFunction(IRContext* context,
|
||||
Module::iterator* func_iter);
|
||||
|
||||
} // namespace eliminatedeadfunctionsutil
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_OPT_ELIMINATE_DEAD_FUNCTIONS_UTIL_H_
|
@ -25,6 +25,8 @@ set(SPIRV_TOOLS_REDUCE_SOURCES
|
||||
reduction_pass.h
|
||||
reduction_util.h
|
||||
remove_instruction_reduction_opportunity.h
|
||||
remove_function_reduction_opportunity.h
|
||||
remove_function_reduction_opportunity_finder.h
|
||||
remove_opname_instruction_reduction_opportunity_finder.h
|
||||
remove_unreferenced_instruction_reduction_opportunity_finder.h
|
||||
structured_loop_to_selection_reduction_opportunity.h
|
||||
@ -41,6 +43,8 @@ set(SPIRV_TOOLS_REDUCE_SOURCES
|
||||
reduction_opportunity.cpp
|
||||
reduction_pass.cpp
|
||||
reduction_util.cpp
|
||||
remove_function_reduction_opportunity.cpp
|
||||
remove_function_reduction_opportunity_finder.cpp
|
||||
remove_instruction_reduction_opportunity.cpp
|
||||
remove_unreferenced_instruction_reduction_opportunity_finder.cpp
|
||||
remove_opname_instruction_reduction_opportunity_finder.cpp
|
||||
|
40
source/reduce/remove_function_reduction_opportunity.cpp
Normal file
40
source/reduce/remove_function_reduction_opportunity.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2019 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 "remove_function_reduction_opportunity.h"
|
||||
#include "source/opt/eliminate_dead_functions_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
bool RemoveFunctionReductionOpportunity::PreconditionHolds() {
|
||||
// Removing one function cannot influence whether another function can be
|
||||
// removed.
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoveFunctionReductionOpportunity::Apply() {
|
||||
for (opt::Module::iterator function_it = context_->module()->begin();
|
||||
function_it != context_->module()->end(); ++function_it) {
|
||||
if (&*function_it == function_) {
|
||||
opt::eliminatedeadfunctionsutil::EliminateFunction(context_,
|
||||
&function_it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(0 && "Function to be removed was not found.");
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
49
source/reduce/remove_function_reduction_opportunity.h
Normal file
49
source/reduce/remove_function_reduction_opportunity.h
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2019 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_FUNCTION_REDUCTION_OPPORTUNITY_H_
|
||||
#define SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_H_
|
||||
|
||||
#include "reduction_opportunity.h"
|
||||
#include "source/opt/function.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// An opportunity to remove an unreferenced function.
|
||||
class RemoveFunctionReductionOpportunity : public ReductionOpportunity {
|
||||
public:
|
||||
// Creates an opportunity to remove |function| from the module represented by
|
||||
// |context|.
|
||||
RemoveFunctionReductionOpportunity(opt::IRContext* context,
|
||||
opt::Function* function)
|
||||
: context_(context), function_(function) {}
|
||||
|
||||
bool PreconditionHolds() override;
|
||||
|
||||
protected:
|
||||
void Apply() override;
|
||||
|
||||
private:
|
||||
// The IR context for the module under analysis.
|
||||
opt::IRContext* context_;
|
||||
|
||||
// The function that can be removed.
|
||||
opt::Function* function_;
|
||||
};
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_H_
|
@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2019 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 "remove_function_reduction_opportunity_finder.h"
|
||||
#include "remove_function_reduction_opportunity.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
RemoveFunctionReductionOpportunityFinder::GetAvailableOpportunities(
|
||||
opt::IRContext* context) const {
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
||||
// Consider each function.
|
||||
for (auto& function : *context->module()) {
|
||||
if (context->get_def_use_mgr()->NumUses(function.result_id()) > 0) {
|
||||
// If the function is referenced, ignore it.
|
||||
continue;
|
||||
}
|
||||
result.push_back(
|
||||
MakeUnique<RemoveFunctionReductionOpportunity>(context, &function));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string RemoveFunctionReductionOpportunityFinder::GetName() const {
|
||||
return "RemoveFunctionReductionOpportunityFinder";
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
42
source/reduce/remove_function_reduction_opportunity_finder.h
Normal file
42
source/reduce/remove_function_reduction_opportunity_finder.h
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2019 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_FUNCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
#define SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
|
||||
#include "source/reduce/reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// A finder of opportunities to remove unreferenced functions.
|
||||
class RemoveFunctionReductionOpportunityFinder
|
||||
: public ReductionOpportunityFinder {
|
||||
public:
|
||||
RemoveFunctionReductionOpportunityFinder() = default;
|
||||
|
||||
~RemoveFunctionReductionOpportunityFinder() override = default;
|
||||
|
||||
std::string GetName() const final;
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||
opt::IRContext* context) const final;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
@ -20,6 +20,7 @@ add_spvtools_unittest(TARGET reduce
|
||||
reduce_test_util.cpp
|
||||
reduce_test_util.h
|
||||
reducer_test.cpp
|
||||
remove_function_test.cpp
|
||||
remove_opname_instruction_test.cpp
|
||||
remove_unreferenced_instruction_test.cpp
|
||||
structured_loop_to_selection_test.cpp
|
||||
|
294
test/reduce/remove_function_test.cpp
Normal file
294
test/reduce/remove_function_test.cpp
Normal file
@ -0,0 +1,294 @@
|
||||
// Copyright (c) 2019 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_function_reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
namespace {
|
||||
|
||||
// Helper to count the number of functions in the module.
|
||||
// Remove if there turns out to be a more direct way to do this.
|
||||
uint32_t count_functions(opt::IRContext* context) {
|
||||
uint32_t result = 0;
|
||||
for (auto& function : *context->module()) {
|
||||
(void)(function);
|
||||
++result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST(RemoveFunctionTest, BasicCheck) {
|
||||
std::string shader = 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
|
||||
%6 = OpFunction %2 None %3
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%8 = OpFunction %2 None %3
|
||||
%9 = OpLabel
|
||||
%10 = OpFunctionCall %2 %6
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
|
||||
ASSERT_EQ(3, count_functions(context.get()));
|
||||
|
||||
auto ops =
|
||||
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
|
||||
ASSERT_EQ(2, count_functions(context.get()));
|
||||
|
||||
std::string after_first = 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
|
||||
%6 = OpFunction %2 None %3
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CheckEqual(env, after_first, context.get());
|
||||
|
||||
ops = RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
|
||||
ASSERT_EQ(1, count_functions(context.get()));
|
||||
|
||||
std::string after_second = 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
|
||||
)";
|
||||
|
||||
CheckEqual(env, after_second, context.get());
|
||||
}
|
||||
|
||||
TEST(RemoveFunctionTest, NothingToRemove) {
|
||||
std::string shader = 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
|
||||
%11 = OpFunctionCall %2 %8
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%6 = OpFunction %2 None %3
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%8 = OpFunction %2 None %3
|
||||
%9 = OpLabel
|
||||
%10 = OpFunctionCall %2 %6
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
auto ops =
|
||||
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(0, ops.size());
|
||||
}
|
||||
|
||||
TEST(RemoveFunctionTest, TwoRemovableFunctions) {
|
||||
std::string shader = 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
|
||||
%6 = OpFunction %2 None %3
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%8 = OpFunction %2 None %3
|
||||
%9 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
|
||||
ASSERT_EQ(3, count_functions(context.get()));
|
||||
|
||||
auto ops =
|
||||
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(2, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
ASSERT_EQ(2, count_functions(context.get()));
|
||||
ASSERT_TRUE(ops[1]->PreconditionHolds());
|
||||
ops[1]->TryToApply();
|
||||
ASSERT_EQ(1, count_functions(context.get()));
|
||||
|
||||
std::string after = 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
|
||||
)";
|
||||
|
||||
CheckEqual(env, after, context.get());
|
||||
}
|
||||
|
||||
TEST(RemoveFunctionTest, NoRemovalsDueToOpName) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %6 "foo("
|
||||
OpName %8 "bar("
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%6 = OpFunction %2 None %3
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%8 = OpFunction %2 None %3
|
||||
%9 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
auto ops =
|
||||
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(0, ops.size());
|
||||
}
|
||||
|
||||
TEST(RemoveFunctionTest, NoRemovalDueToLinkageDecoration) {
|
||||
// The non-entry point function is not removable because it is referenced by a
|
||||
// linkage decoration. Thus no function can be removed.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "main"
|
||||
OpName %1 "main"
|
||||
OpDecorate %2 LinkageAttributes "ExportedFunc" Export
|
||||
%4 = OpTypeVoid
|
||||
%5 = OpTypeFunction %4
|
||||
%1 = OpFunction %4 None %5
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%2 = OpFunction %4 None %5
|
||||
%7 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
auto ops =
|
||||
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(0, ops.size());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
@ -25,6 +25,7 @@
|
||||
#include "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/reducer.h"
|
||||
#include "source/reduce/remove_function_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h"
|
||||
@ -243,6 +244,8 @@ int main(int argc, const char** argv) {
|
||||
StructuredLoopToSelectionReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<MergeBlocksReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<RemoveFunctionReductionOpportunityFinder>());
|
||||
|
||||
reducer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user