| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- // 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/remove_selection_reduction_opportunity_finder.h"
- #include "source/reduce/remove_selection_reduction_opportunity.h"
- namespace spvtools {
- namespace reduce {
- using opt::BasicBlock;
- using opt::IRContext;
- using opt::Instruction;
- namespace {
- const uint32_t kMergeNodeIndex = 0;
- const uint32_t kContinueNodeIndex = 1;
- } // namespace
- std::string RemoveSelectionReductionOpportunityFinder::GetName() const {
- return "RemoveSelectionReductionOpportunityFinder";
- }
- std::vector<std::unique_ptr<ReductionOpportunity>>
- RemoveSelectionReductionOpportunityFinder::GetAvailableOpportunities(
- IRContext* context) const {
- // 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;
- for (auto& function : *context->module()) {
- for (auto& block : function) {
- if (auto merge_instruction = block.GetMergeInst()) {
- if (merge_instruction->opcode() == SpvOpLoopMerge) {
- uint32_t merge_block_id =
- merge_instruction->GetSingleWordOperand(kMergeNodeIndex);
- uint32_t continue_block_id =
- merge_instruction->GetSingleWordOperand(kContinueNodeIndex);
- merge_and_continue_blocks_from_loops.insert(merge_block_id);
- merge_and_continue_blocks_from_loops.insert(continue_block_id);
- }
- }
- }
- }
- // Return all selection headers where the OpSelectionMergeInstruction can be
- // removed.
- std::vector<std::unique_ptr<ReductionOpportunity>> result;
- for (auto& function : *context->module()) {
- for (auto& block : function) {
- if (auto merge_instruction = block.GetMergeInst()) {
- if (merge_instruction->opcode() == SpvOpSelectionMerge) {
- if (CanOpSelectionMergeBeRemoved(
- context, block, merge_instruction,
- merge_and_continue_blocks_from_loops)) {
- result.push_back(
- MakeUnique<RemoveSelectionReductionOpportunity>(&block));
- }
- }
- }
- }
- }
- return result;
- }
- bool RemoveSelectionReductionOpportunityFinder::CanOpSelectionMergeBeRemoved(
- IRContext* context, const BasicBlock& header_block,
- Instruction* merge_instruction,
- std::unordered_set<uint32_t> merge_and_continue_blocks_from_loops) {
- assert(header_block.GetMergeInst() == merge_instruction &&
- "CanOpSelectionMergeBeRemoved(...): header block and merge "
- "instruction mismatch");
- // The OpSelectionMerge instruction is needed if either of the following are
- // true.
- //
- // 1. The header block has at least two (unique) successors that are not
- // merge or continue blocks of a loop.
- //
- // 2. The predecessors of the merge block are "using" the merge block to avoid
- // divergence. In other words, there exists a predecessor of the merge block
- // that has a successor that is not the merge block of this construct and not
- // a merge or continue block of a loop.
- // 1.
- {
- uint32_t divergent_successor_count = 0;
- std::unordered_set<uint32_t> seen_successors;
- header_block.ForEachSuccessorLabel(
- [&seen_successors, &merge_and_continue_blocks_from_loops,
- &divergent_successor_count](uint32_t successor) {
- // Not already seen.
- if (seen_successors.find(successor) == seen_successors.end()) {
- seen_successors.insert(successor);
- // Not a loop continue or merge.
- if (merge_and_continue_blocks_from_loops.find(successor) ==
- merge_and_continue_blocks_from_loops.end()) {
- ++divergent_successor_count;
- }
- }
- });
- if (divergent_successor_count > 1) {
- return false;
- }
- }
- // 2.
- {
- uint32_t merge_block_id =
- merge_instruction->GetSingleWordOperand(kMergeNodeIndex);
- for (uint32_t predecessor_block_id :
- context->cfg()->preds(merge_block_id)) {
- const BasicBlock* predecessor_block =
- context->cfg()->block(predecessor_block_id);
- assert(predecessor_block);
- bool found_divergent_successor = false;
- predecessor_block->ForEachSuccessorLabel(
- [&found_divergent_successor, merge_block_id,
- &merge_and_continue_blocks_from_loops](uint32_t successor_id) {
- // The successor is not the merge block, nor a loop merge or
- // continue.
- if (successor_id != merge_block_id &&
- merge_and_continue_blocks_from_loops.find(successor_id) ==
- merge_and_continue_blocks_from_loops.end()) {
- found_divergent_successor = true;
- }
- });
- if (found_divergent_successor) {
- return false;
- }
- }
- }
- return true;
- }
- } // namespace reduce
- } // namespace spvtools
|