blob: 3fe61280380fe650858cd5bd30631bc6e19afce0 [file] [log] [blame]
// Copyright (c) 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h"
#include "source/reduce/structured_loop_to_selection_reduction_opportunity.h"
namespace spvtools {
namespace reduce {
namespace {
const uint32_t kMergeNodeIndex = 0;
const uint32_t kContinueNodeIndex = 1;
} // namespace
std::vector<std::unique_ptr<ReductionOpportunity>>
StructuredLoopToSelectionReductionOpportunityFinder::GetAvailableOpportunities(
opt::IRContext* context, uint32_t target_function) const {
std::vector<std::unique_ptr<ReductionOpportunity>> result;
std::set<uint32_t> merge_block_ids;
for (auto* function : GetTargetFunctions(context, target_function)) {
for (auto& block : *function) {
auto merge_block_id = block.MergeBlockIdIfAny();
if (merge_block_id) {
merge_block_ids.insert(merge_block_id);
}
}
}
// Consider each loop construct header in the module.
for (auto* function : GetTargetFunctions(context, target_function)) {
for (auto& block : *function) {
auto loop_merge_inst = block.GetLoopMergeInst();
if (!loop_merge_inst) {
// This is not a loop construct header.
continue;
}
uint32_t continue_block_id =
loop_merge_inst->GetSingleWordOperand(kContinueNodeIndex);
// Check whether the loop construct's continue target is the merge block
// of some structured control flow construct. If it is, we cautiously do
// not consider applying a transformation.
if (merge_block_ids.find(continue_block_id) != merge_block_ids.end()) {
continue;
}
// Check whether the loop header block is also the continue target. If it
// is, we cautiously do not consider applying a transformation.
if (block.id() == continue_block_id) {
continue;
}
// Check whether the loop construct header dominates its merge block.
// If not, the merge block must be unreachable in the control flow graph
// so we cautiously do not consider applying a transformation.
auto merge_block_id =
loop_merge_inst->GetSingleWordInOperand(kMergeNodeIndex);
if (!context->GetDominatorAnalysis(function)->Dominates(block.id(),
merge_block_id)) {
continue;
}
// Check whether the loop construct merge block postdominates the loop
// construct header. If not (e.g. because the loop contains OpReturn,
// OpKill or OpUnreachable), we cautiously do not consider applying
// a transformation.
if (!context->GetPostDominatorAnalysis(function)->Dominates(
merge_block_id, block.id())) {
continue;
}
// We can turn this structured loop into a selection, so add the
// opportunity to do so.
result.push_back(
MakeUnique<StructuredLoopToSelectionReductionOpportunity>(context,
&block));
}
}
return result;
}
std::string StructuredLoopToSelectionReductionOpportunityFinder::GetName()
const {
return "StructuredLoopToSelectionReductionOpportunityFinder";
}
} // namespace reduce
} // namespace spvtools