blob: 93b51a11f6bbcfe28567985cc283aa39f166625f [file] [log] [blame]
// Copyright (c) 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.h"
#include "source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h"
#include "source/reduce/reduction_util.h"
namespace spvtools {
namespace reduce {
std::vector<std::unique_ptr<ReductionOpportunity>>
ConditionalBranchToSimpleConditionalBranchOpportunityFinder::
GetAvailableOpportunities(opt::IRContext* context,
uint32_t target_function) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result;
// Find the opportunities for redirecting all false targets before the
// opportunities for redirecting all true targets because the former
// opportunities disable the latter, and vice versa, and the efficiency of the
// reducer is improved by avoiding contiguous opportunities that disable one
// another.
for (bool redirect_to_true : {true, false}) {
// Consider every relevant function.
for (auto* function : GetTargetFunctions(context, target_function)) {
// Consider every block in the function.
for (auto& block : *function) {
// The terminator must be spv::Op::OpBranchConditional.
opt::Instruction* terminator = block.terminator();
if (terminator->opcode() != spv::Op::OpBranchConditional) {
continue;
}
uint32_t true_block_id =
terminator->GetSingleWordInOperand(kTrueBranchOperandIndex);
uint32_t false_block_id =
terminator->GetSingleWordInOperand(kFalseBranchOperandIndex);
// The conditional branch must not already be simplified.
if (true_block_id == false_block_id) {
continue;
}
// The redirected target must not be a back-edge to a structured loop
// header.
uint32_t redirected_block_id =
redirect_to_true ? false_block_id : true_block_id;
uint32_t containing_loop_header =
context->GetStructuredCFGAnalysis()->ContainingLoop(block.id());
// The structured CFG analysis does not include a loop header as part
// of the loop construct, but we want to include it, so handle this
// special case:
if (block.GetLoopMergeInst() != nullptr) {
containing_loop_header = block.id();
}
if (redirected_block_id == containing_loop_header) {
continue;
}
result.push_back(
MakeUnique<
ConditionalBranchToSimpleConditionalBranchReductionOpportunity>(
context, block.terminator(), redirect_to_true));
}
}
}
return result;
}
std::string
ConditionalBranchToSimpleConditionalBranchOpportunityFinder::GetName() const {
return "ConditionalBranchToSimpleConditionalBranchOpportunityFinder";
}
} // namespace reduce
} // namespace spvtools