spirv-reduce: Support reducing a specific function (#3774)

Motivated by integrating spirv-reduce into spirv-fuzz, so that an
added function can be made smaller during shrinking, this adds support
in spirv-reduce for asking reduction to be restricted to the
instructions of a single specified function.
This commit is contained in:
Alastair Donaldson 2020-09-11 06:29:43 +01:00 коммит произвёл GitHub
Родитель de7d57984d
Коммит 5dcb576b69
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
49 изменённых файлов: 727 добавлений и 229 удалений

Просмотреть файл

@ -674,6 +674,13 @@ SPIRV_TOOLS_EXPORT void spvReducerOptionsSetStepLimit(
SPIRV_TOOLS_EXPORT void spvReducerOptionsSetFailOnValidationError( SPIRV_TOOLS_EXPORT void spvReducerOptionsSetFailOnValidationError(
spv_reducer_options options, bool fail_on_validation_error); spv_reducer_options options, bool fail_on_validation_error);
// Sets the function that the reducer should target. If set to zero the reducer
// will target all functions as well as parts of the module that lie outside
// functions. Otherwise the reducer will restrict reduction to the function
// with result id |target_function|, which is required to exist.
SPIRV_TOOLS_EXPORT void spvReducerOptionsSetTargetFunction(
spv_reducer_options options, uint32_t target_function);
// Creates a fuzzer options object with default options. Returns a valid // Creates a fuzzer options object with default options. Returns a valid
// options object. The object remains valid until it is passed into // options object. The object remains valid until it is passed into
// |spvFuzzerOptionsDestroy|. // |spvFuzzerOptionsDestroy|.

Просмотреть файл

@ -202,6 +202,11 @@ class ReducerOptions {
fail_on_validation_error); fail_on_validation_error);
} }
// See spvReducerOptionsSetTargetFunction.
void set_target_function(uint32_t target_function) {
spvReducerOptionsSetTargetFunction(options_, target_function);
}
private: private:
spv_reducer_options options_; spv_reducer_options options_;
}; };

Просмотреть файл

@ -50,6 +50,7 @@ set(SPIRV_TOOLS_REDUCE_SOURCES
operand_to_dominating_id_reduction_opportunity_finder.cpp operand_to_dominating_id_reduction_opportunity_finder.cpp
reducer.cpp reducer.cpp
reduction_opportunity.cpp reduction_opportunity.cpp
reduction_opportunity_finder.cpp
reduction_pass.cpp reduction_pass.cpp
reduction_util.cpp reduction_util.cpp
remove_block_reduction_opportunity.cpp remove_block_reduction_opportunity.cpp

Просмотреть файл

@ -22,7 +22,8 @@ namespace reduce {
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
ConditionalBranchToSimpleConditionalBranchOpportunityFinder:: ConditionalBranchToSimpleConditionalBranchOpportunityFinder::
GetAvailableOpportunities(opt::IRContext* context) const { GetAvailableOpportunities(opt::IRContext* context,
uint32_t target_function) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
// Find the opportunities for redirecting all false targets before the // Find the opportunities for redirecting all false targets before the
@ -31,10 +32,10 @@ ConditionalBranchToSimpleConditionalBranchOpportunityFinder::
// reducer is improved by avoiding contiguous opportunities that disable one // reducer is improved by avoiding contiguous opportunities that disable one
// another. // another.
for (bool redirect_to_true : {true, false}) { for (bool redirect_to_true : {true, false}) {
// Consider every function. // Consider every relevant function.
for (auto& function : *context->module()) { for (auto* function : GetTargetFunctions(context, target_function)) {
// Consider every block in the function. // Consider every block in the function.
for (auto& block : function) { for (auto& block : *function) {
// The terminator must be SpvOpBranchConditional. // The terminator must be SpvOpBranchConditional.
opt::Instruction* terminator = block.terminator(); opt::Instruction* terminator = block.terminator();
if (terminator->opcode() != SpvOpBranchConditional) { if (terminator->opcode() != SpvOpBranchConditional) {

Просмотреть файл

@ -26,7 +26,7 @@ class ConditionalBranchToSimpleConditionalBranchOpportunityFinder
: public ReductionOpportunityFinder { : public ReductionOpportunityFinder {
public: public:
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const override; opt::IRContext* context, uint32_t target_function) const override;
std::string GetName() const override; std::string GetName() const override;
}; };

Просмотреть файл

@ -25,17 +25,17 @@ std::string MergeBlocksReductionOpportunityFinder::GetName() const {
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
MergeBlocksReductionOpportunityFinder::GetAvailableOpportunities( MergeBlocksReductionOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context) const { opt::IRContext* context, uint32_t target_function) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
// Consider every block in every function. // Consider every block in every function.
for (auto& function : *context->module()) { for (auto* function : GetTargetFunctions(context, target_function)) {
for (auto& block : function) { for (auto& block : *function) {
// See whether it is possible to merge this block with its successor. // See whether it is possible to merge this block with its successor.
if (opt::blockmergeutil::CanMergeWithSuccessor(context, &block)) { if (opt::blockmergeutil::CanMergeWithSuccessor(context, &block)) {
// It is, so record an opportunity to do this. // It is, so record an opportunity to do this.
result.push_back(spvtools::MakeUnique<MergeBlocksReductionOpportunity>( result.push_back(spvtools::MakeUnique<MergeBlocksReductionOpportunity>(
context, &function, &block)); context, function, &block));
} }
} }
} }

Просмотреть файл

@ -31,7 +31,7 @@ class MergeBlocksReductionOpportunityFinder
std::string GetName() const final; std::string GetName() const final;
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const final; opt::IRContext* context, uint32_t target_function) const final;
private: private:
}; };

Просмотреть файл

@ -22,7 +22,7 @@ namespace reduce {
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
OperandToConstReductionOpportunityFinder::GetAvailableOpportunities( OperandToConstReductionOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context) const { opt::IRContext* context, uint32_t target_function) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
assert(result.empty()); assert(result.empty());
@ -35,8 +35,8 @@ OperandToConstReductionOpportunityFinder::GetAvailableOpportunities(
// contiguous blocks of opportunities early on, and we want to avoid having a // contiguous blocks of opportunities early on, and we want to avoid having a
// large block of incompatible opportunities if possible. // large block of incompatible opportunities if possible.
for (const auto& constant : context->GetConstants()) { for (const auto& constant : context->GetConstants()) {
for (auto& function : *context->module()) { for (auto* function : GetTargetFunctions(context, target_function)) {
for (auto& block : function) { for (auto& block : *function) {
for (auto& inst : block) { for (auto& inst : block) {
// We iterate through the operands using an explicit index (rather // We iterate through the operands using an explicit index (rather
// than using a lambda) so that we use said index in the construction // than using a lambda) so that we use said index in the construction

Просмотреть файл

@ -33,7 +33,7 @@ class OperandToConstReductionOpportunityFinder
std::string GetName() const final; std::string GetName() const final;
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const final; opt::IRContext* context, uint32_t target_function) const final;
private: private:
}; };

Просмотреть файл

@ -22,7 +22,7 @@ namespace reduce {
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
OperandToDominatingIdReductionOpportunityFinder::GetAvailableOpportunities( OperandToDominatingIdReductionOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context) const { opt::IRContext* context, uint32_t target_function) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
// Go through every instruction in every block, considering it as a potential // Go through every instruction in every block, considering it as a potential
@ -38,15 +38,15 @@ OperandToDominatingIdReductionOpportunityFinder::GetAvailableOpportunities(
// to prioritise replacing e with its smallest sub-expressions; generalising // to prioritise replacing e with its smallest sub-expressions; generalising
// this idea to dominating ids this roughly corresponds to more distant // this idea to dominating ids this roughly corresponds to more distant
// dominators. // dominators.
for (auto& function : *context->module()) { for (auto* function : GetTargetFunctions(context, target_function)) {
for (auto dominating_block = function.begin(); for (auto dominating_block = function->begin();
dominating_block != function.end(); ++dominating_block) { dominating_block != function->end(); ++dominating_block) {
for (auto& dominating_inst : *dominating_block) { for (auto& dominating_inst : *dominating_block) {
if (dominating_inst.HasResultId() && dominating_inst.type_id()) { if (dominating_inst.HasResultId() && dominating_inst.type_id()) {
// Consider replacing any operand with matching type in a dominated // Consider replacing any operand with matching type in a dominated
// instruction with the id generated by this instruction. // instruction with the id generated by this instruction.
GetOpportunitiesForDominatingInst( GetOpportunitiesForDominatingInst(
&result, &dominating_inst, dominating_block, &function, context); &result, &dominating_inst, dominating_block, function, context);
} }
} }
} }

Просмотреть файл

@ -40,7 +40,7 @@ class OperandToDominatingIdReductionOpportunityFinder
std::string GetName() const final; std::string GetName() const final;
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const final; opt::IRContext* context, uint32_t target_function) const final;
private: private:
void GetOpportunitiesForDominatingInst( void GetOpportunitiesForDominatingInst(

Просмотреть файл

@ -22,11 +22,11 @@ namespace reduce {
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
OperandToUndefReductionOpportunityFinder::GetAvailableOpportunities( OperandToUndefReductionOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context) const { opt::IRContext* context, uint32_t target_function) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
for (auto& function : *context->module()) { for (auto* function : GetTargetFunctions(context, target_function)) {
for (auto& block : function) { for (auto& block : *function) {
for (auto& inst : block) { for (auto& inst : block) {
// Skip instructions that result in a pointer type. // Skip instructions that result in a pointer type.
auto type_id = inst.type_id(); auto type_id = inst.type_id();

Просмотреть файл

@ -32,7 +32,7 @@ class OperandToUndefReductionOpportunityFinder
std::string GetName() const final; std::string GetName() const final;
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const final; opt::IRContext* context, uint32_t target_function) const final;
private: private:
}; };

Просмотреть файл

@ -183,7 +183,8 @@ Reducer::ReductionResultStatus Reducer::RunPasses(
consumer_(SPV_MSG_INFO, nullptr, {}, consumer_(SPV_MSG_INFO, nullptr, {},
("Trying pass " + pass->GetName() + ".").c_str()); ("Trying pass " + pass->GetName() + ".").c_str());
do { do {
auto maybe_result = pass->TryApplyReduction(*current_binary); auto maybe_result =
pass->TryApplyReduction(*current_binary, options->target_function);
if (maybe_result.empty()) { if (maybe_result.empty()) {
// For this round, the pass has no more opportunities (chunks) to // For this round, the pass has no more opportunities (chunks) to
// apply, so move on to the next pass. // apply, so move on to the next pass.

Просмотреть файл

@ -0,0 +1,34 @@
// Copyright (c) 2020 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 "reduction_opportunity_finder.h"
namespace spvtools {
namespace reduce {
std::vector<opt::Function*> ReductionOpportunityFinder::GetTargetFunctions(
opt::IRContext* ir_context, uint32_t target_function) {
std::vector<opt::Function*> result;
for (auto& function : *ir_context->module()) {
if (!target_function || function.result_id() == target_function) {
result.push_back(&function);
}
}
assert((!target_function || !result.empty()) &&
"Requested target function must exist.");
return result;
}
} // namespace reduce
} // namespace spvtools

Просмотреть файл

@ -15,6 +15,8 @@
#ifndef SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_ #ifndef SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_
#define SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_ #define SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_
#include <vector>
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
#include "source/reduce/reduction_opportunity.h" #include "source/reduce/reduction_opportunity.h"
@ -29,12 +31,25 @@ class ReductionOpportunityFinder {
virtual ~ReductionOpportunityFinder() = default; virtual ~ReductionOpportunityFinder() = default;
// Finds and returns the reduction opportunities relevant to this pass that // Finds and returns the reduction opportunities relevant to this pass that
// could be applied to the given SPIR-V module. // could be applied to SPIR-V module |context|.
//
// If |target_function| is non-zero then the available opportunities will be
// restricted to only those opportunities that modify the function with result
// id |target_function|.
virtual std::vector<std::unique_ptr<ReductionOpportunity>> virtual std::vector<std::unique_ptr<ReductionOpportunity>>
GetAvailableOpportunities(opt::IRContext* context) const = 0; GetAvailableOpportunities(opt::IRContext* context,
uint32_t target_function) const = 0;
// Provides a name for the finder. // Provides a name for the finder.
virtual std::string GetName() const = 0; virtual std::string GetName() const = 0;
protected:
// Requires that |target_function| is zero or the id of a function in
// |ir_context|. If |target_function| is zero, returns all the functions in
// |ir_context|. Otherwise, returns the function with id |target_function|.
// This allows fuzzer passes to restrict attention to a single function.
static std::vector<opt::Function*> GetTargetFunctions(
opt::IRContext* ir_context, uint32_t target_function);
}; };
} // namespace reduce } // namespace reduce

Просмотреть файл

@ -22,7 +22,7 @@ namespace spvtools {
namespace reduce { namespace reduce {
std::vector<uint32_t> ReductionPass::TryApplyReduction( std::vector<uint32_t> ReductionPass::TryApplyReduction(
const std::vector<uint32_t>& binary) { const std::vector<uint32_t>& binary, uint32_t target_function) {
// We represent modules as binaries because (a) attempts at reduction need to // We represent modules as binaries because (a) attempts at reduction need to
// end up in binary form to be passed on to SPIR-V-consuming tools, and (b) // end up in binary form to be passed on to SPIR-V-consuming tools, and (b)
// when we apply a reduction step we need to do it on a fresh version of the // when we apply a reduction step we need to do it on a fresh version of the
@ -34,7 +34,7 @@ std::vector<uint32_t> ReductionPass::TryApplyReduction(
assert(context); assert(context);
std::vector<std::unique_ptr<ReductionOpportunity>> opportunities = std::vector<std::unique_ptr<ReductionOpportunity>> opportunities =
finder_->GetAvailableOpportunities(context.get()); finder_->GetAvailableOpportunities(context.get(), target_function);
// There is no point in having a granularity larger than the number of // There is no point in having a granularity larger than the number of
// opportunities, so reduce the granularity in this case. // opportunities, so reduce the granularity in this case.

Просмотреть файл

@ -49,7 +49,12 @@ class ReductionPass {
// Returns an empty vector if there are no more chunks left to apply; in this // Returns an empty vector if there are no more chunks left to apply; in this
// case, the index will be reset and the granularity lowered for the next // case, the index will be reset and the granularity lowered for the next
// round. // round.
std::vector<uint32_t> TryApplyReduction(const std::vector<uint32_t>& binary); //
// If |target_function| is non-zero, only reduction opportunities that
// simplify the internals of the function with result id |target_function|
// will be applied.
std::vector<uint32_t> TryApplyReduction(const std::vector<uint32_t>& binary,
uint32_t target_function);
// Notifies the reduction pass whether the binary returned from // Notifies the reduction pass whether the binary returned from
// TryApplyReduction is interesting, so that the next call to // TryApplyReduction is interesting, so that the next call to

Просмотреть файл

@ -25,15 +25,15 @@ std::string RemoveBlockReductionOpportunityFinder::GetName() const {
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
RemoveBlockReductionOpportunityFinder::GetAvailableOpportunities( RemoveBlockReductionOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context) const { opt::IRContext* context, uint32_t target_function) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
// Consider every block in every function. // Consider every block in every relevant function.
for (auto& function : *context->module()) { for (auto* function : GetTargetFunctions(context, target_function)) {
for (auto bi = function.begin(); bi != function.end(); ++bi) { for (auto bi = function->begin(); bi != function->end(); ++bi) {
if (IsBlockValidOpportunity(context, function, bi)) { if (IsBlockValidOpportunity(context, function, &bi)) {
result.push_back(spvtools::MakeUnique<RemoveBlockReductionOpportunity>( result.push_back(
&function, &*bi)); MakeUnique<RemoveBlockReductionOpportunity>(function, &*bi));
} }
} }
} }
@ -41,22 +41,22 @@ RemoveBlockReductionOpportunityFinder::GetAvailableOpportunities(
} }
bool RemoveBlockReductionOpportunityFinder::IsBlockValidOpportunity( bool RemoveBlockReductionOpportunityFinder::IsBlockValidOpportunity(
opt::IRContext* context, opt::Function& function, opt::IRContext* context, opt::Function* function,
opt::Function::iterator& bi) { opt::Function::iterator* bi) {
assert(bi != function.end() && "Block iterator was out of bounds"); assert(*bi != function->end() && "Block iterator was out of bounds");
// Don't remove first block; we don't want to end up with no blocks. // Don't remove first block; we don't want to end up with no blocks.
if (bi == function.begin()) { if (*bi == function->begin()) {
return false; return false;
} }
// Don't remove blocks with references. // Don't remove blocks with references.
if (context->get_def_use_mgr()->NumUsers(bi->id()) > 0) { if (context->get_def_use_mgr()->NumUsers((*bi)->id()) > 0) {
return false; return false;
} }
// Don't remove blocks whose instructions have outside references. // Don't remove blocks whose instructions have outside references.
if (!BlockInstructionsHaveNoOutsideReferences(context, bi)) { if (!BlockInstructionsHaveNoOutsideReferences(context, *bi)) {
return false; return false;
} }

Просмотреть файл

@ -34,14 +34,14 @@ class RemoveBlockReductionOpportunityFinder
std::string GetName() const final; std::string GetName() const final;
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const final; opt::IRContext* context, uint32_t target_function) const final;
private: private:
// Returns true if the block |bi| in function |function| is a valid // Returns true if the block |bi| in function |function| is a valid
// opportunity according to various restrictions. // opportunity according to various restrictions.
static bool IsBlockValidOpportunity(opt::IRContext* context, static bool IsBlockValidOpportunity(opt::IRContext* context,
opt::Function& function, opt::Function* function,
opt::Function::iterator& bi); opt::Function::iterator* bi);
// Returns true if the instructions (definitions) in block |bi| have no // Returns true if the instructions (definitions) in block |bi| have no
// references, except for references from inside the block itself. // references, except for references from inside the block itself.

Просмотреть файл

@ -21,7 +21,14 @@ namespace reduce {
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
RemoveFunctionReductionOpportunityFinder::GetAvailableOpportunities( RemoveFunctionReductionOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context) const { opt::IRContext* context, uint32_t target_function) const {
if (target_function) {
// If we are targeting a specific function then we are only interested in
// opportunities that simplify the internals of that function; removing
// whole functions does not fit the bill.
return {};
}
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
// Consider each function. // Consider each function.
for (auto& function : *context->module()) { for (auto& function : *context->module()) {

Просмотреть файл

@ -31,7 +31,7 @@ class RemoveFunctionReductionOpportunityFinder
std::string GetName() const final; std::string GetName() const final;
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const final; opt::IRContext* context, uint32_t target_function) const final;
private: private:
}; };

Просмотреть файл

@ -30,11 +30,11 @@ std::string RemoveSelectionReductionOpportunityFinder::GetName() const {
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
RemoveSelectionReductionOpportunityFinder::GetAvailableOpportunities( RemoveSelectionReductionOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context) const { opt::IRContext* context, uint32_t target_function) const {
// Get all loop merge and continue blocks so we can check for these later. // Get all loop merge and continue blocks so we can check for these later.
std::unordered_set<uint32_t> merge_and_continue_blocks_from_loops; std::unordered_set<uint32_t> merge_and_continue_blocks_from_loops;
for (auto& function : *context->module()) { for (auto* function : GetTargetFunctions(context, target_function)) {
for (auto& block : function) { for (auto& block : *function) {
if (auto merge_instruction = block.GetMergeInst()) { if (auto merge_instruction = block.GetMergeInst()) {
if (merge_instruction->opcode() == SpvOpLoopMerge) { if (merge_instruction->opcode() == SpvOpLoopMerge) {
uint32_t merge_block_id = uint32_t merge_block_id =

Просмотреть файл

@ -33,7 +33,7 @@ class RemoveSelectionReductionOpportunityFinder
std::string GetName() const final; std::string GetName() const final;
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const final; opt::IRContext* context, uint32_t target_function) const final;
// Returns true if the OpSelectionMerge instruction |merge_instruction| in // Returns true if the OpSelectionMerge instruction |merge_instruction| in
// block |header_block| can be removed. // block |header_block| can be removed.

Просмотреть файл

@ -28,61 +28,72 @@ RemoveUnusedInstructionReductionOpportunityFinder::
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
RemoveUnusedInstructionReductionOpportunityFinder::GetAvailableOpportunities( RemoveUnusedInstructionReductionOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context) const { opt::IRContext* context, uint32_t target_function) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
for (auto& inst : context->module()->debugs1()) { if (!target_function) {
if (context->get_def_use_mgr()->NumUses(&inst) > 0) { // We are not restricting reduction to a specific function, so we consider
continue; // unused instructions defined outside functions.
for (auto& inst : context->module()->debugs1()) {
if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
continue;
}
result.push_back(
MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& inst : context->module()->debugs2()) {
if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
continue;
}
result.push_back(
MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& inst : context->module()->debugs3()) {
if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
continue;
}
result.push_back(
MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& inst : context->module()->ext_inst_debuginfo()) {
if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
continue;
}
result.push_back(
MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& inst : context->module()->types_values()) {
if (!remove_constants_and_undefs_ &&
spvOpcodeIsConstantOrUndef(inst.opcode())) {
continue;
}
if (!OnlyReferencedByIntimateDecorationOrEntryPointInterface(context,
inst)) {
continue;
}
result.push_back(
MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& inst : context->module()->annotations()) {
if (context->get_def_use_mgr()->NumUsers(&inst) > 0) {
continue;
}
if (!IsIndependentlyRemovableDecoration(inst)) {
continue;
}
result.push_back(
MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
} }
result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
} }
for (auto& inst : context->module()->debugs2()) { for (auto* function : GetTargetFunctions(context, target_function)) {
if (context->get_def_use_mgr()->NumUses(&inst) > 0) { for (auto& block : *function) {
continue;
}
result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& inst : context->module()->debugs3()) {
if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
continue;
}
result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& inst : context->module()->ext_inst_debuginfo()) {
if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
continue;
}
result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& inst : context->module()->types_values()) {
if (!remove_constants_and_undefs_ &&
spvOpcodeIsConstantOrUndef(inst.opcode())) {
continue;
}
if (!OnlyReferencedByIntimateDecorationOrEntryPointInterface(context,
inst)) {
continue;
}
result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& inst : context->module()->annotations()) {
if (context->get_def_use_mgr()->NumUsers(&inst) > 0) {
continue;
}
if (!IsIndependentlyRemovableDecoration(inst)) {
continue;
}
result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& function : *context->module()) {
for (auto& block : function) {
for (auto& inst : block) { for (auto& inst : block) {
if (context->get_def_use_mgr()->NumUses(&inst) > 0) { if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
continue; continue;

Просмотреть файл

@ -38,7 +38,7 @@ class RemoveUnusedInstructionReductionOpportunityFinder
std::string GetName() const final; std::string GetName() const final;
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const final; opt::IRContext* context, uint32_t target_function) const final;
private: private:
// Returns true if and only if the only uses of |inst| are by decorations that // Returns true if and only if the only uses of |inst| are by decorations that

Просмотреть файл

@ -24,7 +24,14 @@ namespace reduce {
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
RemoveUnusedStructMemberReductionOpportunityFinder::GetAvailableOpportunities( RemoveUnusedStructMemberReductionOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context) const { opt::IRContext* context, uint32_t target_function) const {
if (target_function) {
// Removing an unused struct member is a global change, as struct types are
// global. We thus do not consider such opportunities if we are targeting
// a specific function.
return {};
}
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
// We track those struct members that are never accessed. We do this by // We track those struct members that are never accessed. We do this by

Просмотреть файл

@ -32,7 +32,7 @@ class RemoveUnusedStructMemberReductionOpportunityFinder
std::string GetName() const final; std::string GetName() const final;
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const final; opt::IRContext* context, uint32_t target_function) const final;
private: private:
// A helper method to update |unused_members_to_structs| by removing from it // A helper method to update |unused_members_to_structs| by removing from it

Просмотреть файл

@ -22,13 +22,13 @@ namespace reduce {
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
SimpleConditionalBranchToBranchOpportunityFinder::GetAvailableOpportunities( SimpleConditionalBranchToBranchOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context) const { opt::IRContext* context, uint32_t target_function) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
// Consider every function. // Consider every function.
for (auto& function : *context->module()) { for (auto* function : GetTargetFunctions(context, target_function)) {
// Consider every block in the function. // Consider every block in the function.
for (auto& block : function) { for (auto& block : *function) {
// The terminator must be SpvOpBranchConditional. // The terminator must be SpvOpBranchConditional.
opt::Instruction* terminator = block.terminator(); opt::Instruction* terminator = block.terminator();
if (terminator->opcode() != SpvOpBranchConditional) { if (terminator->opcode() != SpvOpBranchConditional) {

Просмотреть файл

@ -26,7 +26,7 @@ class SimpleConditionalBranchToBranchOpportunityFinder
: public ReductionOpportunityFinder { : public ReductionOpportunityFinder {
public: public:
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const override; opt::IRContext* context, uint32_t target_function) const override;
std::string GetName() const override; std::string GetName() const override;
}; };

Просмотреть файл

@ -26,12 +26,12 @@ const uint32_t kContinueNodeIndex = 1;
std::vector<std::unique_ptr<ReductionOpportunity>> std::vector<std::unique_ptr<ReductionOpportunity>>
StructuredLoopToSelectionReductionOpportunityFinder::GetAvailableOpportunities( StructuredLoopToSelectionReductionOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context) const { opt::IRContext* context, uint32_t target_function) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
std::set<uint32_t> merge_block_ids; std::set<uint32_t> merge_block_ids;
for (auto& function : *context->module()) { for (auto* function : GetTargetFunctions(context, target_function)) {
for (auto& block : function) { for (auto& block : *function) {
auto merge_block_id = block.MergeBlockIdIfAny(); auto merge_block_id = block.MergeBlockIdIfAny();
if (merge_block_id) { if (merge_block_id) {
merge_block_ids.insert(merge_block_id); merge_block_ids.insert(merge_block_id);
@ -40,8 +40,8 @@ StructuredLoopToSelectionReductionOpportunityFinder::GetAvailableOpportunities(
} }
// Consider each loop construct header in the module. // Consider each loop construct header in the module.
for (auto& function : *context->module()) { for (auto* function : GetTargetFunctions(context, target_function)) {
for (auto& block : function) { for (auto& block : *function) {
auto loop_merge_inst = block.GetLoopMergeInst(); auto loop_merge_inst = block.GetLoopMergeInst();
if (!loop_merge_inst) { if (!loop_merge_inst) {
// This is not a loop construct header. // This is not a loop construct header.
@ -69,8 +69,8 @@ StructuredLoopToSelectionReductionOpportunityFinder::GetAvailableOpportunities(
// so we cautiously do not consider applying a transformation. // so we cautiously do not consider applying a transformation.
auto merge_block_id = auto merge_block_id =
loop_merge_inst->GetSingleWordInOperand(kMergeNodeIndex); loop_merge_inst->GetSingleWordInOperand(kMergeNodeIndex);
if (!context->GetDominatorAnalysis(&function)->Dominates( if (!context->GetDominatorAnalysis(function)->Dominates(block.id(),
block.id(), merge_block_id)) { merge_block_id)) {
continue; continue;
} }
@ -78,7 +78,7 @@ StructuredLoopToSelectionReductionOpportunityFinder::GetAvailableOpportunities(
// construct header. If not (e.g. because the loop contains OpReturn, // construct header. If not (e.g. because the loop contains OpReturn,
// OpKill or OpUnreachable), we cautiously do not consider applying // OpKill or OpUnreachable), we cautiously do not consider applying
// a transformation. // a transformation.
if (!context->GetPostDominatorAnalysis(&function)->Dominates( if (!context->GetPostDominatorAnalysis(function)->Dominates(
merge_block_id, block.id())) { merge_block_id, block.id())) {
continue; continue;
} }
@ -87,7 +87,7 @@ StructuredLoopToSelectionReductionOpportunityFinder::GetAvailableOpportunities(
// opportunity to do so. // opportunity to do so.
result.push_back( result.push_back(
MakeUnique<StructuredLoopToSelectionReductionOpportunity>( MakeUnique<StructuredLoopToSelectionReductionOpportunity>(
context, &block, &function)); context, &block, function));
} }
} }
return result; return result;

Просмотреть файл

@ -46,7 +46,7 @@ class StructuredLoopToSelectionReductionOpportunityFinder
std::string GetName() const final; std::string GetName() const final;
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
opt::IRContext* context) const final; opt::IRContext* context, uint32_t target_function) const final;
private: private:
}; };

Просмотреть файл

@ -23,7 +23,9 @@ const uint32_t kDefaultStepLimit = 2500;
} // namespace } // namespace
spv_reducer_options_t::spv_reducer_options_t() spv_reducer_options_t::spv_reducer_options_t()
: step_limit(kDefaultStepLimit), fail_on_validation_error(false) {} : step_limit(kDefaultStepLimit),
fail_on_validation_error(false),
target_function(0) {}
SPIRV_TOOLS_EXPORT spv_reducer_options spvReducerOptionsCreate() { SPIRV_TOOLS_EXPORT spv_reducer_options spvReducerOptionsCreate() {
return new spv_reducer_options_t(); return new spv_reducer_options_t();
@ -42,3 +44,8 @@ SPIRV_TOOLS_EXPORT void spvReducerOptionsSetFailOnValidationError(
spv_reducer_options options, bool fail_on_validation_error) { spv_reducer_options options, bool fail_on_validation_error) {
options->fail_on_validation_error = fail_on_validation_error; options->fail_on_validation_error = fail_on_validation_error;
} }
SPIRV_TOOLS_EXPORT void spvReducerOptionsSetTargetFunction(
spv_reducer_options options, uint32_t target_function) {
options->target_function = target_function;
}

Просмотреть файл

@ -30,6 +30,9 @@ struct spv_reducer_options_t {
// See spvReducerOptionsSetFailOnValidationError. // See spvReducerOptionsSetFailOnValidationError.
bool fail_on_validation_error; bool fail_on_validation_error;
// See spvReducerOptionsSetTargetFunction.
uint32_t target_function;
}; };
#endif // SOURCE_SPIRV_REDUCER_OPTIONS_H_ #endif // SOURCE_SPIRV_REDUCER_OPTIONS_H_

Просмотреть файл

@ -80,7 +80,7 @@ TEST(ConditionalBranchToSimpleConditionalBranchTest, Diamond) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(2, ops.size()); ASSERT_EQ(2, ops.size());
@ -125,7 +125,7 @@ TEST(ConditionalBranchToSimpleConditionalBranchTest, Diamond) {
} }
ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
// Start again, and apply the other op. // Start again, and apply the other op.
@ -134,7 +134,7 @@ TEST(ConditionalBranchToSimpleConditionalBranchTest, Diamond) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(2, ops.size()); ASSERT_EQ(2, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -225,7 +225,7 @@ TEST(ConditionalBranchToSimpleConditionalBranchTest, AlreadySimplified) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -276,7 +276,7 @@ TEST(ConditionalBranchToSimpleConditionalBranchTest, DontRemoveBackEdge) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -313,7 +313,7 @@ TEST(ConditionalBranchToSimpleConditionalBranchTest, DontRemoveBackEdge) {
CheckEqual(kEnv, after, context.get()); CheckEqual(kEnv, after, context.get());
ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -361,7 +361,7 @@ TEST(ConditionalBranchToSimpleConditionalBranchTest,
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -396,7 +396,7 @@ TEST(ConditionalBranchToSimpleConditionalBranchTest,
CheckEqual(kEnv, after, context.get()); CheckEqual(kEnv, after, context.get());
ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -453,7 +453,7 @@ TEST(ConditionalBranchToSimpleConditionalBranchTest, BackEdgeUnreachable) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -492,7 +492,7 @@ TEST(ConditionalBranchToSimpleConditionalBranchTest, BackEdgeUnreachable) {
CheckEqual(kEnv, after, context.get()); CheckEqual(kEnv, after, context.get());
ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }

Просмотреть файл

@ -66,7 +66,7 @@ TEST(MergeBlocksReductionPassTest, BasicCheck) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
const auto ops = const auto ops =
MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities( MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(5, ops.size()); ASSERT_EQ(5, ops.size());
// Try order 3, 0, 2, 4, 1 // Try order 3, 0, 2, 4, 1
@ -356,7 +356,7 @@ TEST(MergeBlocksReductionPassTest, Loops) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
const auto ops = const auto ops =
MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities( MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(11, ops.size()); ASSERT_EQ(11, ops.size());
for (auto& ri : ops) { for (auto& ri : ops) {
@ -474,7 +474,7 @@ TEST(MergeBlocksReductionPassTest, MergeWithOpPhi) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
const auto ops = const auto ops =
MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities( MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -556,7 +556,7 @@ void MergeBlocksReductionPassTest_LoopReturn_Helper(bool reverse) {
ASSERT_NE(context.get(), nullptr); ASSERT_NE(context.get(), nullptr);
auto opportunities = auto opportunities =
MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities( MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
// A->B and B->C // A->B and B->C
ASSERT_EQ(opportunities.size(), 2); ASSERT_EQ(opportunities.size(), 2);

Просмотреть файл

@ -101,7 +101,7 @@ TEST(OperandToConstantReductionPassTest, BasicCheck) {
BuildModule(env, consumer, original, kReduceAssembleOption); BuildModule(env, consumer, original, kReduceAssembleOption);
const auto ops = const auto ops =
OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(17, ops.size()); ASSERT_EQ(17, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
ops[0]->TryToApply(); ops[0]->TryToApply();
@ -151,10 +151,158 @@ TEST(OperandToConstantReductionPassTest, WithCalledFunction) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
const auto ops = const auto ops =
OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
TEST(OperandToConstantReductionPassTest, TargetSpecificFunction) {
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%8 = OpTypeFunction %6 %7
%17 = OpConstant %6 1
%20 = OpConstant %6 2
%23 = OpConstant %6 0
%24 = OpTypeBool
%35 = OpConstant %6 3
%53 = OpConstant %6 10
%4 = OpFunction %2 None %3
%5 = OpLabel
%65 = OpVariable %7 Function
%68 = OpVariable %7 Function
%73 = OpVariable %7 Function
OpStore %65 %35
%66 = OpLoad %6 %65
%67 = OpIAdd %6 %66 %17
OpStore %65 %67
%69 = OpLoad %6 %65
OpStore %68 %69
%70 = OpFunctionCall %6 %13 %68
%71 = OpLoad %6 %65
%72 = OpIAdd %6 %71 %70
OpStore %65 %72
%74 = OpLoad %6 %65
OpStore %73 %74
%75 = OpFunctionCall %6 %10 %73
%76 = OpLoad %6 %65
%77 = OpIAdd %6 %76 %75
OpStore %65 %77
OpReturn
OpFunctionEnd
%10 = OpFunction %6 None %8
%9 = OpFunctionParameter %7
%11 = OpLabel
%15 = OpVariable %7 Function
%16 = OpLoad %6 %9
%18 = OpIAdd %6 %16 %17
OpStore %15 %18
%19 = OpLoad %6 %15
%21 = OpIAdd %6 %19 %20
OpStore %15 %21
%22 = OpLoad %6 %15
%25 = OpSGreaterThan %24 %22 %23
OpSelectionMerge %27 None
OpBranchConditional %25 %26 %27
%26 = OpLabel
%28 = OpLoad %6 %9
OpReturnValue %28
%27 = OpLabel
%30 = OpLoad %6 %9
%31 = OpIAdd %6 %30 %17
OpReturnValue %31
OpFunctionEnd
%13 = OpFunction %6 None %8
%12 = OpFunctionParameter %7
%14 = OpLabel
%41 = OpVariable %7 Function
%46 = OpVariable %7 Function
%55 = OpVariable %7 Function
%34 = OpLoad %6 %12
%36 = OpIEqual %24 %34 %35
OpSelectionMerge %38 None
OpBranchConditional %36 %37 %38
%37 = OpLabel
%39 = OpLoad %6 %12
%40 = OpIMul %6 %20 %39
OpStore %41 %40
%42 = OpFunctionCall %6 %10 %41
OpReturnValue %42
%38 = OpLabel
%44 = OpLoad %6 %12
%45 = OpIAdd %6 %44 %17
OpStore %12 %45
OpStore %46 %23
OpBranch %47
%47 = OpLabel
OpLoopMerge %49 %50 None
OpBranch %51
%51 = OpLabel
%52 = OpLoad %6 %46
%54 = OpSLessThan %24 %52 %53
OpBranchConditional %54 %48 %49
%48 = OpLabel
%56 = OpLoad %6 %12
OpStore %55 %56
%57 = OpFunctionCall %6 %10 %55
%58 = OpLoad %6 %12
%59 = OpIAdd %6 %58 %57
OpStore %12 %59
OpBranch %50
%50 = OpLabel
%60 = OpLoad %6 %46
%61 = OpIAdd %6 %60 %17
OpStore %46 %61
OpBranch %47
%49 = OpLabel
%62 = OpLoad %6 %12
OpReturnValue %62
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context =
BuildModule(env, consumer, shader, kReduceAssembleOption);
// Targeting all functions, there are quite a few opportunities. To avoid
// making the test too sensitive, we check that there are more than a number
// somewhat lower than the real number.
const auto all_ops =
OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
context.get(), 0);
ASSERT_TRUE(all_ops.size() > 100);
// Targeting individual functions, there are fewer opportunities. Again, we
// avoid checking against an exact number so that the test is not too
// sensitive.
const auto ops_for_function_4 =
OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
context.get(), 4);
const auto ops_for_function_10 =
OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
context.get(), 10);
const auto ops_for_function_13 =
OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
context.get(), 13);
ASSERT_TRUE(ops_for_function_4.size() < 60);
ASSERT_TRUE(ops_for_function_10.size() < 50);
ASSERT_TRUE(ops_for_function_13.size() < 80);
// The total number of opportunities should be the sum of the per-function
// opportunities.
ASSERT_EQ(all_ops.size(), ops_for_function_4.size() +
ops_for_function_10.size() +
ops_for_function_13.size());
}
} // namespace } // namespace
} // namespace reduce } // namespace reduce
} // namespace spvtools } // namespace spvtools

Просмотреть файл

@ -56,7 +56,7 @@ TEST(OperandToDominatingIdReductionPassTest, BasicCheck) {
const auto context = const auto context =
BuildModule(env, consumer, original, kReduceAssembleOption); BuildModule(env, consumer, original, kReduceAssembleOption);
const auto ops = OperandToDominatingIdReductionOpportunityFinder() const auto ops = OperandToDominatingIdReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(10, ops.size()); ASSERT_EQ(10, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
ops[0]->TryToApply(); ops[0]->TryToApply();

Просмотреть файл

@ -167,7 +167,7 @@ TEST(OperandToUndefReductionPassTest, BasicCheck) {
BuildModule(env, consumer, original, kReduceAssembleOption); BuildModule(env, consumer, original, kReduceAssembleOption);
const auto ops = const auto ops =
OperandToUndefReductionOpportunityFinder().GetAvailableOpportunities( OperandToUndefReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(10, ops.size()); ASSERT_EQ(10, ops.size());
@ -221,7 +221,7 @@ TEST(OperandToUndefReductionPassTest, WithCalledFunction) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
const auto ops = const auto ops =
OperandToUndefReductionOpportunityFinder().GetAvailableOpportunities( OperandToUndefReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }

Просмотреть файл

@ -14,6 +14,8 @@
#include "source/reduce/reducer.h" #include "source/reduce/reducer.h"
#include <unordered_map>
#include "source/opt/build_module.h" #include "source/opt/build_module.h"
#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" #include "source/reduce/operand_to_const_reduction_opportunity_finder.h"
#include "source/reduce/remove_unused_instruction_reduction_opportunity_finder.h" #include "source/reduce/remove_unused_instruction_reduction_opportunity_finder.h"
@ -23,11 +25,8 @@ namespace spvtools {
namespace reduce { namespace reduce {
namespace { namespace {
using opt::BasicBlock;
using opt::IRContext;
const spv_target_env kEnv = SPV_ENV_UNIVERSAL_1_3; const spv_target_env kEnv = SPV_ENV_UNIVERSAL_1_3;
const MessageConsumer kMessageConsumer = CLIMessageConsumer; const MessageConsumer kMessageConsumer = NopDiagnostic;
// This changes 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 // binary is interesting, until some limit is reached after which the binary is
@ -42,7 +41,7 @@ class PingPongInteresting {
always_interesting_after_(always_interesting_after), always_interesting_after_(always_interesting_after),
count_(0) {} count_(0) {}
bool IsInteresting(const std::vector<uint32_t>&) { bool IsInteresting() {
bool result; bool result;
if (count_ > always_interesting_after_) { if (count_ > always_interesting_after_) {
result = true; result = true;
@ -194,10 +193,10 @@ TEST(ReducerTest, ExprToConstantAndRemoveUnreferenced) {
Reducer reducer(kEnv); Reducer reducer(kEnv);
PingPongInteresting ping_pong_interesting(10); PingPongInteresting ping_pong_interesting(10);
reducer.SetMessageConsumer(NopDiagnostic); reducer.SetMessageConsumer(kMessageConsumer);
reducer.SetInterestingnessFunction( reducer.SetInterestingnessFunction(
[&](const std::vector<uint32_t>& binary, uint32_t) -> bool { [&ping_pong_interesting](const std::vector<uint32_t>&, uint32_t) -> bool {
return ping_pong_interesting.IsInteresting(binary); return ping_pong_interesting.IsInteresting();
}); });
reducer.AddReductionPass( reducer.AddReductionPass(
MakeUnique<RemoveUnusedInstructionReductionOpportunityFinder>(false)); MakeUnique<RemoveUnusedInstructionReductionOpportunityFinder>(false));
@ -230,13 +229,14 @@ bool InterestingWhileOpcodeExists(const std::vector<uint32_t>& binary,
DumpShader(binary, ss.str().c_str()); DumpShader(binary, ss.str().c_str());
} }
std::unique_ptr<IRContext> context = std::unique_ptr<opt::IRContext> context =
BuildModule(kEnv, kMessageConsumer, binary.data(), binary.size()); BuildModule(kEnv, kMessageConsumer, binary.data(), binary.size());
assert(context); assert(context);
bool interesting = false; bool interesting = false;
for (auto& function : *context->module()) { for (auto& function : *context->module()) {
context->cfg()->ForEachBlockInPostOrder( context->cfg()->ForEachBlockInPostOrder(
&*function.begin(), [opcode, &interesting](BasicBlock* block) -> void { &*function.begin(),
[opcode, &interesting](opt::BasicBlock* block) -> void {
for (auto& inst : *block) { for (auto& inst : *block) {
if (inst.opcode() == opcode) { if (inst.opcode() == opcode) {
interesting = true; interesting = true;
@ -369,6 +369,147 @@ const std::string kShaderWithLoopsDivAndMul = R"(
OpFunctionEnd OpFunctionEnd
)"; )";
// The shader below comes from the following GLSL.
// #version 320 es
//
// int baz(int x) {
// int y = x + 1;
// y = y + 2;
// if (y > 0) {
// return x;
// }
// return x + 1;
// }
//
// int bar(int a) {
// if (a == 3) {
// return baz(2*a);
// }
// a = a + 1;
// for (int i = 0; i < 10; i++) {
// a += baz(a);
// }
// return a;
// }
//
// void main() {
// int x;
// x = 3;
// x += 1;
// x += bar(x);
// x += baz(x);
// }
const std::string kShaderWithMultipleFunctions = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%8 = OpTypeFunction %6 %7
%17 = OpConstant %6 1
%20 = OpConstant %6 2
%23 = OpConstant %6 0
%24 = OpTypeBool
%35 = OpConstant %6 3
%53 = OpConstant %6 10
%4 = OpFunction %2 None %3
%5 = OpLabel
%65 = OpVariable %7 Function
%68 = OpVariable %7 Function
%73 = OpVariable %7 Function
OpStore %65 %35
%66 = OpLoad %6 %65
%67 = OpIAdd %6 %66 %17
OpStore %65 %67
%69 = OpLoad %6 %65
OpStore %68 %69
%70 = OpFunctionCall %6 %13 %68
%71 = OpLoad %6 %65
%72 = OpIAdd %6 %71 %70
OpStore %65 %72
%74 = OpLoad %6 %65
OpStore %73 %74
%75 = OpFunctionCall %6 %10 %73
%76 = OpLoad %6 %65
%77 = OpIAdd %6 %76 %75
OpStore %65 %77
OpReturn
OpFunctionEnd
%10 = OpFunction %6 None %8
%9 = OpFunctionParameter %7
%11 = OpLabel
%15 = OpVariable %7 Function
%16 = OpLoad %6 %9
%18 = OpIAdd %6 %16 %17
OpStore %15 %18
%19 = OpLoad %6 %15
%21 = OpIAdd %6 %19 %20
OpStore %15 %21
%22 = OpLoad %6 %15
%25 = OpSGreaterThan %24 %22 %23
OpSelectionMerge %27 None
OpBranchConditional %25 %26 %27
%26 = OpLabel
%28 = OpLoad %6 %9
OpReturnValue %28
%27 = OpLabel
%30 = OpLoad %6 %9
%31 = OpIAdd %6 %30 %17
OpReturnValue %31
OpFunctionEnd
%13 = OpFunction %6 None %8
%12 = OpFunctionParameter %7
%14 = OpLabel
%41 = OpVariable %7 Function
%46 = OpVariable %7 Function
%55 = OpVariable %7 Function
%34 = OpLoad %6 %12
%36 = OpIEqual %24 %34 %35
OpSelectionMerge %38 None
OpBranchConditional %36 %37 %38
%37 = OpLabel
%39 = OpLoad %6 %12
%40 = OpIMul %6 %20 %39
OpStore %41 %40
%42 = OpFunctionCall %6 %10 %41
OpReturnValue %42
%38 = OpLabel
%44 = OpLoad %6 %12
%45 = OpIAdd %6 %44 %17
OpStore %12 %45
OpStore %46 %23
OpBranch %47
%47 = OpLabel
OpLoopMerge %49 %50 None
OpBranch %51
%51 = OpLabel
%52 = OpLoad %6 %46
%54 = OpSLessThan %24 %52 %53
OpBranchConditional %54 %48 %49
%48 = OpLabel
%56 = OpLoad %6 %12
OpStore %55 %56
%57 = OpFunctionCall %6 %10 %55
%58 = OpLoad %6 %12
%59 = OpIAdd %6 %58 %57
OpStore %12 %59
OpBranch %50
%50 = OpLabel
%60 = OpLoad %6 %46
%61 = OpIAdd %6 %60 %17
OpStore %46 %61
OpBranch %47
%49 = OpLabel
%62 = OpLoad %6 %12
OpReturnValue %62
OpFunctionEnd
)";
TEST(ReducerTest, ShaderReduceWhileMulReachable) { TEST(ReducerTest, ShaderReduceWhileMulReachable) {
Reducer reducer(kEnv); Reducer reducer(kEnv);
@ -417,6 +558,70 @@ TEST(ReducerTest, ShaderReduceWhileDivReachable) {
ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete); ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete);
} }
// Computes an instruction count for each function in the module represented by
// |binary|.
std::unordered_map<uint32_t, uint32_t> GetFunctionInstructionCount(
const std::vector<uint32_t>& binary) {
std::unique_ptr<opt::IRContext> context =
BuildModule(kEnv, kMessageConsumer, binary.data(), binary.size());
assert(context != nullptr && "Failed to build module.");
std::unordered_map<uint32_t, uint32_t> result;
for (auto& function : *context->module()) {
uint32_t& count = result[function.result_id()] = 0;
function.ForEachInst([&count](opt::Instruction*) { count++; });
}
return result;
}
TEST(ReducerTest, SingleFunctionReduction) {
Reducer reducer(kEnv);
PingPongInteresting ping_pong_interesting(4);
reducer.SetInterestingnessFunction(
[&ping_pong_interesting](const std::vector<uint32_t>&, uint32_t) -> bool {
return ping_pong_interesting.IsInteresting();
});
reducer.AddDefaultReductionPasses();
reducer.SetMessageConsumer(kMessageConsumer);
std::vector<uint32_t> binary_in;
SpirvTools t(kEnv);
ASSERT_TRUE(t.Assemble(kShaderWithMultipleFunctions, &binary_in,
kReduceAssembleOption));
auto original_instruction_count = GetFunctionInstructionCount(binary_in);
std::vector<uint32_t> binary_out;
spvtools::ReducerOptions reducer_options;
reducer_options.set_step_limit(500);
reducer_options.set_fail_on_validation_error(true);
// Instruct the reducer to only target function 13.
reducer_options.set_target_function(13);
spvtools::ValidatorOptions validator_options;
Reducer::ReductionResultStatus status = reducer.Run(
std::move(binary_in), &binary_out, reducer_options, validator_options);
ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete);
auto final_instruction_count = GetFunctionInstructionCount(binary_out);
// Nothing should have been removed from these functions.
ASSERT_EQ(original_instruction_count.at(4), final_instruction_count.at(4));
ASSERT_EQ(original_instruction_count.at(10), final_instruction_count.at(10));
// Function 13 should have been reduced to these five instructions:
// OpFunction
// OpFunctionParameter
// OpLabel
// OpReturnValue
// OpFunctionEnd
ASSERT_EQ(5, final_instruction_count.at(13));
}
} // namespace } // namespace
} // namespace reduce } // namespace reduce
} // namespace spvtools } // namespace spvtools

Просмотреть файл

@ -66,7 +66,7 @@ TEST(RemoveBlockReductionPassTest, BasicCheck) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
const auto ops = const auto ops =
RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(2, ops.size()); ASSERT_EQ(2, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -181,7 +181,7 @@ TEST(RemoveBlockReductionPassTest, UnreachableContinueAndMerge) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
const auto ops = const auto ops =
RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -209,7 +209,7 @@ TEST(RemoveBlockReductionPassTest, OneBlock) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
const auto ops = const auto ops =
RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -247,7 +247,7 @@ TEST(RemoveBlockReductionPassTest, UnreachableBlocksWithOutsideIdUses) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
const auto ops = const auto ops =
RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -287,7 +287,7 @@ TEST(RemoveBlockReductionPassTest, UnreachableBlocksWithInsideIdUses) {
const auto context = const auto context =
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
auto ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( auto ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -323,7 +323,7 @@ TEST(RemoveBlockReductionPassTest, UnreachableBlocksWithInsideIdUses) {
// removed. // removed.
ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());

Просмотреть файл

@ -67,7 +67,7 @@ TEST(RemoveFunctionTest, BasicCheck) {
auto ops = auto ops =
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -97,7 +97,7 @@ TEST(RemoveFunctionTest, BasicCheck) {
CheckEqual(env, after_first, context.get()); CheckEqual(env, after_first, context.get());
ops = RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( ops = RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -156,7 +156,7 @@ TEST(RemoveFunctionTest, NothingToRemove) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
auto ops = auto ops =
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -193,7 +193,7 @@ TEST(RemoveFunctionTest, TwoRemovableFunctions) {
auto ops = auto ops =
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(2, ops.size()); ASSERT_EQ(2, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -254,7 +254,7 @@ TEST(RemoveFunctionTest, NoRemovalsDueToOpName) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
auto ops = auto ops =
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -286,7 +286,7 @@ TEST(RemoveFunctionTest, NoRemovalDueToLinkageDecoration) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
auto ops = auto ops =
RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }

Просмотреть файл

@ -62,7 +62,7 @@ TEST(RemoveSelectionTest, OpportunityBecauseSameTargetBlock) {
auto ops = auto ops =
RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -96,7 +96,7 @@ TEST(RemoveSelectionTest, OpportunityBecauseSameTargetBlock) {
CheckEqual(env, after, context.get()); CheckEqual(env, after, context.get());
ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -136,7 +136,7 @@ TEST(RemoveSelectionTest, OpportunityBecauseSameTargetBlockMerge) {
auto ops = auto ops =
RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -168,7 +168,7 @@ TEST(RemoveSelectionTest, OpportunityBecauseSameTargetBlockMerge) {
CheckEqual(env, after, context.get()); CheckEqual(env, after, context.get());
ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -212,7 +212,7 @@ TEST(RemoveSelectionTest, NoOpportunityBecauseDifferentTargetBlocksOneMerge) {
auto ops = auto ops =
RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -258,7 +258,7 @@ TEST(RemoveSelectionTest, NoOpportunityBecauseDifferentTargetBlocks) {
auto ops = auto ops =
RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -306,7 +306,7 @@ TEST(RemoveSelectionTest, NoOpportunityBecauseMergeUsed) {
auto ops = auto ops =
RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -384,7 +384,7 @@ TEST(RemoveSelectionTest, OpportunityBecauseLoopMergeUsed) {
auto ops = auto ops =
RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -427,7 +427,7 @@ TEST(RemoveSelectionTest, OpportunityBecauseLoopMergeUsed) {
CheckEqual(env, after, context.get()); CheckEqual(env, after, context.get());
ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -505,7 +505,7 @@ TEST(RemoveSelectionTest, OpportunityBecauseLoopContinueUsed) {
auto ops = auto ops =
RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -548,7 +548,7 @@ TEST(RemoveSelectionTest, OpportunityBecauseLoopContinueUsed) {
CheckEqual(env, after, context.get()); CheckEqual(env, after, context.get());
ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
context.get()); context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }

Просмотреть файл

@ -72,7 +72,7 @@ TEST(RemoveUnusedInstructionReductionPassTest, RemoveStores) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = finder.GetAvailableOpportunities(context.get()); auto ops = finder.GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(10, ops.size()); ASSERT_EQ(10, ops.size());
@ -108,7 +108,7 @@ TEST(RemoveUnusedInstructionReductionPassTest, RemoveStores) {
CheckEqual(kEnv, step_2, context.get()); CheckEqual(kEnv, step_2, context.get());
ops = finder.GetAvailableOpportunities(context.get()); ops = finder.GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(7, ops.size()); ASSERT_EQ(7, ops.size());
@ -137,7 +137,7 @@ TEST(RemoveUnusedInstructionReductionPassTest, RemoveStores) {
CheckEqual(kEnv, step_3, context.get()); CheckEqual(kEnv, step_3, context.get());
ops = finder.GetAvailableOpportunities(context.get()); ops = finder.GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -165,7 +165,7 @@ TEST(RemoveUnusedInstructionReductionPassTest, RemoveStores) {
CheckEqual(kEnv, step_4, context.get()); CheckEqual(kEnv, step_4, context.get());
ops = finder.GetAvailableOpportunities(context.get()); ops = finder.GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -192,7 +192,7 @@ TEST(RemoveUnusedInstructionReductionPassTest, RemoveStores) {
CheckEqual(kEnv, step_5, context.get()); CheckEqual(kEnv, step_5, context.get());
ops = finder.GetAvailableOpportunities(context.get()); ops = finder.GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -218,7 +218,7 @@ TEST(RemoveUnusedInstructionReductionPassTest, RemoveStores) {
CheckEqual(kEnv, step_6, context.get()); CheckEqual(kEnv, step_6, context.get());
ops = finder.GetAvailableOpportunities(context.get()); ops = finder.GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -258,7 +258,7 @@ TEST(RemoveUnusedInstructionReductionPassTest, Referenced) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = finder.GetAvailableOpportunities(context.get()); auto ops = finder.GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(6, ops.size()); ASSERT_EQ(6, ops.size());
@ -289,7 +289,7 @@ TEST(RemoveUnusedInstructionReductionPassTest, Referenced) {
CheckEqual(kEnv, after, context.get()); CheckEqual(kEnv, after, context.get());
ops = finder.GetAvailableOpportunities(context.get()); ops = finder.GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(3, ops.size()); ASSERT_EQ(3, ops.size());
@ -317,7 +317,7 @@ TEST(RemoveUnusedInstructionReductionPassTest, Referenced) {
CheckEqual(kEnv, after_2, context.get()); CheckEqual(kEnv, after_2, context.get());
ops = finder.GetAvailableOpportunities(context.get()); ops = finder.GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -344,7 +344,7 @@ TEST(RemoveUnusedInstructionReductionPassTest, Referenced) {
CheckEqual(kEnv, after_3, context.get()); CheckEqual(kEnv, after_3, context.get());
ops = finder.GetAvailableOpportunities(context.get()); ops = finder.GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -370,7 +370,7 @@ TEST(RemoveUnusedInstructionReductionPassTest, Referenced) {
CheckEqual(kEnv, after_4, context.get()); CheckEqual(kEnv, after_4, context.get());
ops = finder.GetAvailableOpportunities(context.get()); ops = finder.GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -438,7 +438,7 @@ TEST(RemoveUnusedResourceVariableTest, RemoveUnusedResourceVariables) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
auto ops = RemoveUnusedInstructionReductionOpportunityFinder(true) auto ops = RemoveUnusedInstructionReductionOpportunityFinder(true)
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(7, ops.size()); ASSERT_EQ(7, ops.size());
for (auto& op : ops) { for (auto& op : ops) {
@ -487,7 +487,7 @@ TEST(RemoveUnusedResourceVariableTest, RemoveUnusedResourceVariables) {
CheckEqual(env, expected_1, context.get()); CheckEqual(env, expected_1, context.get());
ops = RemoveUnusedInstructionReductionOpportunityFinder(true) ops = RemoveUnusedInstructionReductionOpportunityFinder(true)
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(6, ops.size()); ASSERT_EQ(6, ops.size());
for (auto& op : ops) { for (auto& op : ops) {
@ -530,7 +530,7 @@ TEST(RemoveUnusedResourceVariableTest, RemoveUnusedResourceVariables) {
CheckEqual(env, expected_2, context.get()); CheckEqual(env, expected_2, context.get());
ops = RemoveUnusedInstructionReductionOpportunityFinder(true) ops = RemoveUnusedInstructionReductionOpportunityFinder(true)
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(6, ops.size()); ASSERT_EQ(6, ops.size());
for (auto& op : ops) { for (auto& op : ops) {

Просмотреть файл

@ -61,7 +61,7 @@ TEST(RemoveUnusedStructMemberTest, RemoveOneMember) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
auto ops = RemoveUnusedStructMemberReductionOpportunityFinder() auto ops = RemoveUnusedStructMemberReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
ops[0]->TryToApply(); ops[0]->TryToApply();
@ -143,7 +143,7 @@ TEST(RemoveUnusedStructMemberTest, RemoveUniformBufferMember) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
auto ops = RemoveUnusedStructMemberReductionOpportunityFinder() auto ops = RemoveUnusedStructMemberReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
ops[0]->TryToApply(); ops[0]->TryToApply();
@ -229,7 +229,7 @@ TEST(RemoveUnusedStructMemberTest, DoNotRemoveNamedMemberRemoveOneMember) {
BuildModule(env, consumer, shader, kReduceAssembleOption); BuildModule(env, consumer, shader, kReduceAssembleOption);
auto ops = RemoveUnusedStructMemberReductionOpportunityFinder() auto ops = RemoveUnusedStructMemberReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }

Просмотреть файл

@ -73,7 +73,7 @@ TEST(SimpleConditionalBranchToBranchTest, Diamond) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = SimpleConditionalBranchToBranchOpportunityFinder() auto ops = SimpleConditionalBranchToBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -122,7 +122,7 @@ TEST(SimpleConditionalBranchToBranchTest, DiamondNoSelection) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = SimpleConditionalBranchToBranchOpportunityFinder() auto ops = SimpleConditionalBranchToBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -161,7 +161,7 @@ TEST(SimpleConditionalBranchToBranchTest, DiamondNoSelection) {
CheckEqual(kEnv, after, context.get()); CheckEqual(kEnv, after, context.get());
ops = SimpleConditionalBranchToBranchOpportunityFinder() ops = SimpleConditionalBranchToBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -217,7 +217,7 @@ TEST(SimpleConditionalBranchToBranchTest, ConditionalBranchesButNotSimple) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = SimpleConditionalBranchToBranchOpportunityFinder() auto ops = SimpleConditionalBranchToBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -266,7 +266,7 @@ TEST(SimpleConditionalBranchToBranchTest, SimplifyBackEdge) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = SimpleConditionalBranchToBranchOpportunityFinder() auto ops = SimpleConditionalBranchToBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -303,7 +303,7 @@ TEST(SimpleConditionalBranchToBranchTest, SimplifyBackEdge) {
CheckEqual(kEnv, after, context.get()); CheckEqual(kEnv, after, context.get());
ops = SimpleConditionalBranchToBranchOpportunityFinder() ops = SimpleConditionalBranchToBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -349,7 +349,7 @@ TEST(SimpleConditionalBranchToBranchTest,
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = SimpleConditionalBranchToBranchOpportunityFinder() auto ops = SimpleConditionalBranchToBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -384,7 +384,7 @@ TEST(SimpleConditionalBranchToBranchTest,
CheckEqual(kEnv, after, context.get()); CheckEqual(kEnv, after, context.get());
ops = SimpleConditionalBranchToBranchOpportunityFinder() ops = SimpleConditionalBranchToBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -438,7 +438,7 @@ TEST(SimpleConditionalBranchToBranchTest, BackEdgeUnreachable) {
CheckValid(kEnv, context.get()); CheckValid(kEnv, context.get());
auto ops = SimpleConditionalBranchToBranchOpportunityFinder() auto ops = SimpleConditionalBranchToBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
@ -477,7 +477,7 @@ TEST(SimpleConditionalBranchToBranchTest, BackEdgeUnreachable) {
CheckEqual(kEnv, after, context.get()); CheckEqual(kEnv, after, context.get());
ops = SimpleConditionalBranchToBranchOpportunityFinder() ops = SimpleConditionalBranchToBranchOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }

Просмотреть файл

@ -65,7 +65,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader1) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -211,7 +211,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader2) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(4, ops.size()); ASSERT_EQ(4, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -680,7 +680,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader3) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }
@ -758,7 +758,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader4) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
// Initially there are two opportunities. // Initially there are two opportunities.
ASSERT_EQ(2, ops.size()); ASSERT_EQ(2, ops.size());
@ -881,7 +881,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, ConditionalBreak1) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -956,7 +956,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, ConditionalBreak2) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -1024,7 +1024,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, UnconditionalBreak) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -1224,7 +1224,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, Complex) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(2, ops.size()); ASSERT_EQ(2, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -1691,7 +1691,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, ComplexOptimized) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(2, ops.size()); ASSERT_EQ(2, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -2008,7 +2008,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, DominanceIssue) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -2156,7 +2156,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, AccessChainIssue) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -2313,7 +2313,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, DominanceAndPhiIssue) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -2421,7 +2421,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, OpLineBeforeOpPhi) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -2511,7 +2511,7 @@ TEST(StructuredLoopToSelectionReductionPassTest,
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
// There should be no opportunities. // There should be no opportunities.
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
@ -2555,7 +2555,7 @@ TEST(StructuredLoopToSelectionReductionPassTest,
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
// There should be no opportunities. // There should be no opportunities.
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
@ -2595,7 +2595,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, ContinueTargetIsSwitchTarget) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -2670,7 +2670,7 @@ TEST(StructuredLoopToSelectionReductionPassTest,
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -2733,7 +2733,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopBranchesStraightToMerge) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -2790,7 +2790,7 @@ TEST(StructuredLoopToSelectionReductionPassTest,
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -2874,7 +2874,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, MultipleAccessChains) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -2970,7 +2970,7 @@ TEST(StructuredLoopToSelectionReductionPassTest,
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(2, ops.size()); ASSERT_EQ(2, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -3089,7 +3089,7 @@ TEST(StructuredLoopToSelectionReductionPassTest,
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(2, ops.size()); ASSERT_EQ(2, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -3209,7 +3209,7 @@ TEST(StructuredLoopToSelectionReductionPassTest,
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
auto ops = StructuredLoopToSelectionReductionOpportunityFinder() auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
// We cannot transform the inner loop due to its header jumping straight to // We cannot transform the inner loop due to its header jumping straight to
// the outer loop merge (the inner loop's merge does not post-dominate its // the outer loop merge (the inner loop's merge does not post-dominate its
@ -3254,7 +3254,7 @@ TEST(StructuredLoopToSelectionReductionPassTest,
// Now look again for more opportunities. // Now look again for more opportunities.
ops = StructuredLoopToSelectionReductionOpportunityFinder() ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
// What was the inner loop should now be transformable, as the jump to the // What was the inner loop should now be transformable, as the jump to the
// outer loop's merge has been redirected. // outer loop's merge has been redirected.
@ -3422,7 +3422,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, LongAccessChains) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
auto ops = StructuredLoopToSelectionReductionOpportunityFinder() auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -3513,7 +3513,7 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShaderWithOpDecorate) {
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(1, ops.size()); ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds()); ASSERT_TRUE(ops[0]->PreconditionHolds());
@ -3619,7 +3619,7 @@ TEST(StructuredLoopToSelectionReductionPassTest,
const auto env = SPV_ENV_UNIVERSAL_1_3; const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
.GetAvailableOpportunities(context.get()); .GetAvailableOpportunities(context.get(), 0);
ASSERT_EQ(0, ops.size()); ASSERT_EQ(0, ops.size());
} }

Просмотреть файл

@ -22,8 +22,8 @@ namespace reduce {
namespace { namespace {
using opt::Function; using opt::Function;
using opt::Instruction;
using opt::IRContext; using opt::IRContext;
using opt::Instruction;
// A reduction opportunity finder that finds opportunities to remove global // A reduction opportunity finder that finds opportunities to remove global
// values regardless of whether they are referenced. This is very likely to make // values regardless of whether they are referenced. This is very likely to make
@ -43,7 +43,7 @@ class BlindlyRemoveGlobalValuesReductionOpportunityFinder
// referenced (directly or indirectly) from elsewhere in the module, each such // referenced (directly or indirectly) from elsewhere in the module, each such
// opportunity will make the module invalid. // opportunity will make the module invalid.
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
IRContext* context) const final { IRContext* context, uint32_t /*unused*/) const final {
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
for (auto& inst : context->module()->types_values()) { for (auto& inst : context->module()->types_values()) {
if (inst.HasResultId()) { if (inst.HasResultId()) {
@ -101,7 +101,7 @@ class OpVariableDuplicatorReductionOpportunityFinder
} }
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
IRContext* context) const final { IRContext* context, uint32_t /*unused*/) const final {
std::vector<std::unique_ptr<ReductionOpportunity>> result; std::vector<std::unique_ptr<ReductionOpportunity>> result;
for (auto& function : *context->module()) { for (auto& function : *context->module()) {
Instruction* first_instruction = &*function.begin()[0].begin(); Instruction* first_instruction = &*function.begin()[0].begin();

Просмотреть файл

@ -16,6 +16,7 @@
#include <cerrno> #include <cerrno>
#include <cstring> #include <cstring>
#include <functional> #include <functional>
#include <sstream>
#include "source/opt/build_module.h" #include "source/opt/build_module.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
@ -102,6 +103,14 @@ Options (in lexicographical order):
--step-limit= --step-limit=
32-bit unsigned integer specifying maximum number of steps the 32-bit unsigned integer specifying maximum number of steps the
reducer will take before giving up. reducer will take before giving up.
--target-function=
32-bit unsigned integer specifying the id of a function in the
input module. The reducer will restrict attention to this
function, and will not make changes to other functions or to
instructions outside of functions, except that some global
instructions may be added in support of reducing the target
function. If 0 is specified (the default) then all functions are
reduced.
--temp-file-prefix= --temp-file-prefix=
Specifies a temporary file prefix that will be used to output Specifies a temporary file prefix that will be used to output
temporary shader files during reduction. A number and .spv temporary shader files during reduction. A number and .spv
@ -169,6 +178,15 @@ ReduceStatus ParseFlags(int argc, const char** argv,
static_cast<uint32_t>(strtol(split_flag.second.c_str(), &end, 10)); static_cast<uint32_t>(strtol(split_flag.second.c_str(), &end, 10));
assert(end != split_flag.second.c_str() && errno == 0); assert(end != split_flag.second.c_str() && errno == 0);
reducer_options->set_step_limit(step_limit); reducer_options->set_step_limit(step_limit);
} else if (0 == strncmp(cur_arg, "--target-function=",
sizeof("--target-function=") - 1)) {
const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg);
char* end = nullptr;
errno = 0;
const auto target_function =
static_cast<uint32_t>(strtol(split_flag.second.c_str(), &end, 10));
assert(end != split_flag.second.c_str() && errno == 0);
reducer_options->set_target_function(target_function);
} else if (0 == strcmp(cur_arg, "--fail-on-validation-error")) { } else if (0 == strcmp(cur_arg, "--fail-on-validation-error")) {
reducer_options->set_fail_on_validation_error(true); reducer_options->set_fail_on_validation_error(true);
} else if (0 == strcmp(cur_arg, "--before-hlsl-legalization")) { } else if (0 == strcmp(cur_arg, "--before-hlsl-legalization")) {
@ -304,6 +322,29 @@ int main(int argc, const char** argv) {
return 1; return 1;
} }
const uint32_t target_function = (*reducer_options).target_function;
if (target_function) {
// A target function was specified; check that it exists.
std::unique_ptr<spvtools::opt::IRContext> context = spvtools::BuildModule(
kDefaultEnvironment, spvtools::utils::CLIMessageConsumer,
binary_in.data(), binary_in.size());
bool found_target_function = false;
for (auto& function : *context->module()) {
if (function.result_id() == target_function) {
found_target_function = true;
break;
}
}
if (!found_target_function) {
std::stringstream strstr;
strstr << "Target function with id " << target_function
<< " was requested, but not found in the module; stopping.";
spvtools::utils::CLIMessageConsumer(SPV_MSG_ERROR, nullptr, {},
strstr.str().c_str());
return 1;
}
}
std::vector<uint32_t> binary_out; std::vector<uint32_t> binary_out;
const auto reduction_status = reducer.Run(std::move(binary_in), &binary_out, const auto reduction_status = reducer.Run(std::move(binary_in), &binary_out,
reducer_options, validator_options); reducer_options, validator_options);