1fd4e5da5Sopenharmony_ci// Copyright (c) 2019 Google LLC 2fd4e5da5Sopenharmony_ci// 3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License. 5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at 6fd4e5da5Sopenharmony_ci// 7fd4e5da5Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8fd4e5da5Sopenharmony_ci// 9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and 13fd4e5da5Sopenharmony_ci// limitations under the License. 14fd4e5da5Sopenharmony_ci 15fd4e5da5Sopenharmony_ci#include "source/reduce/merge_blocks_reduction_opportunity.h" 16fd4e5da5Sopenharmony_ci 17fd4e5da5Sopenharmony_ci#include "source/opt/block_merge_util.h" 18fd4e5da5Sopenharmony_ci#include "source/opt/ir_context.h" 19fd4e5da5Sopenharmony_ci 20fd4e5da5Sopenharmony_cinamespace spvtools { 21fd4e5da5Sopenharmony_cinamespace reduce { 22fd4e5da5Sopenharmony_ci 23fd4e5da5Sopenharmony_ciMergeBlocksReductionOpportunity::MergeBlocksReductionOpportunity( 24fd4e5da5Sopenharmony_ci opt::IRContext* context, opt::Function* function, opt::BasicBlock* block) { 25fd4e5da5Sopenharmony_ci // Precondition: the terminator has to be OpBranch. 26fd4e5da5Sopenharmony_ci assert(block->terminator()->opcode() == spv::Op::OpBranch); 27fd4e5da5Sopenharmony_ci context_ = context; 28fd4e5da5Sopenharmony_ci function_ = function; 29fd4e5da5Sopenharmony_ci // Get the successor block associated with the OpBranch. 30fd4e5da5Sopenharmony_ci successor_block_ = 31fd4e5da5Sopenharmony_ci context->cfg()->block(block->terminator()->GetSingleWordInOperand(0)); 32fd4e5da5Sopenharmony_ci} 33fd4e5da5Sopenharmony_ci 34fd4e5da5Sopenharmony_cibool MergeBlocksReductionOpportunity::PreconditionHolds() { 35fd4e5da5Sopenharmony_ci // Merge block opportunities can disable each other. 36fd4e5da5Sopenharmony_ci // Example: Given blocks: A->B->C. 37fd4e5da5Sopenharmony_ci // A is a loop header; B and C are blocks in the loop; C ends with OpReturn. 38fd4e5da5Sopenharmony_ci // There are two opportunities: B and C can be merged with their predecessors. 39fd4e5da5Sopenharmony_ci // Merge C. B now ends with OpReturn. We now just have: A->B. 40fd4e5da5Sopenharmony_ci // Merge B is now disabled, as this would lead to A, a loop header, ending 41fd4e5da5Sopenharmony_ci // with an OpReturn, which is invalid. 42fd4e5da5Sopenharmony_ci 43fd4e5da5Sopenharmony_ci const auto predecessors = context_->cfg()->preds(successor_block_->id()); 44fd4e5da5Sopenharmony_ci assert(1 == predecessors.size() && 45fd4e5da5Sopenharmony_ci "For a successor to be merged into its predecessor, exactly one " 46fd4e5da5Sopenharmony_ci "predecessor must be present."); 47fd4e5da5Sopenharmony_ci const uint32_t predecessor_id = predecessors[0]; 48fd4e5da5Sopenharmony_ci opt::BasicBlock* predecessor_block = 49fd4e5da5Sopenharmony_ci context_->get_instr_block(predecessor_id); 50fd4e5da5Sopenharmony_ci return opt::blockmergeutil::CanMergeWithSuccessor(context_, 51fd4e5da5Sopenharmony_ci predecessor_block); 52fd4e5da5Sopenharmony_ci} 53fd4e5da5Sopenharmony_ci 54fd4e5da5Sopenharmony_civoid MergeBlocksReductionOpportunity::Apply() { 55fd4e5da5Sopenharmony_ci // While the original block that targeted the successor may not exist anymore 56fd4e5da5Sopenharmony_ci // (it might have been merged with another block), some block must exist that 57fd4e5da5Sopenharmony_ci // targets the successor. Find it. 58fd4e5da5Sopenharmony_ci 59fd4e5da5Sopenharmony_ci const auto predecessors = context_->cfg()->preds(successor_block_->id()); 60fd4e5da5Sopenharmony_ci assert(1 == predecessors.size() && 61fd4e5da5Sopenharmony_ci "For a successor to be merged into its predecessor, exactly one " 62fd4e5da5Sopenharmony_ci "predecessor must be present."); 63fd4e5da5Sopenharmony_ci const uint32_t predecessor_id = predecessors[0]; 64fd4e5da5Sopenharmony_ci 65fd4e5da5Sopenharmony_ci // We need an iterator pointing to the predecessor, hence the loop. 66fd4e5da5Sopenharmony_ci for (auto bi = function_->begin(); bi != function_->end(); ++bi) { 67fd4e5da5Sopenharmony_ci if (bi->id() == predecessor_id) { 68fd4e5da5Sopenharmony_ci opt::blockmergeutil::MergeWithSuccessor(context_, function_, bi); 69fd4e5da5Sopenharmony_ci // Block merging changes the control flow graph, so invalidate it. 70fd4e5da5Sopenharmony_ci context_->InvalidateAnalysesExceptFor( 71fd4e5da5Sopenharmony_ci opt::IRContext::Analysis::kAnalysisNone); 72fd4e5da5Sopenharmony_ci return; 73fd4e5da5Sopenharmony_ci } 74fd4e5da5Sopenharmony_ci } 75fd4e5da5Sopenharmony_ci 76fd4e5da5Sopenharmony_ci assert(false && 77fd4e5da5Sopenharmony_ci "Unreachable: we should have found a block with the desired id."); 78fd4e5da5Sopenharmony_ci} 79fd4e5da5Sopenharmony_ci 80fd4e5da5Sopenharmony_ci} // namespace reduce 81fd4e5da5Sopenharmony_ci} // namespace spvtools 82