1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "superblock_cloner.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "common_dominator.h"
20*795d594fSAndroid Build Coastguard Worker #include "induction_var_range.h"
21*795d594fSAndroid Build Coastguard Worker #include "graph_checker.h"
22*795d594fSAndroid Build Coastguard Worker
23*795d594fSAndroid Build Coastguard Worker #include <sstream>
24*795d594fSAndroid Build Coastguard Worker
25*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
26*795d594fSAndroid Build Coastguard Worker
27*795d594fSAndroid Build Coastguard Worker using HBasicBlockMap = SuperblockCloner::HBasicBlockMap;
28*795d594fSAndroid Build Coastguard Worker using HInstructionMap = SuperblockCloner::HInstructionMap;
29*795d594fSAndroid Build Coastguard Worker using HBasicBlockSet = SuperblockCloner::HBasicBlockSet;
30*795d594fSAndroid Build Coastguard Worker using HEdgeSet = SuperblockCloner::HEdgeSet;
31*795d594fSAndroid Build Coastguard Worker
Dump(std::ostream & stream) const32*795d594fSAndroid Build Coastguard Worker void HEdge::Dump(std::ostream& stream) const {
33*795d594fSAndroid Build Coastguard Worker stream << "(" << from_ << "->" << to_ << ")";
34*795d594fSAndroid Build Coastguard Worker }
35*795d594fSAndroid Build Coastguard Worker
36*795d594fSAndroid Build Coastguard Worker //
37*795d594fSAndroid Build Coastguard Worker // Static helper methods.
38*795d594fSAndroid Build Coastguard Worker //
39*795d594fSAndroid Build Coastguard Worker
40*795d594fSAndroid Build Coastguard Worker // Returns whether instruction has any uses (regular or environmental) outside the region,
41*795d594fSAndroid Build Coastguard Worker // defined by basic block set.
IsUsedOutsideRegion(const HInstruction * instr,const HBasicBlockSet & bb_set)42*795d594fSAndroid Build Coastguard Worker static bool IsUsedOutsideRegion(const HInstruction* instr, const HBasicBlockSet& bb_set) {
43*795d594fSAndroid Build Coastguard Worker auto& uses = instr->GetUses();
44*795d594fSAndroid Build Coastguard Worker for (auto use_node = uses.begin(), e = uses.end(); use_node != e; ++use_node) {
45*795d594fSAndroid Build Coastguard Worker HInstruction* user = use_node->GetUser();
46*795d594fSAndroid Build Coastguard Worker if (!bb_set.IsBitSet(user->GetBlock()->GetBlockId())) {
47*795d594fSAndroid Build Coastguard Worker return true;
48*795d594fSAndroid Build Coastguard Worker }
49*795d594fSAndroid Build Coastguard Worker }
50*795d594fSAndroid Build Coastguard Worker
51*795d594fSAndroid Build Coastguard Worker auto& env_uses = instr->GetEnvUses();
52*795d594fSAndroid Build Coastguard Worker for (auto use_node = env_uses.begin(), e = env_uses.end(); use_node != e; ++use_node) {
53*795d594fSAndroid Build Coastguard Worker HInstruction* user = use_node->GetUser()->GetHolder();
54*795d594fSAndroid Build Coastguard Worker if (!bb_set.IsBitSet(user->GetBlock()->GetBlockId())) {
55*795d594fSAndroid Build Coastguard Worker return true;
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker }
58*795d594fSAndroid Build Coastguard Worker
59*795d594fSAndroid Build Coastguard Worker return false;
60*795d594fSAndroid Build Coastguard Worker }
61*795d594fSAndroid Build Coastguard Worker
62*795d594fSAndroid Build Coastguard Worker // Returns whether the phi's inputs are the same HInstruction.
ArePhiInputsTheSame(const HPhi * phi)63*795d594fSAndroid Build Coastguard Worker static bool ArePhiInputsTheSame(const HPhi* phi) {
64*795d594fSAndroid Build Coastguard Worker HInstruction* first_input = phi->InputAt(0);
65*795d594fSAndroid Build Coastguard Worker for (size_t i = 1, e = phi->InputCount(); i < e; i++) {
66*795d594fSAndroid Build Coastguard Worker if (phi->InputAt(i) != first_input) {
67*795d594fSAndroid Build Coastguard Worker return false;
68*795d594fSAndroid Build Coastguard Worker }
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker
71*795d594fSAndroid Build Coastguard Worker return true;
72*795d594fSAndroid Build Coastguard Worker }
73*795d594fSAndroid Build Coastguard Worker
74*795d594fSAndroid Build Coastguard Worker // Returns whether two Edge sets are equal (ArenaHashSet doesn't have "Equal" method).
EdgeHashSetsEqual(const HEdgeSet * set1,const HEdgeSet * set2)75*795d594fSAndroid Build Coastguard Worker static bool EdgeHashSetsEqual(const HEdgeSet* set1, const HEdgeSet* set2) {
76*795d594fSAndroid Build Coastguard Worker if (set1->size() != set2->size()) {
77*795d594fSAndroid Build Coastguard Worker return false;
78*795d594fSAndroid Build Coastguard Worker }
79*795d594fSAndroid Build Coastguard Worker
80*795d594fSAndroid Build Coastguard Worker for (auto e : *set1) {
81*795d594fSAndroid Build Coastguard Worker if (set2->find(e) == set2->end()) {
82*795d594fSAndroid Build Coastguard Worker return false;
83*795d594fSAndroid Build Coastguard Worker }
84*795d594fSAndroid Build Coastguard Worker }
85*795d594fSAndroid Build Coastguard Worker return true;
86*795d594fSAndroid Build Coastguard Worker }
87*795d594fSAndroid Build Coastguard Worker
88*795d594fSAndroid Build Coastguard Worker // Calls HGraph::OrderLoopHeaderPredecessors for each loop in the graph.
OrderLoopsHeadersPredecessors(HGraph * graph)89*795d594fSAndroid Build Coastguard Worker static void OrderLoopsHeadersPredecessors(HGraph* graph) {
90*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph->GetPostOrder()) {
91*795d594fSAndroid Build Coastguard Worker if (block->IsLoopHeader()) {
92*795d594fSAndroid Build Coastguard Worker graph->OrderLoopHeaderPredecessors(block);
93*795d594fSAndroid Build Coastguard Worker }
94*795d594fSAndroid Build Coastguard Worker }
95*795d594fSAndroid Build Coastguard Worker }
96*795d594fSAndroid Build Coastguard Worker
97*795d594fSAndroid Build Coastguard Worker // Performs DFS on the subgraph (specified by 'bb_set') starting from the specified block; while
98*795d594fSAndroid Build Coastguard Worker // traversing the function removes basic blocks from the bb_set (instead of traditional DFS
99*795d594fSAndroid Build Coastguard Worker // 'marking'). So what is left in the 'bb_set' after the traversal is not reachable from the start
100*795d594fSAndroid Build Coastguard Worker // block.
TraverseSubgraphForConnectivity(HBasicBlock * block,HBasicBlockSet * bb_set)101*795d594fSAndroid Build Coastguard Worker static void TraverseSubgraphForConnectivity(HBasicBlock* block, HBasicBlockSet* bb_set) {
102*795d594fSAndroid Build Coastguard Worker DCHECK(bb_set->IsBitSet(block->GetBlockId()));
103*795d594fSAndroid Build Coastguard Worker bb_set->ClearBit(block->GetBlockId());
104*795d594fSAndroid Build Coastguard Worker
105*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* succ : block->GetSuccessors()) {
106*795d594fSAndroid Build Coastguard Worker if (bb_set->IsBitSet(succ->GetBlockId())) {
107*795d594fSAndroid Build Coastguard Worker TraverseSubgraphForConnectivity(succ, bb_set);
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker }
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker
112*795d594fSAndroid Build Coastguard Worker //
113*795d594fSAndroid Build Coastguard Worker // Helpers for CloneBasicBlock.
114*795d594fSAndroid Build Coastguard Worker //
115*795d594fSAndroid Build Coastguard Worker
ReplaceInputsWithCopies(HInstruction * copy_instr)116*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::ReplaceInputsWithCopies(HInstruction* copy_instr) {
117*795d594fSAndroid Build Coastguard Worker DCHECK(!copy_instr->IsPhi());
118*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = copy_instr->InputCount(); i < e; i++) {
119*795d594fSAndroid Build Coastguard Worker // Copy instruction holds the same input as the original instruction holds.
120*795d594fSAndroid Build Coastguard Worker HInstruction* orig_input = copy_instr->InputAt(i);
121*795d594fSAndroid Build Coastguard Worker if (!IsInOrigBBSet(orig_input->GetBlock())) {
122*795d594fSAndroid Build Coastguard Worker // Defined outside the subgraph.
123*795d594fSAndroid Build Coastguard Worker continue;
124*795d594fSAndroid Build Coastguard Worker }
125*795d594fSAndroid Build Coastguard Worker HInstruction* copy_input = GetInstrCopy(orig_input);
126*795d594fSAndroid Build Coastguard Worker // copy_instr will be registered as a user of copy_inputs after returning from this function:
127*795d594fSAndroid Build Coastguard Worker // 'copy_block->AddInstruction(copy_instr)'.
128*795d594fSAndroid Build Coastguard Worker copy_instr->SetRawInputAt(i, copy_input);
129*795d594fSAndroid Build Coastguard Worker }
130*795d594fSAndroid Build Coastguard Worker }
131*795d594fSAndroid Build Coastguard Worker
DeepCloneEnvironmentWithRemapping(HInstruction * copy_instr,const HEnvironment * orig_env)132*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::DeepCloneEnvironmentWithRemapping(HInstruction* copy_instr,
133*795d594fSAndroid Build Coastguard Worker const HEnvironment* orig_env) {
134*795d594fSAndroid Build Coastguard Worker if (orig_env->GetParent() != nullptr) {
135*795d594fSAndroid Build Coastguard Worker DeepCloneEnvironmentWithRemapping(copy_instr, orig_env->GetParent());
136*795d594fSAndroid Build Coastguard Worker }
137*795d594fSAndroid Build Coastguard Worker HEnvironment* copy_env = HEnvironment::Create(arena_, *orig_env, copy_instr);
138*795d594fSAndroid Build Coastguard Worker
139*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < orig_env->Size(); i++) {
140*795d594fSAndroid Build Coastguard Worker HInstruction* env_input = orig_env->GetInstructionAt(i);
141*795d594fSAndroid Build Coastguard Worker if (env_input != nullptr && IsInOrigBBSet(env_input->GetBlock())) {
142*795d594fSAndroid Build Coastguard Worker env_input = GetInstrCopy(env_input);
143*795d594fSAndroid Build Coastguard Worker DCHECK(env_input != nullptr && env_input->GetBlock() != nullptr);
144*795d594fSAndroid Build Coastguard Worker }
145*795d594fSAndroid Build Coastguard Worker copy_env->SetRawEnvAt(i, env_input);
146*795d594fSAndroid Build Coastguard Worker if (env_input != nullptr) {
147*795d594fSAndroid Build Coastguard Worker env_input->AddEnvUseAt(copy_env, i);
148*795d594fSAndroid Build Coastguard Worker }
149*795d594fSAndroid Build Coastguard Worker }
150*795d594fSAndroid Build Coastguard Worker // InsertRawEnvironment assumes that instruction already has an environment that's why we use
151*795d594fSAndroid Build Coastguard Worker // SetRawEnvironment in the 'else' case.
152*795d594fSAndroid Build Coastguard Worker // As this function calls itself recursively with the same copy_instr - this copy_instr may
153*795d594fSAndroid Build Coastguard Worker // have partially copied chain of HEnvironments.
154*795d594fSAndroid Build Coastguard Worker if (copy_instr->HasEnvironment()) {
155*795d594fSAndroid Build Coastguard Worker copy_instr->InsertRawEnvironment(copy_env);
156*795d594fSAndroid Build Coastguard Worker } else {
157*795d594fSAndroid Build Coastguard Worker copy_instr->SetRawEnvironment(copy_env);
158*795d594fSAndroid Build Coastguard Worker }
159*795d594fSAndroid Build Coastguard Worker }
160*795d594fSAndroid Build Coastguard Worker
161*795d594fSAndroid Build Coastguard Worker //
162*795d594fSAndroid Build Coastguard Worker // Helpers for RemapEdgesSuccessors.
163*795d594fSAndroid Build Coastguard Worker //
164*795d594fSAndroid Build Coastguard Worker
RemapOrigInternalOrIncomingEdge(HBasicBlock * orig_block,HBasicBlock * orig_succ)165*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::RemapOrigInternalOrIncomingEdge(HBasicBlock* orig_block,
166*795d594fSAndroid Build Coastguard Worker HBasicBlock* orig_succ) {
167*795d594fSAndroid Build Coastguard Worker DCHECK(IsInOrigBBSet(orig_succ));
168*795d594fSAndroid Build Coastguard Worker HBasicBlock* copy_succ = GetBlockCopy(orig_succ);
169*795d594fSAndroid Build Coastguard Worker
170*795d594fSAndroid Build Coastguard Worker size_t this_index = orig_succ->GetPredecessorIndexOf(orig_block);
171*795d594fSAndroid Build Coastguard Worker size_t phi_input_count = 0;
172*795d594fSAndroid Build Coastguard Worker // This flag reflects whether the original successor has at least one phi and this phi
173*795d594fSAndroid Build Coastguard Worker // has been already processed in the loop. Used for validation purposes in DCHECK to check that
174*795d594fSAndroid Build Coastguard Worker // in the end all of the phis in the copy successor have the same number of inputs - the number
175*795d594fSAndroid Build Coastguard Worker // of copy successor's predecessors.
176*795d594fSAndroid Build Coastguard Worker bool first_phi_met = false;
177*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(orig_succ->GetPhis()); !it.Done(); it.Advance()) {
178*795d594fSAndroid Build Coastguard Worker HPhi* orig_phi = it.Current()->AsPhi();
179*795d594fSAndroid Build Coastguard Worker HPhi* copy_phi = GetInstrCopy(orig_phi)->AsPhi();
180*795d594fSAndroid Build Coastguard Worker HInstruction* orig_phi_input = orig_phi->InputAt(this_index);
181*795d594fSAndroid Build Coastguard Worker // Remove corresponding input for original phi.
182*795d594fSAndroid Build Coastguard Worker orig_phi->RemoveInputAt(this_index);
183*795d594fSAndroid Build Coastguard Worker // Copy phi doesn't yet have either orig_block as predecessor or the input that corresponds
184*795d594fSAndroid Build Coastguard Worker // to orig_block, so add the input at the end of the list.
185*795d594fSAndroid Build Coastguard Worker copy_phi->AddInput(orig_phi_input);
186*795d594fSAndroid Build Coastguard Worker if (!first_phi_met) {
187*795d594fSAndroid Build Coastguard Worker phi_input_count = copy_phi->InputCount();
188*795d594fSAndroid Build Coastguard Worker first_phi_met = true;
189*795d594fSAndroid Build Coastguard Worker } else {
190*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(phi_input_count, copy_phi->InputCount());
191*795d594fSAndroid Build Coastguard Worker }
192*795d594fSAndroid Build Coastguard Worker }
193*795d594fSAndroid Build Coastguard Worker // orig_block will be put at the end of the copy_succ's predecessors list; that corresponds
194*795d594fSAndroid Build Coastguard Worker // to the previously added phi inputs position.
195*795d594fSAndroid Build Coastguard Worker orig_block->ReplaceSuccessor(orig_succ, copy_succ);
196*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(first_phi_met, copy_succ->GetPredecessors().size() == phi_input_count);
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker
AddCopyInternalEdge(HBasicBlock * orig_block,HBasicBlock * orig_succ)199*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::AddCopyInternalEdge(HBasicBlock* orig_block,
200*795d594fSAndroid Build Coastguard Worker HBasicBlock* orig_succ) {
201*795d594fSAndroid Build Coastguard Worker DCHECK(IsInOrigBBSet(orig_succ));
202*795d594fSAndroid Build Coastguard Worker HBasicBlock* copy_block = GetBlockCopy(orig_block);
203*795d594fSAndroid Build Coastguard Worker HBasicBlock* copy_succ = GetBlockCopy(orig_succ);
204*795d594fSAndroid Build Coastguard Worker copy_block->AddSuccessor(copy_succ);
205*795d594fSAndroid Build Coastguard Worker
206*795d594fSAndroid Build Coastguard Worker size_t orig_index = orig_succ->GetPredecessorIndexOf(orig_block);
207*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(orig_succ->GetPhis()); !it.Done(); it.Advance()) {
208*795d594fSAndroid Build Coastguard Worker HPhi* orig_phi = it.Current()->AsPhi();
209*795d594fSAndroid Build Coastguard Worker HPhi* copy_phi = GetInstrCopy(orig_phi)->AsPhi();
210*795d594fSAndroid Build Coastguard Worker HInstruction* orig_phi_input = orig_phi->InputAt(orig_index);
211*795d594fSAndroid Build Coastguard Worker copy_phi->AddInput(orig_phi_input);
212*795d594fSAndroid Build Coastguard Worker }
213*795d594fSAndroid Build Coastguard Worker }
214*795d594fSAndroid Build Coastguard Worker
RemapCopyInternalEdge(HBasicBlock * orig_block,HBasicBlock * orig_succ)215*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::RemapCopyInternalEdge(HBasicBlock* orig_block,
216*795d594fSAndroid Build Coastguard Worker HBasicBlock* orig_succ) {
217*795d594fSAndroid Build Coastguard Worker DCHECK(IsInOrigBBSet(orig_succ));
218*795d594fSAndroid Build Coastguard Worker HBasicBlock* copy_block = GetBlockCopy(orig_block);
219*795d594fSAndroid Build Coastguard Worker copy_block->AddSuccessor(orig_succ);
220*795d594fSAndroid Build Coastguard Worker DCHECK(copy_block->HasSuccessor(orig_succ));
221*795d594fSAndroid Build Coastguard Worker
222*795d594fSAndroid Build Coastguard Worker size_t orig_index = orig_succ->GetPredecessorIndexOf(orig_block);
223*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(orig_succ->GetPhis()); !it.Done(); it.Advance()) {
224*795d594fSAndroid Build Coastguard Worker HPhi* orig_phi = it.Current()->AsPhi();
225*795d594fSAndroid Build Coastguard Worker HInstruction* orig_phi_input = orig_phi->InputAt(orig_index);
226*795d594fSAndroid Build Coastguard Worker orig_phi->AddInput(orig_phi_input);
227*795d594fSAndroid Build Coastguard Worker }
228*795d594fSAndroid Build Coastguard Worker }
229*795d594fSAndroid Build Coastguard Worker
IsRemapInfoForVersioning() const230*795d594fSAndroid Build Coastguard Worker bool SuperblockCloner::IsRemapInfoForVersioning() const {
231*795d594fSAndroid Build Coastguard Worker return remap_incoming_->empty() &&
232*795d594fSAndroid Build Coastguard Worker remap_orig_internal_->empty() &&
233*795d594fSAndroid Build Coastguard Worker remap_copy_internal_->empty();
234*795d594fSAndroid Build Coastguard Worker }
235*795d594fSAndroid Build Coastguard Worker
CopyIncomingEdgesForVersioning()236*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::CopyIncomingEdgesForVersioning() {
237*795d594fSAndroid Build Coastguard Worker for (uint32_t orig_block_id : orig_bb_set_.Indexes()) {
238*795d594fSAndroid Build Coastguard Worker HBasicBlock* orig_block = GetBlockById(orig_block_id);
239*795d594fSAndroid Build Coastguard Worker size_t incoming_edge_count = 0;
240*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* orig_pred : orig_block->GetPredecessors()) {
241*795d594fSAndroid Build Coastguard Worker uint32_t orig_pred_id = orig_pred->GetBlockId();
242*795d594fSAndroid Build Coastguard Worker if (IsInOrigBBSet(orig_pred_id)) {
243*795d594fSAndroid Build Coastguard Worker continue;
244*795d594fSAndroid Build Coastguard Worker }
245*795d594fSAndroid Build Coastguard Worker
246*795d594fSAndroid Build Coastguard Worker HBasicBlock* copy_block = GetBlockCopy(orig_block);
247*795d594fSAndroid Build Coastguard Worker // This corresponds to the requirement on the order of predecessors: all the incoming
248*795d594fSAndroid Build Coastguard Worker // edges must be seen before the internal ones. This is always true for natural loops.
249*795d594fSAndroid Build Coastguard Worker // TODO: remove this requirement.
250*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(orig_block->GetPredecessorIndexOf(orig_pred), incoming_edge_count);
251*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(orig_block->GetPhis()); !it.Done(); it.Advance()) {
252*795d594fSAndroid Build Coastguard Worker HPhi* orig_phi = it.Current()->AsPhi();
253*795d594fSAndroid Build Coastguard Worker HPhi* copy_phi = GetInstrCopy(orig_phi)->AsPhi();
254*795d594fSAndroid Build Coastguard Worker HInstruction* orig_phi_input = orig_phi->InputAt(incoming_edge_count);
255*795d594fSAndroid Build Coastguard Worker // Add the corresponding input of the original phi to the copy one.
256*795d594fSAndroid Build Coastguard Worker copy_phi->AddInput(orig_phi_input);
257*795d594fSAndroid Build Coastguard Worker }
258*795d594fSAndroid Build Coastguard Worker copy_block->AddPredecessor(orig_pred);
259*795d594fSAndroid Build Coastguard Worker incoming_edge_count++;
260*795d594fSAndroid Build Coastguard Worker }
261*795d594fSAndroid Build Coastguard Worker }
262*795d594fSAndroid Build Coastguard Worker }
263*795d594fSAndroid Build Coastguard Worker
264*795d594fSAndroid Build Coastguard Worker //
265*795d594fSAndroid Build Coastguard Worker // Local versions of CF calculation/adjustment routines.
266*795d594fSAndroid Build Coastguard Worker //
267*795d594fSAndroid Build Coastguard Worker
268*795d594fSAndroid Build Coastguard Worker // TODO: merge with the original version in nodes.cc. The concern is that we don't want to affect
269*795d594fSAndroid Build Coastguard Worker // the performance of the base version by checking the local set.
270*795d594fSAndroid Build Coastguard Worker // TODO: this version works when updating the back edges info for natural loop-based local_set.
271*795d594fSAndroid Build Coastguard Worker // Check which exactly types of subgraphs can be analysed or rename it to
272*795d594fSAndroid Build Coastguard Worker // FindBackEdgesInTheNaturalLoop.
FindBackEdgesLocal(HBasicBlock * entry_block,ArenaBitVector * local_set)273*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::FindBackEdgesLocal(HBasicBlock* entry_block, ArenaBitVector* local_set) {
274*795d594fSAndroid Build Coastguard Worker ArenaBitVector visited(arena_, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
275*795d594fSAndroid Build Coastguard Worker
276*795d594fSAndroid Build Coastguard Worker // Nodes that we're currently visiting, indexed by block id.
277*795d594fSAndroid Build Coastguard Worker ArenaBitVector visiting(arena_, graph_->GetBlocks().size(), false, kArenaAllocGraphBuilder);
278*795d594fSAndroid Build Coastguard Worker // Number of successors visited from a given node, indexed by block id.
279*795d594fSAndroid Build Coastguard Worker ArenaVector<size_t> successors_visited(graph_->GetBlocks().size(),
280*795d594fSAndroid Build Coastguard Worker 0u,
281*795d594fSAndroid Build Coastguard Worker arena_->Adapter(kArenaAllocGraphBuilder));
282*795d594fSAndroid Build Coastguard Worker // Stack of nodes that we're currently visiting (same as marked in "visiting" above).
283*795d594fSAndroid Build Coastguard Worker ArenaVector<HBasicBlock*> worklist(arena_->Adapter(kArenaAllocGraphBuilder));
284*795d594fSAndroid Build Coastguard Worker constexpr size_t kDefaultWorklistSize = 8;
285*795d594fSAndroid Build Coastguard Worker worklist.reserve(kDefaultWorklistSize);
286*795d594fSAndroid Build Coastguard Worker
287*795d594fSAndroid Build Coastguard Worker visited.SetBit(entry_block->GetBlockId());
288*795d594fSAndroid Build Coastguard Worker visiting.SetBit(entry_block->GetBlockId());
289*795d594fSAndroid Build Coastguard Worker worklist.push_back(entry_block);
290*795d594fSAndroid Build Coastguard Worker
291*795d594fSAndroid Build Coastguard Worker while (!worklist.empty()) {
292*795d594fSAndroid Build Coastguard Worker HBasicBlock* current = worklist.back();
293*795d594fSAndroid Build Coastguard Worker uint32_t current_id = current->GetBlockId();
294*795d594fSAndroid Build Coastguard Worker if (successors_visited[current_id] == current->GetSuccessors().size()) {
295*795d594fSAndroid Build Coastguard Worker visiting.ClearBit(current_id);
296*795d594fSAndroid Build Coastguard Worker worklist.pop_back();
297*795d594fSAndroid Build Coastguard Worker } else {
298*795d594fSAndroid Build Coastguard Worker HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++];
299*795d594fSAndroid Build Coastguard Worker uint32_t successor_id = successor->GetBlockId();
300*795d594fSAndroid Build Coastguard Worker if (!local_set->IsBitSet(successor_id)) {
301*795d594fSAndroid Build Coastguard Worker continue;
302*795d594fSAndroid Build Coastguard Worker }
303*795d594fSAndroid Build Coastguard Worker
304*795d594fSAndroid Build Coastguard Worker if (visiting.IsBitSet(successor_id)) {
305*795d594fSAndroid Build Coastguard Worker DCHECK(ContainsElement(worklist, successor));
306*795d594fSAndroid Build Coastguard Worker successor->AddBackEdgeWhileUpdating(current);
307*795d594fSAndroid Build Coastguard Worker } else if (!visited.IsBitSet(successor_id)) {
308*795d594fSAndroid Build Coastguard Worker visited.SetBit(successor_id);
309*795d594fSAndroid Build Coastguard Worker visiting.SetBit(successor_id);
310*795d594fSAndroid Build Coastguard Worker worklist.push_back(successor);
311*795d594fSAndroid Build Coastguard Worker }
312*795d594fSAndroid Build Coastguard Worker }
313*795d594fSAndroid Build Coastguard Worker }
314*795d594fSAndroid Build Coastguard Worker }
315*795d594fSAndroid Build Coastguard Worker
RecalculateBackEdgesInfo(ArenaBitVector * outer_loop_bb_set)316*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::RecalculateBackEdgesInfo(ArenaBitVector* outer_loop_bb_set) {
317*795d594fSAndroid Build Coastguard Worker HBasicBlock* block_entry = nullptr;
318*795d594fSAndroid Build Coastguard Worker
319*795d594fSAndroid Build Coastguard Worker if (outer_loop_ == nullptr) {
320*795d594fSAndroid Build Coastguard Worker for (auto block : graph_->GetBlocks()) {
321*795d594fSAndroid Build Coastguard Worker if (block != nullptr) {
322*795d594fSAndroid Build Coastguard Worker outer_loop_bb_set->SetBit(block->GetBlockId());
323*795d594fSAndroid Build Coastguard Worker HLoopInformation* info = block->GetLoopInformation();
324*795d594fSAndroid Build Coastguard Worker if (info != nullptr) {
325*795d594fSAndroid Build Coastguard Worker info->ResetBasicBlockData();
326*795d594fSAndroid Build Coastguard Worker }
327*795d594fSAndroid Build Coastguard Worker }
328*795d594fSAndroid Build Coastguard Worker }
329*795d594fSAndroid Build Coastguard Worker block_entry = graph_->GetEntryBlock();
330*795d594fSAndroid Build Coastguard Worker } else {
331*795d594fSAndroid Build Coastguard Worker outer_loop_bb_set->Copy(&outer_loop_bb_set_);
332*795d594fSAndroid Build Coastguard Worker block_entry = outer_loop_->GetHeader();
333*795d594fSAndroid Build Coastguard Worker
334*795d594fSAndroid Build Coastguard Worker // Add newly created copy blocks.
335*795d594fSAndroid Build Coastguard Worker for (auto entry : *bb_map_) {
336*795d594fSAndroid Build Coastguard Worker outer_loop_bb_set->SetBit(entry.second->GetBlockId());
337*795d594fSAndroid Build Coastguard Worker }
338*795d594fSAndroid Build Coastguard Worker
339*795d594fSAndroid Build Coastguard Worker // Clear loop_info for the whole outer loop.
340*795d594fSAndroid Build Coastguard Worker for (uint32_t idx : outer_loop_bb_set->Indexes()) {
341*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = GetBlockById(idx);
342*795d594fSAndroid Build Coastguard Worker HLoopInformation* info = block->GetLoopInformation();
343*795d594fSAndroid Build Coastguard Worker if (info != nullptr) {
344*795d594fSAndroid Build Coastguard Worker info->ResetBasicBlockData();
345*795d594fSAndroid Build Coastguard Worker }
346*795d594fSAndroid Build Coastguard Worker }
347*795d594fSAndroid Build Coastguard Worker }
348*795d594fSAndroid Build Coastguard Worker
349*795d594fSAndroid Build Coastguard Worker FindBackEdgesLocal(block_entry, outer_loop_bb_set);
350*795d594fSAndroid Build Coastguard Worker
351*795d594fSAndroid Build Coastguard Worker for (uint32_t idx : outer_loop_bb_set->Indexes()) {
352*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = GetBlockById(idx);
353*795d594fSAndroid Build Coastguard Worker HLoopInformation* info = block->GetLoopInformation();
354*795d594fSAndroid Build Coastguard Worker // Reset LoopInformation for regular blocks and old headers which are no longer loop headers.
355*795d594fSAndroid Build Coastguard Worker if (info != nullptr &&
356*795d594fSAndroid Build Coastguard Worker (info->GetHeader() != block || info->NumberOfBackEdges() == 0)) {
357*795d594fSAndroid Build Coastguard Worker block->SetLoopInformation(nullptr);
358*795d594fSAndroid Build Coastguard Worker }
359*795d594fSAndroid Build Coastguard Worker }
360*795d594fSAndroid Build Coastguard Worker }
361*795d594fSAndroid Build Coastguard Worker
362*795d594fSAndroid Build Coastguard Worker // This is a modified version of HGraph::AnalyzeLoops.
AnalyzeLoopsLocally(ArenaBitVector * outer_loop_bb_set)363*795d594fSAndroid Build Coastguard Worker GraphAnalysisResult SuperblockCloner::AnalyzeLoopsLocally(ArenaBitVector* outer_loop_bb_set) {
364*795d594fSAndroid Build Coastguard Worker // We iterate post order to ensure we visit inner loops before outer loops.
365*795d594fSAndroid Build Coastguard Worker // `PopulateRecursive` needs this guarantee to know whether a natural loop
366*795d594fSAndroid Build Coastguard Worker // contains an irreducible loop.
367*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph_->GetPostOrder()) {
368*795d594fSAndroid Build Coastguard Worker if (!outer_loop_bb_set->IsBitSet(block->GetBlockId())) {
369*795d594fSAndroid Build Coastguard Worker continue;
370*795d594fSAndroid Build Coastguard Worker }
371*795d594fSAndroid Build Coastguard Worker if (block->IsLoopHeader()) {
372*795d594fSAndroid Build Coastguard Worker if (block->IsCatchBlock()) {
373*795d594fSAndroid Build Coastguard Worker // TODO: Dealing with exceptional back edges could be tricky because
374*795d594fSAndroid Build Coastguard Worker // they only approximate the real control flow. Bail out for now.
375*795d594fSAndroid Build Coastguard Worker return kAnalysisFailThrowCatchLoop;
376*795d594fSAndroid Build Coastguard Worker }
377*795d594fSAndroid Build Coastguard Worker block->GetLoopInformation()->Populate();
378*795d594fSAndroid Build Coastguard Worker }
379*795d594fSAndroid Build Coastguard Worker }
380*795d594fSAndroid Build Coastguard Worker
381*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph_->GetPostOrder()) {
382*795d594fSAndroid Build Coastguard Worker if (!outer_loop_bb_set->IsBitSet(block->GetBlockId())) {
383*795d594fSAndroid Build Coastguard Worker continue;
384*795d594fSAndroid Build Coastguard Worker }
385*795d594fSAndroid Build Coastguard Worker if (block->IsLoopHeader()) {
386*795d594fSAndroid Build Coastguard Worker HLoopInformation* cur_loop = block->GetLoopInformation();
387*795d594fSAndroid Build Coastguard Worker HLoopInformation* outer_loop = cur_loop->GetPreHeader()->GetLoopInformation();
388*795d594fSAndroid Build Coastguard Worker if (outer_loop != nullptr) {
389*795d594fSAndroid Build Coastguard Worker outer_loop->PopulateInnerLoopUpwards(cur_loop);
390*795d594fSAndroid Build Coastguard Worker }
391*795d594fSAndroid Build Coastguard Worker }
392*795d594fSAndroid Build Coastguard Worker }
393*795d594fSAndroid Build Coastguard Worker
394*795d594fSAndroid Build Coastguard Worker return kAnalysisSuccess;
395*795d594fSAndroid Build Coastguard Worker }
396*795d594fSAndroid Build Coastguard Worker
CleanUpControlFlow()397*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::CleanUpControlFlow() {
398*795d594fSAndroid Build Coastguard Worker // TODO: full control flow clean up for now, optimize it.
399*795d594fSAndroid Build Coastguard Worker graph_->ClearDominanceInformation();
400*795d594fSAndroid Build Coastguard Worker
401*795d594fSAndroid Build Coastguard Worker ArenaBitVector outer_loop_bb_set(
402*795d594fSAndroid Build Coastguard Worker arena_, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
403*795d594fSAndroid Build Coastguard Worker RecalculateBackEdgesInfo(&outer_loop_bb_set);
404*795d594fSAndroid Build Coastguard Worker
405*795d594fSAndroid Build Coastguard Worker // TODO: do it locally.
406*795d594fSAndroid Build Coastguard Worker graph_->SimplifyCFG();
407*795d594fSAndroid Build Coastguard Worker graph_->ComputeDominanceInformation();
408*795d594fSAndroid Build Coastguard Worker
409*795d594fSAndroid Build Coastguard Worker // AnalyzeLoopsLocally requires a correct post-ordering information which was calculated just
410*795d594fSAndroid Build Coastguard Worker // before in ComputeDominanceInformation.
411*795d594fSAndroid Build Coastguard Worker GraphAnalysisResult result = AnalyzeLoopsLocally(&outer_loop_bb_set);
412*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(result, kAnalysisSuccess);
413*795d594fSAndroid Build Coastguard Worker
414*795d594fSAndroid Build Coastguard Worker // TODO: do it locally
415*795d594fSAndroid Build Coastguard Worker OrderLoopsHeadersPredecessors(graph_);
416*795d594fSAndroid Build Coastguard Worker
417*795d594fSAndroid Build Coastguard Worker graph_->ComputeTryBlockInformation();
418*795d594fSAndroid Build Coastguard Worker }
419*795d594fSAndroid Build Coastguard Worker
420*795d594fSAndroid Build Coastguard Worker //
421*795d594fSAndroid Build Coastguard Worker // Helpers for ResolveDataFlow
422*795d594fSAndroid Build Coastguard Worker //
423*795d594fSAndroid Build Coastguard Worker
ResolvePhi(HPhi * phi)424*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::ResolvePhi(HPhi* phi) {
425*795d594fSAndroid Build Coastguard Worker HBasicBlock* phi_block = phi->GetBlock();
426*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = phi->InputCount(); i < e; i++) {
427*795d594fSAndroid Build Coastguard Worker HInstruction* input = phi->InputAt(i);
428*795d594fSAndroid Build Coastguard Worker HBasicBlock* input_block = input->GetBlock();
429*795d594fSAndroid Build Coastguard Worker
430*795d594fSAndroid Build Coastguard Worker // Originally defined outside the region.
431*795d594fSAndroid Build Coastguard Worker if (!IsInOrigBBSet(input_block)) {
432*795d594fSAndroid Build Coastguard Worker continue;
433*795d594fSAndroid Build Coastguard Worker }
434*795d594fSAndroid Build Coastguard Worker HBasicBlock* corresponding_block = phi_block->GetPredecessors()[i];
435*795d594fSAndroid Build Coastguard Worker if (!IsInOrigBBSet(corresponding_block)) {
436*795d594fSAndroid Build Coastguard Worker phi->ReplaceInput(GetInstrCopy(input), i);
437*795d594fSAndroid Build Coastguard Worker }
438*795d594fSAndroid Build Coastguard Worker }
439*795d594fSAndroid Build Coastguard Worker }
440*795d594fSAndroid Build Coastguard Worker
441*795d594fSAndroid Build Coastguard Worker //
442*795d594fSAndroid Build Coastguard Worker // Main algorithm methods.
443*795d594fSAndroid Build Coastguard Worker //
444*795d594fSAndroid Build Coastguard Worker
SearchForSubgraphExits(ArenaVector<HBasicBlock * > * exits) const445*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::SearchForSubgraphExits(ArenaVector<HBasicBlock*>* exits) const {
446*795d594fSAndroid Build Coastguard Worker DCHECK(exits->empty());
447*795d594fSAndroid Build Coastguard Worker for (uint32_t block_id : orig_bb_set_.Indexes()) {
448*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = GetBlockById(block_id);
449*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* succ : block->GetSuccessors()) {
450*795d594fSAndroid Build Coastguard Worker if (!IsInOrigBBSet(succ)) {
451*795d594fSAndroid Build Coastguard Worker exits->push_back(succ);
452*795d594fSAndroid Build Coastguard Worker }
453*795d594fSAndroid Build Coastguard Worker }
454*795d594fSAndroid Build Coastguard Worker }
455*795d594fSAndroid Build Coastguard Worker }
456*795d594fSAndroid Build Coastguard Worker
FindAndSetLocalAreaForAdjustments()457*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::FindAndSetLocalAreaForAdjustments() {
458*795d594fSAndroid Build Coastguard Worker DCHECK(outer_loop_ == nullptr);
459*795d594fSAndroid Build Coastguard Worker ArenaVector<HBasicBlock*> exits(arena_->Adapter(kArenaAllocSuperblockCloner));
460*795d594fSAndroid Build Coastguard Worker SearchForSubgraphExits(&exits);
461*795d594fSAndroid Build Coastguard Worker
462*795d594fSAndroid Build Coastguard Worker // For a reducible graph we need to update back-edges and dominance information only for
463*795d594fSAndroid Build Coastguard Worker // the outermost loop which is affected by the transformation - it can be found by picking
464*795d594fSAndroid Build Coastguard Worker // the common most outer loop of loops to which the subgraph exits blocks belong.
465*795d594fSAndroid Build Coastguard Worker // Note: it can a loop or the whole graph (outer_loop_ will be nullptr in this case).
466*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* exit : exits) {
467*795d594fSAndroid Build Coastguard Worker HLoopInformation* loop_exit_loop_info = exit->GetLoopInformation();
468*795d594fSAndroid Build Coastguard Worker if (loop_exit_loop_info == nullptr) {
469*795d594fSAndroid Build Coastguard Worker outer_loop_ = nullptr;
470*795d594fSAndroid Build Coastguard Worker break;
471*795d594fSAndroid Build Coastguard Worker }
472*795d594fSAndroid Build Coastguard Worker if (outer_loop_ == nullptr) {
473*795d594fSAndroid Build Coastguard Worker // We should not use the initial outer_loop_ value 'nullptr' when finding the most outer
474*795d594fSAndroid Build Coastguard Worker // common loop.
475*795d594fSAndroid Build Coastguard Worker outer_loop_ = loop_exit_loop_info;
476*795d594fSAndroid Build Coastguard Worker }
477*795d594fSAndroid Build Coastguard Worker outer_loop_ = FindCommonLoop(outer_loop_, loop_exit_loop_info);
478*795d594fSAndroid Build Coastguard Worker }
479*795d594fSAndroid Build Coastguard Worker
480*795d594fSAndroid Build Coastguard Worker if (outer_loop_ != nullptr) {
481*795d594fSAndroid Build Coastguard Worker // Save the loop population info as it will be changed later.
482*795d594fSAndroid Build Coastguard Worker outer_loop_bb_set_.Copy(&outer_loop_->GetBlocks());
483*795d594fSAndroid Build Coastguard Worker }
484*795d594fSAndroid Build Coastguard Worker }
485*795d594fSAndroid Build Coastguard Worker
RemapEdgesSuccessors()486*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::RemapEdgesSuccessors() {
487*795d594fSAndroid Build Coastguard Worker // By this stage all the blocks have been copied, copy phis - created with no inputs;
488*795d594fSAndroid Build Coastguard Worker // no copy edges have been created so far.
489*795d594fSAndroid Build Coastguard Worker if (IsRemapInfoForVersioning()) {
490*795d594fSAndroid Build Coastguard Worker CopyIncomingEdgesForVersioning();
491*795d594fSAndroid Build Coastguard Worker }
492*795d594fSAndroid Build Coastguard Worker
493*795d594fSAndroid Build Coastguard Worker // Redirect incoming edges.
494*795d594fSAndroid Build Coastguard Worker for (HEdge e : *remap_incoming_) {
495*795d594fSAndroid Build Coastguard Worker HBasicBlock* orig_block = GetBlockById(e.GetFrom());
496*795d594fSAndroid Build Coastguard Worker HBasicBlock* orig_succ = GetBlockById(e.GetTo());
497*795d594fSAndroid Build Coastguard Worker RemapOrigInternalOrIncomingEdge(orig_block, orig_succ);
498*795d594fSAndroid Build Coastguard Worker }
499*795d594fSAndroid Build Coastguard Worker
500*795d594fSAndroid Build Coastguard Worker // Redirect internal edges.
501*795d594fSAndroid Build Coastguard Worker for (uint32_t orig_block_id : orig_bb_set_.Indexes()) {
502*795d594fSAndroid Build Coastguard Worker HBasicBlock* orig_block = GetBlockById(orig_block_id);
503*795d594fSAndroid Build Coastguard Worker
504*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* orig_succ : orig_block->GetSuccessors()) {
505*795d594fSAndroid Build Coastguard Worker uint32_t orig_succ_id = orig_succ->GetBlockId();
506*795d594fSAndroid Build Coastguard Worker
507*795d594fSAndroid Build Coastguard Worker // Check for outgoing edge.
508*795d594fSAndroid Build Coastguard Worker if (!IsInOrigBBSet(orig_succ)) {
509*795d594fSAndroid Build Coastguard Worker HBasicBlock* copy_block = GetBlockCopy(orig_block);
510*795d594fSAndroid Build Coastguard Worker copy_block->AddSuccessor(orig_succ);
511*795d594fSAndroid Build Coastguard Worker continue;
512*795d594fSAndroid Build Coastguard Worker }
513*795d594fSAndroid Build Coastguard Worker
514*795d594fSAndroid Build Coastguard Worker auto orig_redir = remap_orig_internal_->find(HEdge(orig_block_id, orig_succ_id));
515*795d594fSAndroid Build Coastguard Worker auto copy_redir = remap_copy_internal_->find(HEdge(orig_block_id, orig_succ_id));
516*795d594fSAndroid Build Coastguard Worker
517*795d594fSAndroid Build Coastguard Worker // Due to construction all successors of copied block were set to original.
518*795d594fSAndroid Build Coastguard Worker if (copy_redir != remap_copy_internal_->end()) {
519*795d594fSAndroid Build Coastguard Worker RemapCopyInternalEdge(orig_block, orig_succ);
520*795d594fSAndroid Build Coastguard Worker } else {
521*795d594fSAndroid Build Coastguard Worker AddCopyInternalEdge(orig_block, orig_succ);
522*795d594fSAndroid Build Coastguard Worker }
523*795d594fSAndroid Build Coastguard Worker
524*795d594fSAndroid Build Coastguard Worker if (orig_redir != remap_orig_internal_->end()) {
525*795d594fSAndroid Build Coastguard Worker RemapOrigInternalOrIncomingEdge(orig_block, orig_succ);
526*795d594fSAndroid Build Coastguard Worker }
527*795d594fSAndroid Build Coastguard Worker }
528*795d594fSAndroid Build Coastguard Worker }
529*795d594fSAndroid Build Coastguard Worker }
530*795d594fSAndroid Build Coastguard Worker
AdjustControlFlowInfo()531*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::AdjustControlFlowInfo() {
532*795d594fSAndroid Build Coastguard Worker ArenaBitVector outer_loop_bb_set(
533*795d594fSAndroid Build Coastguard Worker arena_, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
534*795d594fSAndroid Build Coastguard Worker RecalculateBackEdgesInfo(&outer_loop_bb_set);
535*795d594fSAndroid Build Coastguard Worker
536*795d594fSAndroid Build Coastguard Worker graph_->ClearDominanceInformation();
537*795d594fSAndroid Build Coastguard Worker // TODO: Do it locally.
538*795d594fSAndroid Build Coastguard Worker graph_->ComputeDominanceInformation();
539*795d594fSAndroid Build Coastguard Worker }
540*795d594fSAndroid Build Coastguard Worker
541*795d594fSAndroid Build Coastguard Worker // TODO: Current FastCase restriction guarantees that instructions' inputs are already mapped to
542*795d594fSAndroid Build Coastguard Worker // the valid values; only phis' inputs must be adjusted.
ResolveDataFlow()543*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::ResolveDataFlow() {
544*795d594fSAndroid Build Coastguard Worker for (auto entry : *bb_map_) {
545*795d594fSAndroid Build Coastguard Worker HBasicBlock* orig_block = entry.first;
546*795d594fSAndroid Build Coastguard Worker
547*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(orig_block->GetPhis()); !it.Done(); it.Advance()) {
548*795d594fSAndroid Build Coastguard Worker HPhi* orig_phi = it.Current()->AsPhi();
549*795d594fSAndroid Build Coastguard Worker HPhi* copy_phi = GetInstrCopy(orig_phi)->AsPhi();
550*795d594fSAndroid Build Coastguard Worker ResolvePhi(orig_phi);
551*795d594fSAndroid Build Coastguard Worker ResolvePhi(copy_phi);
552*795d594fSAndroid Build Coastguard Worker }
553*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
554*795d594fSAndroid Build Coastguard Worker // Inputs of instruction copies must be already mapped to correspondent inputs copies.
555*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(orig_block->GetInstructions()); !it.Done(); it.Advance()) {
556*795d594fSAndroid Build Coastguard Worker CheckInstructionInputsRemapping(it.Current());
557*795d594fSAndroid Build Coastguard Worker }
558*795d594fSAndroid Build Coastguard Worker }
559*795d594fSAndroid Build Coastguard Worker }
560*795d594fSAndroid Build Coastguard Worker }
561*795d594fSAndroid Build Coastguard Worker
562*795d594fSAndroid Build Coastguard Worker //
563*795d594fSAndroid Build Coastguard Worker // Helpers for live-outs processing and Subgraph-closed SSA.
564*795d594fSAndroid Build Coastguard Worker //
565*795d594fSAndroid Build Coastguard Worker
CollectLiveOutsAndCheckClonable(HInstructionMap * live_outs) const566*795d594fSAndroid Build Coastguard Worker bool SuperblockCloner::CollectLiveOutsAndCheckClonable(HInstructionMap* live_outs) const {
567*795d594fSAndroid Build Coastguard Worker DCHECK(live_outs->empty());
568*795d594fSAndroid Build Coastguard Worker for (uint32_t idx : orig_bb_set_.Indexes()) {
569*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = GetBlockById(idx);
570*795d594fSAndroid Build Coastguard Worker
571*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
572*795d594fSAndroid Build Coastguard Worker HInstruction* instr = it.Current();
573*795d594fSAndroid Build Coastguard Worker DCHECK(instr->IsClonable());
574*795d594fSAndroid Build Coastguard Worker
575*795d594fSAndroid Build Coastguard Worker if (IsUsedOutsideRegion(instr, orig_bb_set_)) {
576*795d594fSAndroid Build Coastguard Worker live_outs->FindOrAdd(instr, instr);
577*795d594fSAndroid Build Coastguard Worker }
578*795d594fSAndroid Build Coastguard Worker }
579*795d594fSAndroid Build Coastguard Worker
580*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
581*795d594fSAndroid Build Coastguard Worker HInstruction* instr = it.Current();
582*795d594fSAndroid Build Coastguard Worker if (!instr->IsClonable()) {
583*795d594fSAndroid Build Coastguard Worker return false;
584*795d594fSAndroid Build Coastguard Worker }
585*795d594fSAndroid Build Coastguard Worker
586*795d594fSAndroid Build Coastguard Worker if (IsUsedOutsideRegion(instr, orig_bb_set_)) {
587*795d594fSAndroid Build Coastguard Worker // TODO: Investigate why HNewInstance, HCheckCast has a requirement for the input.
588*795d594fSAndroid Build Coastguard Worker if (instr->IsLoadClass()) {
589*795d594fSAndroid Build Coastguard Worker return false;
590*795d594fSAndroid Build Coastguard Worker }
591*795d594fSAndroid Build Coastguard Worker live_outs->FindOrAdd(instr, instr);
592*795d594fSAndroid Build Coastguard Worker }
593*795d594fSAndroid Build Coastguard Worker }
594*795d594fSAndroid Build Coastguard Worker }
595*795d594fSAndroid Build Coastguard Worker return true;
596*795d594fSAndroid Build Coastguard Worker }
597*795d594fSAndroid Build Coastguard Worker
UpdateInductionRangeInfoOf(HInstruction * user,HInstruction * old_instruction,HInstruction * replacement)598*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::UpdateInductionRangeInfoOf(
599*795d594fSAndroid Build Coastguard Worker HInstruction* user, HInstruction* old_instruction, HInstruction* replacement) {
600*795d594fSAndroid Build Coastguard Worker if (induction_range_ != nullptr) {
601*795d594fSAndroid Build Coastguard Worker induction_range_->Replace(user, old_instruction, replacement);
602*795d594fSAndroid Build Coastguard Worker }
603*795d594fSAndroid Build Coastguard Worker }
604*795d594fSAndroid Build Coastguard Worker
ConstructSubgraphClosedSSA()605*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::ConstructSubgraphClosedSSA() {
606*795d594fSAndroid Build Coastguard Worker if (live_outs_.empty()) {
607*795d594fSAndroid Build Coastguard Worker return;
608*795d594fSAndroid Build Coastguard Worker }
609*795d594fSAndroid Build Coastguard Worker
610*795d594fSAndroid Build Coastguard Worker ArenaVector<HBasicBlock*> exits(arena_->Adapter(kArenaAllocSuperblockCloner));
611*795d594fSAndroid Build Coastguard Worker SearchForSubgraphExits(&exits);
612*795d594fSAndroid Build Coastguard Worker if (exits.empty()) {
613*795d594fSAndroid Build Coastguard Worker DCHECK(live_outs_.empty());
614*795d594fSAndroid Build Coastguard Worker return;
615*795d594fSAndroid Build Coastguard Worker }
616*795d594fSAndroid Build Coastguard Worker
617*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(exits.size(), 1u);
618*795d594fSAndroid Build Coastguard Worker HBasicBlock* exit_block = exits[0];
619*795d594fSAndroid Build Coastguard Worker // There should be no critical edges.
620*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(exit_block->GetPredecessors().size(), 1u);
621*795d594fSAndroid Build Coastguard Worker DCHECK(exit_block->GetPhis().IsEmpty());
622*795d594fSAndroid Build Coastguard Worker
623*795d594fSAndroid Build Coastguard Worker // For each live-out value insert a phi into the loop exit and replace all the value's uses
624*795d594fSAndroid Build Coastguard Worker // external to the loop with this phi. The phi will have the original value as its only input;
625*795d594fSAndroid Build Coastguard Worker // after copying is done FixSubgraphClosedSSAAfterCloning will add a corresponding copy of the
626*795d594fSAndroid Build Coastguard Worker // original value as the second input thus merging data flow from the original and copy parts of
627*795d594fSAndroid Build Coastguard Worker // the subgraph. Also update the record in the live_outs_ map from (value, value) to
628*795d594fSAndroid Build Coastguard Worker // (value, new_phi).
629*795d594fSAndroid Build Coastguard Worker for (auto live_out_it = live_outs_.begin(); live_out_it != live_outs_.end(); ++live_out_it) {
630*795d594fSAndroid Build Coastguard Worker HInstruction* value = live_out_it->first;
631*795d594fSAndroid Build Coastguard Worker HPhi* phi = new (arena_) HPhi(arena_, kNoRegNumber, 0, value->GetType());
632*795d594fSAndroid Build Coastguard Worker
633*795d594fSAndroid Build Coastguard Worker if (value->GetType() == DataType::Type::kReference) {
634*795d594fSAndroid Build Coastguard Worker phi->SetReferenceTypeInfoIfValid(value->GetReferenceTypeInfo());
635*795d594fSAndroid Build Coastguard Worker }
636*795d594fSAndroid Build Coastguard Worker
637*795d594fSAndroid Build Coastguard Worker exit_block->AddPhi(phi);
638*795d594fSAndroid Build Coastguard Worker live_out_it->second = phi;
639*795d594fSAndroid Build Coastguard Worker
640*795d594fSAndroid Build Coastguard Worker const HUseList<HInstruction*>& uses = value->GetUses();
641*795d594fSAndroid Build Coastguard Worker for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
642*795d594fSAndroid Build Coastguard Worker HInstruction* user = it->GetUser();
643*795d594fSAndroid Build Coastguard Worker size_t index = it->GetIndex();
644*795d594fSAndroid Build Coastguard Worker // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
645*795d594fSAndroid Build Coastguard Worker ++it;
646*795d594fSAndroid Build Coastguard Worker if (!IsInOrigBBSet(user->GetBlock())) {
647*795d594fSAndroid Build Coastguard Worker user->ReplaceInput(phi, index);
648*795d594fSAndroid Build Coastguard Worker UpdateInductionRangeInfoOf(user, value, phi);
649*795d594fSAndroid Build Coastguard Worker }
650*795d594fSAndroid Build Coastguard Worker }
651*795d594fSAndroid Build Coastguard Worker
652*795d594fSAndroid Build Coastguard Worker const HUseList<HEnvironment*>& env_uses = value->GetEnvUses();
653*795d594fSAndroid Build Coastguard Worker for (auto it = env_uses.begin(), e = env_uses.end(); it != e; /* ++it below */) {
654*795d594fSAndroid Build Coastguard Worker HEnvironment* env = it->GetUser();
655*795d594fSAndroid Build Coastguard Worker size_t index = it->GetIndex();
656*795d594fSAndroid Build Coastguard Worker ++it;
657*795d594fSAndroid Build Coastguard Worker if (!IsInOrigBBSet(env->GetHolder()->GetBlock())) {
658*795d594fSAndroid Build Coastguard Worker env->ReplaceInput(phi, index);
659*795d594fSAndroid Build Coastguard Worker }
660*795d594fSAndroid Build Coastguard Worker }
661*795d594fSAndroid Build Coastguard Worker
662*795d594fSAndroid Build Coastguard Worker phi->AddInput(value);
663*795d594fSAndroid Build Coastguard Worker }
664*795d594fSAndroid Build Coastguard Worker }
665*795d594fSAndroid Build Coastguard Worker
FixSubgraphClosedSSAAfterCloning()666*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::FixSubgraphClosedSSAAfterCloning() {
667*795d594fSAndroid Build Coastguard Worker for (auto it : live_outs_) {
668*795d594fSAndroid Build Coastguard Worker DCHECK(it.first != it.second);
669*795d594fSAndroid Build Coastguard Worker HInstruction* orig_value = it.first;
670*795d594fSAndroid Build Coastguard Worker HPhi* phi = it.second->AsPhi();
671*795d594fSAndroid Build Coastguard Worker HInstruction* copy_value = GetInstrCopy(orig_value);
672*795d594fSAndroid Build Coastguard Worker // Copy edges are inserted after the original so we can just add new input to the phi.
673*795d594fSAndroid Build Coastguard Worker phi->AddInput(copy_value);
674*795d594fSAndroid Build Coastguard Worker }
675*795d594fSAndroid Build Coastguard Worker }
676*795d594fSAndroid Build Coastguard Worker
677*795d594fSAndroid Build Coastguard Worker //
678*795d594fSAndroid Build Coastguard Worker // Debug and logging methods.
679*795d594fSAndroid Build Coastguard Worker //
680*795d594fSAndroid Build Coastguard Worker
681*795d594fSAndroid Build Coastguard Worker // Debug function to dump graph' BasicBlocks info.
DumpBB(HGraph * graph)682*795d594fSAndroid Build Coastguard Worker void DumpBB(HGraph* graph) {
683*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* bb : graph->GetBlocks()) {
684*795d594fSAndroid Build Coastguard Worker if (bb == nullptr) {
685*795d594fSAndroid Build Coastguard Worker continue;
686*795d594fSAndroid Build Coastguard Worker }
687*795d594fSAndroid Build Coastguard Worker std::ostringstream oss;
688*795d594fSAndroid Build Coastguard Worker oss << bb->GetBlockId();
689*795d594fSAndroid Build Coastguard Worker oss << " <- ";
690*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* pred : bb->GetPredecessors()) {
691*795d594fSAndroid Build Coastguard Worker oss << pred->GetBlockId() << " ";
692*795d594fSAndroid Build Coastguard Worker }
693*795d594fSAndroid Build Coastguard Worker oss << " -> ";
694*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* succ : bb->GetSuccessors()) {
695*795d594fSAndroid Build Coastguard Worker oss << succ->GetBlockId() << " ";
696*795d594fSAndroid Build Coastguard Worker }
697*795d594fSAndroid Build Coastguard Worker
698*795d594fSAndroid Build Coastguard Worker if (bb->GetDominator()) {
699*795d594fSAndroid Build Coastguard Worker oss << " dom " << bb->GetDominator()->GetBlockId();
700*795d594fSAndroid Build Coastguard Worker }
701*795d594fSAndroid Build Coastguard Worker
702*795d594fSAndroid Build Coastguard Worker if (bb->GetLoopInformation()) {
703*795d594fSAndroid Build Coastguard Worker oss << "\tloop: " << bb->GetLoopInformation()->GetHeader()->GetBlockId();
704*795d594fSAndroid Build Coastguard Worker }
705*795d594fSAndroid Build Coastguard Worker
706*795d594fSAndroid Build Coastguard Worker LOG(INFO) << oss.str();
707*795d594fSAndroid Build Coastguard Worker }
708*795d594fSAndroid Build Coastguard Worker }
709*795d594fSAndroid Build Coastguard Worker
CheckInstructionInputsRemapping(HInstruction * orig_instr)710*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::CheckInstructionInputsRemapping(HInstruction* orig_instr) {
711*795d594fSAndroid Build Coastguard Worker DCHECK(!orig_instr->IsPhi());
712*795d594fSAndroid Build Coastguard Worker HInstruction* copy_instr = GetInstrCopy(orig_instr);
713*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = orig_instr->InputCount(); i < e; i++) {
714*795d594fSAndroid Build Coastguard Worker HInstruction* orig_input = orig_instr->InputAt(i);
715*795d594fSAndroid Build Coastguard Worker DCHECK(orig_input->GetBlock()->Dominates(orig_instr->GetBlock()));
716*795d594fSAndroid Build Coastguard Worker
717*795d594fSAndroid Build Coastguard Worker // If original input is defined outside the region then it will remain for both original
718*795d594fSAndroid Build Coastguard Worker // instruction and the copy after the transformation.
719*795d594fSAndroid Build Coastguard Worker if (!IsInOrigBBSet(orig_input->GetBlock())) {
720*795d594fSAndroid Build Coastguard Worker continue;
721*795d594fSAndroid Build Coastguard Worker }
722*795d594fSAndroid Build Coastguard Worker HInstruction* copy_input = GetInstrCopy(orig_input);
723*795d594fSAndroid Build Coastguard Worker DCHECK(copy_input->GetBlock()->Dominates(copy_instr->GetBlock()));
724*795d594fSAndroid Build Coastguard Worker }
725*795d594fSAndroid Build Coastguard Worker
726*795d594fSAndroid Build Coastguard Worker // Resolve environment.
727*795d594fSAndroid Build Coastguard Worker if (orig_instr->HasEnvironment()) {
728*795d594fSAndroid Build Coastguard Worker HEnvironment* orig_env = orig_instr->GetEnvironment();
729*795d594fSAndroid Build Coastguard Worker
730*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = orig_env->Size(); i < e; ++i) {
731*795d594fSAndroid Build Coastguard Worker HInstruction* orig_input = orig_env->GetInstructionAt(i);
732*795d594fSAndroid Build Coastguard Worker
733*795d594fSAndroid Build Coastguard Worker // If original input is defined outside the region then it will remain for both original
734*795d594fSAndroid Build Coastguard Worker // instruction and the copy after the transformation.
735*795d594fSAndroid Build Coastguard Worker if (orig_input == nullptr || !IsInOrigBBSet(orig_input->GetBlock())) {
736*795d594fSAndroid Build Coastguard Worker continue;
737*795d594fSAndroid Build Coastguard Worker }
738*795d594fSAndroid Build Coastguard Worker
739*795d594fSAndroid Build Coastguard Worker HInstruction* copy_input = GetInstrCopy(orig_input);
740*795d594fSAndroid Build Coastguard Worker DCHECK(copy_input->GetBlock()->Dominates(copy_instr->GetBlock()));
741*795d594fSAndroid Build Coastguard Worker }
742*795d594fSAndroid Build Coastguard Worker }
743*795d594fSAndroid Build Coastguard Worker }
744*795d594fSAndroid Build Coastguard Worker
CheckRemappingInfoIsValid()745*795d594fSAndroid Build Coastguard Worker bool SuperblockCloner::CheckRemappingInfoIsValid() {
746*795d594fSAndroid Build Coastguard Worker for (HEdge edge : *remap_orig_internal_) {
747*795d594fSAndroid Build Coastguard Worker if (!IsEdgeValid(edge, graph_) ||
748*795d594fSAndroid Build Coastguard Worker !IsInOrigBBSet(edge.GetFrom()) ||
749*795d594fSAndroid Build Coastguard Worker !IsInOrigBBSet(edge.GetTo())) {
750*795d594fSAndroid Build Coastguard Worker return false;
751*795d594fSAndroid Build Coastguard Worker }
752*795d594fSAndroid Build Coastguard Worker }
753*795d594fSAndroid Build Coastguard Worker
754*795d594fSAndroid Build Coastguard Worker for (auto edge : *remap_copy_internal_) {
755*795d594fSAndroid Build Coastguard Worker if (!IsEdgeValid(edge, graph_) ||
756*795d594fSAndroid Build Coastguard Worker !IsInOrigBBSet(edge.GetFrom()) ||
757*795d594fSAndroid Build Coastguard Worker !IsInOrigBBSet(edge.GetTo())) {
758*795d594fSAndroid Build Coastguard Worker return false;
759*795d594fSAndroid Build Coastguard Worker }
760*795d594fSAndroid Build Coastguard Worker }
761*795d594fSAndroid Build Coastguard Worker
762*795d594fSAndroid Build Coastguard Worker for (auto edge : *remap_incoming_) {
763*795d594fSAndroid Build Coastguard Worker if (!IsEdgeValid(edge, graph_) ||
764*795d594fSAndroid Build Coastguard Worker IsInOrigBBSet(edge.GetFrom()) ||
765*795d594fSAndroid Build Coastguard Worker !IsInOrigBBSet(edge.GetTo())) {
766*795d594fSAndroid Build Coastguard Worker return false;
767*795d594fSAndroid Build Coastguard Worker }
768*795d594fSAndroid Build Coastguard Worker }
769*795d594fSAndroid Build Coastguard Worker
770*795d594fSAndroid Build Coastguard Worker return true;
771*795d594fSAndroid Build Coastguard Worker }
772*795d594fSAndroid Build Coastguard Worker
VerifyGraph()773*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::VerifyGraph() {
774*795d594fSAndroid Build Coastguard Worker for (auto it : *hir_map_) {
775*795d594fSAndroid Build Coastguard Worker HInstruction* orig_instr = it.first;
776*795d594fSAndroid Build Coastguard Worker HInstruction* copy_instr = it.second;
777*795d594fSAndroid Build Coastguard Worker if (!orig_instr->IsPhi() && !orig_instr->IsSuspendCheck()) {
778*795d594fSAndroid Build Coastguard Worker DCHECK(it.first->GetBlock() != nullptr);
779*795d594fSAndroid Build Coastguard Worker }
780*795d594fSAndroid Build Coastguard Worker if (!copy_instr->IsPhi() && !copy_instr->IsSuspendCheck()) {
781*795d594fSAndroid Build Coastguard Worker DCHECK(it.second->GetBlock() != nullptr);
782*795d594fSAndroid Build Coastguard Worker }
783*795d594fSAndroid Build Coastguard Worker }
784*795d594fSAndroid Build Coastguard Worker if (kSuperblockClonerVerify) {
785*795d594fSAndroid Build Coastguard Worker GraphChecker checker(graph_);
786*795d594fSAndroid Build Coastguard Worker checker.Run();
787*795d594fSAndroid Build Coastguard Worker if (!checker.IsValid()) {
788*795d594fSAndroid Build Coastguard Worker for (const std::string& error : checker.GetErrors()) {
789*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << error;
790*795d594fSAndroid Build Coastguard Worker }
791*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "GraphChecker failed: superblock cloner";
792*795d594fSAndroid Build Coastguard Worker }
793*795d594fSAndroid Build Coastguard Worker }
794*795d594fSAndroid Build Coastguard Worker }
795*795d594fSAndroid Build Coastguard Worker
DumpBBSet(const ArenaBitVector * set)796*795d594fSAndroid Build Coastguard Worker void DumpBBSet(const ArenaBitVector* set) {
797*795d594fSAndroid Build Coastguard Worker for (uint32_t idx : set->Indexes()) {
798*795d594fSAndroid Build Coastguard Worker LOG(INFO) << idx;
799*795d594fSAndroid Build Coastguard Worker }
800*795d594fSAndroid Build Coastguard Worker }
801*795d594fSAndroid Build Coastguard Worker
DumpInputSets()802*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::DumpInputSets() {
803*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "orig_bb_set:";
804*795d594fSAndroid Build Coastguard Worker for (uint32_t idx : orig_bb_set_.Indexes()) {
805*795d594fSAndroid Build Coastguard Worker LOG(INFO) << idx;
806*795d594fSAndroid Build Coastguard Worker }
807*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "remap_orig_internal:";
808*795d594fSAndroid Build Coastguard Worker for (HEdge e : *remap_orig_internal_) {
809*795d594fSAndroid Build Coastguard Worker LOG(INFO) << e;
810*795d594fSAndroid Build Coastguard Worker }
811*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "remap_copy_internal:";
812*795d594fSAndroid Build Coastguard Worker for (auto e : *remap_copy_internal_) {
813*795d594fSAndroid Build Coastguard Worker LOG(INFO) << e;
814*795d594fSAndroid Build Coastguard Worker }
815*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "remap_incoming:";
816*795d594fSAndroid Build Coastguard Worker for (auto e : *remap_incoming_) {
817*795d594fSAndroid Build Coastguard Worker LOG(INFO) << e;
818*795d594fSAndroid Build Coastguard Worker }
819*795d594fSAndroid Build Coastguard Worker }
820*795d594fSAndroid Build Coastguard Worker
821*795d594fSAndroid Build Coastguard Worker //
822*795d594fSAndroid Build Coastguard Worker // Public methods.
823*795d594fSAndroid Build Coastguard Worker //
824*795d594fSAndroid Build Coastguard Worker
SuperblockCloner(HGraph * graph,const HBasicBlockSet * orig_bb_set,HBasicBlockMap * bb_map,HInstructionMap * hir_map,InductionVarRange * induction_range)825*795d594fSAndroid Build Coastguard Worker SuperblockCloner::SuperblockCloner(HGraph* graph,
826*795d594fSAndroid Build Coastguard Worker const HBasicBlockSet* orig_bb_set,
827*795d594fSAndroid Build Coastguard Worker HBasicBlockMap* bb_map,
828*795d594fSAndroid Build Coastguard Worker HInstructionMap* hir_map,
829*795d594fSAndroid Build Coastguard Worker InductionVarRange* induction_range)
830*795d594fSAndroid Build Coastguard Worker : graph_(graph),
831*795d594fSAndroid Build Coastguard Worker arena_(graph->GetAllocator()),
832*795d594fSAndroid Build Coastguard Worker orig_bb_set_(arena_, orig_bb_set->GetSizeOf(), true, kArenaAllocSuperblockCloner),
833*795d594fSAndroid Build Coastguard Worker remap_orig_internal_(nullptr),
834*795d594fSAndroid Build Coastguard Worker remap_copy_internal_(nullptr),
835*795d594fSAndroid Build Coastguard Worker remap_incoming_(nullptr),
836*795d594fSAndroid Build Coastguard Worker bb_map_(bb_map),
837*795d594fSAndroid Build Coastguard Worker hir_map_(hir_map),
838*795d594fSAndroid Build Coastguard Worker induction_range_(induction_range),
839*795d594fSAndroid Build Coastguard Worker outer_loop_(nullptr),
840*795d594fSAndroid Build Coastguard Worker outer_loop_bb_set_(arena_, orig_bb_set->GetSizeOf(), true, kArenaAllocSuperblockCloner),
841*795d594fSAndroid Build Coastguard Worker live_outs_(std::less<HInstruction*>(),
842*795d594fSAndroid Build Coastguard Worker graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)) {
843*795d594fSAndroid Build Coastguard Worker orig_bb_set_.Copy(orig_bb_set);
844*795d594fSAndroid Build Coastguard Worker }
845*795d594fSAndroid Build Coastguard Worker
SetSuccessorRemappingInfo(const HEdgeSet * remap_orig_internal,const HEdgeSet * remap_copy_internal,const HEdgeSet * remap_incoming)846*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::SetSuccessorRemappingInfo(const HEdgeSet* remap_orig_internal,
847*795d594fSAndroid Build Coastguard Worker const HEdgeSet* remap_copy_internal,
848*795d594fSAndroid Build Coastguard Worker const HEdgeSet* remap_incoming) {
849*795d594fSAndroid Build Coastguard Worker remap_orig_internal_ = remap_orig_internal;
850*795d594fSAndroid Build Coastguard Worker remap_copy_internal_ = remap_copy_internal;
851*795d594fSAndroid Build Coastguard Worker remap_incoming_ = remap_incoming;
852*795d594fSAndroid Build Coastguard Worker DCHECK(CheckRemappingInfoIsValid());
853*795d594fSAndroid Build Coastguard Worker }
854*795d594fSAndroid Build Coastguard Worker
IsSubgraphClonable() const855*795d594fSAndroid Build Coastguard Worker bool SuperblockCloner::IsSubgraphClonable() const {
856*795d594fSAndroid Build Coastguard Worker // TODO: Support irreducible graphs and subgraphs with try-catch.
857*795d594fSAndroid Build Coastguard Worker if (graph_->HasIrreducibleLoops()) {
858*795d594fSAndroid Build Coastguard Worker return false;
859*795d594fSAndroid Build Coastguard Worker }
860*795d594fSAndroid Build Coastguard Worker
861*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph_->GetReversePostOrder()) {
862*795d594fSAndroid Build Coastguard Worker if (!IsInOrigBBSet(block)) {
863*795d594fSAndroid Build Coastguard Worker continue;
864*795d594fSAndroid Build Coastguard Worker }
865*795d594fSAndroid Build Coastguard Worker if (block->GetTryCatchInformation() != nullptr) {
866*795d594fSAndroid Build Coastguard Worker return false;
867*795d594fSAndroid Build Coastguard Worker }
868*795d594fSAndroid Build Coastguard Worker }
869*795d594fSAndroid Build Coastguard Worker
870*795d594fSAndroid Build Coastguard Worker HInstructionMap live_outs(
871*795d594fSAndroid Build Coastguard Worker std::less<HInstruction*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
872*795d594fSAndroid Build Coastguard Worker
873*795d594fSAndroid Build Coastguard Worker if (!CollectLiveOutsAndCheckClonable(&live_outs)) {
874*795d594fSAndroid Build Coastguard Worker return false;
875*795d594fSAndroid Build Coastguard Worker }
876*795d594fSAndroid Build Coastguard Worker
877*795d594fSAndroid Build Coastguard Worker ArenaVector<HBasicBlock*> exits(arena_->Adapter(kArenaAllocSuperblockCloner));
878*795d594fSAndroid Build Coastguard Worker SearchForSubgraphExits(&exits);
879*795d594fSAndroid Build Coastguard Worker
880*795d594fSAndroid Build Coastguard Worker // The only loops with live-outs which are currently supported are loops with a single exit.
881*795d594fSAndroid Build Coastguard Worker if (!live_outs.empty() && exits.size() != 1) {
882*795d594fSAndroid Build Coastguard Worker return false;
883*795d594fSAndroid Build Coastguard Worker }
884*795d594fSAndroid Build Coastguard Worker
885*795d594fSAndroid Build Coastguard Worker // The values in live_outs should be defined in a block that dominates exit_block.
886*795d594fSAndroid Build Coastguard Worker for (const auto& live_out : live_outs) {
887*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(exits.size(), 1u);
888*795d594fSAndroid Build Coastguard Worker HInstruction* value = live_out.first;
889*795d594fSAndroid Build Coastguard Worker if (!value->GetBlock()->Dominates(exits[0])) {
890*795d594fSAndroid Build Coastguard Worker // This case can only happen when `value` is used in a catch phi, so the graph must contain a
891*795d594fSAndroid Build Coastguard Worker // catch block.
892*795d594fSAndroid Build Coastguard Worker DCHECK(graph_->HasTryCatch());
893*795d594fSAndroid Build Coastguard Worker return false;
894*795d594fSAndroid Build Coastguard Worker }
895*795d594fSAndroid Build Coastguard Worker }
896*795d594fSAndroid Build Coastguard Worker
897*795d594fSAndroid Build Coastguard Worker return true;
898*795d594fSAndroid Build Coastguard Worker }
899*795d594fSAndroid Build Coastguard Worker
900*795d594fSAndroid Build Coastguard Worker // Checks that loop unrolling/peeling/versioning is being conducted.
IsFastCase() const901*795d594fSAndroid Build Coastguard Worker bool SuperblockCloner::IsFastCase() const {
902*795d594fSAndroid Build Coastguard Worker // Check that all the basic blocks belong to the same loop.
903*795d594fSAndroid Build Coastguard Worker bool flag = false;
904*795d594fSAndroid Build Coastguard Worker HLoopInformation* common_loop_info = nullptr;
905*795d594fSAndroid Build Coastguard Worker for (uint32_t idx : orig_bb_set_.Indexes()) {
906*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = GetBlockById(idx);
907*795d594fSAndroid Build Coastguard Worker HLoopInformation* block_loop_info = block->GetLoopInformation();
908*795d594fSAndroid Build Coastguard Worker if (!flag) {
909*795d594fSAndroid Build Coastguard Worker common_loop_info = block_loop_info;
910*795d594fSAndroid Build Coastguard Worker } else {
911*795d594fSAndroid Build Coastguard Worker if (block_loop_info != common_loop_info) {
912*795d594fSAndroid Build Coastguard Worker return false;
913*795d594fSAndroid Build Coastguard Worker }
914*795d594fSAndroid Build Coastguard Worker }
915*795d594fSAndroid Build Coastguard Worker }
916*795d594fSAndroid Build Coastguard Worker
917*795d594fSAndroid Build Coastguard Worker // Check that orig_bb_set_ corresponds to loop peeling/unrolling/versioning.
918*795d594fSAndroid Build Coastguard Worker if (common_loop_info == nullptr || !orig_bb_set_.SameBitsSet(&common_loop_info->GetBlocks())) {
919*795d594fSAndroid Build Coastguard Worker return false;
920*795d594fSAndroid Build Coastguard Worker }
921*795d594fSAndroid Build Coastguard Worker
922*795d594fSAndroid Build Coastguard Worker if (IsRemapInfoForVersioning()) {
923*795d594fSAndroid Build Coastguard Worker return true;
924*795d594fSAndroid Build Coastguard Worker }
925*795d594fSAndroid Build Coastguard Worker
926*795d594fSAndroid Build Coastguard Worker bool peeling_or_unrolling = false;
927*795d594fSAndroid Build Coastguard Worker HEdgeSet remap_orig_internal(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
928*795d594fSAndroid Build Coastguard Worker HEdgeSet remap_copy_internal(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
929*795d594fSAndroid Build Coastguard Worker HEdgeSet remap_incoming(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
930*795d594fSAndroid Build Coastguard Worker
931*795d594fSAndroid Build Coastguard Worker
932*795d594fSAndroid Build Coastguard Worker // Check whether remapping info corresponds to loop unrolling.
933*795d594fSAndroid Build Coastguard Worker CollectRemappingInfoForPeelUnroll(/* to_unroll*/ true,
934*795d594fSAndroid Build Coastguard Worker common_loop_info,
935*795d594fSAndroid Build Coastguard Worker &remap_orig_internal,
936*795d594fSAndroid Build Coastguard Worker &remap_copy_internal,
937*795d594fSAndroid Build Coastguard Worker &remap_incoming);
938*795d594fSAndroid Build Coastguard Worker
939*795d594fSAndroid Build Coastguard Worker peeling_or_unrolling |= EdgeHashSetsEqual(&remap_orig_internal, remap_orig_internal_) &&
940*795d594fSAndroid Build Coastguard Worker EdgeHashSetsEqual(&remap_copy_internal, remap_copy_internal_) &&
941*795d594fSAndroid Build Coastguard Worker EdgeHashSetsEqual(&remap_incoming, remap_incoming_);
942*795d594fSAndroid Build Coastguard Worker
943*795d594fSAndroid Build Coastguard Worker remap_orig_internal.clear();
944*795d594fSAndroid Build Coastguard Worker remap_copy_internal.clear();
945*795d594fSAndroid Build Coastguard Worker remap_incoming.clear();
946*795d594fSAndroid Build Coastguard Worker
947*795d594fSAndroid Build Coastguard Worker // Check whether remapping info corresponds to loop peeling.
948*795d594fSAndroid Build Coastguard Worker CollectRemappingInfoForPeelUnroll(/* to_unroll*/ false,
949*795d594fSAndroid Build Coastguard Worker common_loop_info,
950*795d594fSAndroid Build Coastguard Worker &remap_orig_internal,
951*795d594fSAndroid Build Coastguard Worker &remap_copy_internal,
952*795d594fSAndroid Build Coastguard Worker &remap_incoming);
953*795d594fSAndroid Build Coastguard Worker
954*795d594fSAndroid Build Coastguard Worker peeling_or_unrolling |= EdgeHashSetsEqual(&remap_orig_internal, remap_orig_internal_) &&
955*795d594fSAndroid Build Coastguard Worker EdgeHashSetsEqual(&remap_copy_internal, remap_copy_internal_) &&
956*795d594fSAndroid Build Coastguard Worker EdgeHashSetsEqual(&remap_incoming, remap_incoming_);
957*795d594fSAndroid Build Coastguard Worker
958*795d594fSAndroid Build Coastguard Worker return peeling_or_unrolling;
959*795d594fSAndroid Build Coastguard Worker }
960*795d594fSAndroid Build Coastguard Worker
Run()961*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::Run() {
962*795d594fSAndroid Build Coastguard Worker DCHECK(bb_map_ != nullptr);
963*795d594fSAndroid Build Coastguard Worker DCHECK(hir_map_ != nullptr);
964*795d594fSAndroid Build Coastguard Worker DCHECK(remap_orig_internal_ != nullptr &&
965*795d594fSAndroid Build Coastguard Worker remap_copy_internal_ != nullptr &&
966*795d594fSAndroid Build Coastguard Worker remap_incoming_ != nullptr);
967*795d594fSAndroid Build Coastguard Worker DCHECK(IsSubgraphClonable());
968*795d594fSAndroid Build Coastguard Worker DCHECK(IsFastCase());
969*795d594fSAndroid Build Coastguard Worker
970*795d594fSAndroid Build Coastguard Worker if (kSuperblockClonerLogging) {
971*795d594fSAndroid Build Coastguard Worker DumpInputSets();
972*795d594fSAndroid Build Coastguard Worker }
973*795d594fSAndroid Build Coastguard Worker
974*795d594fSAndroid Build Coastguard Worker bool result = CollectLiveOutsAndCheckClonable(&live_outs_);
975*795d594fSAndroid Build Coastguard Worker DCHECK(result);
976*795d594fSAndroid Build Coastguard Worker // Find an area in the graph for which control flow information should be adjusted.
977*795d594fSAndroid Build Coastguard Worker FindAndSetLocalAreaForAdjustments();
978*795d594fSAndroid Build Coastguard Worker ConstructSubgraphClosedSSA();
979*795d594fSAndroid Build Coastguard Worker // Clone the basic blocks from the orig_bb_set_; data flow is invalid after the call and is to be
980*795d594fSAndroid Build Coastguard Worker // adjusted.
981*795d594fSAndroid Build Coastguard Worker CloneBasicBlocks();
982*795d594fSAndroid Build Coastguard Worker // Connect the blocks together/remap successors and fix phis which are directly affected my the
983*795d594fSAndroid Build Coastguard Worker // remapping.
984*795d594fSAndroid Build Coastguard Worker RemapEdgesSuccessors();
985*795d594fSAndroid Build Coastguard Worker
986*795d594fSAndroid Build Coastguard Worker // Check that the subgraph is connected.
987*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
988*795d594fSAndroid Build Coastguard Worker HBasicBlockSet work_set(arena_, orig_bb_set_.GetSizeOf(), true, kArenaAllocSuperblockCloner);
989*795d594fSAndroid Build Coastguard Worker
990*795d594fSAndroid Build Coastguard Worker // Add original and copy blocks of the subgraph to the work set.
991*795d594fSAndroid Build Coastguard Worker for (auto iter : *bb_map_) {
992*795d594fSAndroid Build Coastguard Worker work_set.SetBit(iter.first->GetBlockId()); // Original block.
993*795d594fSAndroid Build Coastguard Worker work_set.SetBit(iter.second->GetBlockId()); // Copy block.
994*795d594fSAndroid Build Coastguard Worker }
995*795d594fSAndroid Build Coastguard Worker CHECK(IsSubgraphConnected(&work_set, graph_));
996*795d594fSAndroid Build Coastguard Worker }
997*795d594fSAndroid Build Coastguard Worker
998*795d594fSAndroid Build Coastguard Worker // Recalculate dominance and backedge information which is required by the next stage.
999*795d594fSAndroid Build Coastguard Worker AdjustControlFlowInfo();
1000*795d594fSAndroid Build Coastguard Worker // Fix data flow of the graph.
1001*795d594fSAndroid Build Coastguard Worker ResolveDataFlow();
1002*795d594fSAndroid Build Coastguard Worker FixSubgraphClosedSSAAfterCloning();
1003*795d594fSAndroid Build Coastguard Worker }
1004*795d594fSAndroid Build Coastguard Worker
CleanUp()1005*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::CleanUp() {
1006*795d594fSAndroid Build Coastguard Worker CleanUpControlFlow();
1007*795d594fSAndroid Build Coastguard Worker
1008*795d594fSAndroid Build Coastguard Worker // Remove phis which have all inputs being same.
1009*795d594fSAndroid Build Coastguard Worker // When a block has a single predecessor it must not have any phis. However after the
1010*795d594fSAndroid Build Coastguard Worker // transformation it could happen that there is such block with a phi with a single input.
1011*795d594fSAndroid Build Coastguard Worker // As this is needed to be processed we also simplify phis with multiple same inputs here.
1012*795d594fSAndroid Build Coastguard Worker for (auto entry : *bb_map_) {
1013*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : {entry.first, entry.second}) {
1014*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
1015*795d594fSAndroid Build Coastguard Worker HPhi* phi = inst_it.Current()->AsPhi();
1016*795d594fSAndroid Build Coastguard Worker if (ArePhiInputsTheSame(phi)) {
1017*795d594fSAndroid Build Coastguard Worker phi->ReplaceWith(phi->InputAt(0));
1018*795d594fSAndroid Build Coastguard Worker block->RemovePhi(phi);
1019*795d594fSAndroid Build Coastguard Worker }
1020*795d594fSAndroid Build Coastguard Worker }
1021*795d594fSAndroid Build Coastguard Worker }
1022*795d594fSAndroid Build Coastguard Worker }
1023*795d594fSAndroid Build Coastguard Worker
1024*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1025*795d594fSAndroid Build Coastguard Worker VerifyGraph();
1026*795d594fSAndroid Build Coastguard Worker }
1027*795d594fSAndroid Build Coastguard Worker }
1028*795d594fSAndroid Build Coastguard Worker
CloneBasicBlock(const HBasicBlock * orig_block)1029*795d594fSAndroid Build Coastguard Worker HBasicBlock* SuperblockCloner::CloneBasicBlock(const HBasicBlock* orig_block) {
1030*795d594fSAndroid Build Coastguard Worker HGraph* graph = orig_block->GetGraph();
1031*795d594fSAndroid Build Coastguard Worker HBasicBlock* copy_block = new (arena_) HBasicBlock(graph, orig_block->GetDexPc());
1032*795d594fSAndroid Build Coastguard Worker graph->AddBlock(copy_block);
1033*795d594fSAndroid Build Coastguard Worker
1034*795d594fSAndroid Build Coastguard Worker // Clone all the phis and add them to the map.
1035*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(orig_block->GetPhis()); !it.Done(); it.Advance()) {
1036*795d594fSAndroid Build Coastguard Worker HInstruction* orig_instr = it.Current();
1037*795d594fSAndroid Build Coastguard Worker HInstruction* copy_instr = orig_instr->Clone(arena_);
1038*795d594fSAndroid Build Coastguard Worker copy_block->AddPhi(copy_instr->AsPhi());
1039*795d594fSAndroid Build Coastguard Worker copy_instr->AsPhi()->RemoveAllInputs();
1040*795d594fSAndroid Build Coastguard Worker DCHECK(!orig_instr->HasEnvironment());
1041*795d594fSAndroid Build Coastguard Worker hir_map_->Put(orig_instr, copy_instr);
1042*795d594fSAndroid Build Coastguard Worker }
1043*795d594fSAndroid Build Coastguard Worker
1044*795d594fSAndroid Build Coastguard Worker // Clone all the instructions and add them to the map.
1045*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(orig_block->GetInstructions()); !it.Done(); it.Advance()) {
1046*795d594fSAndroid Build Coastguard Worker HInstruction* orig_instr = it.Current();
1047*795d594fSAndroid Build Coastguard Worker HInstruction* copy_instr = orig_instr->Clone(arena_);
1048*795d594fSAndroid Build Coastguard Worker ReplaceInputsWithCopies(copy_instr);
1049*795d594fSAndroid Build Coastguard Worker copy_block->AddInstruction(copy_instr);
1050*795d594fSAndroid Build Coastguard Worker if (orig_instr->HasEnvironment()) {
1051*795d594fSAndroid Build Coastguard Worker DeepCloneEnvironmentWithRemapping(copy_instr, orig_instr->GetEnvironment());
1052*795d594fSAndroid Build Coastguard Worker }
1053*795d594fSAndroid Build Coastguard Worker hir_map_->Put(orig_instr, copy_instr);
1054*795d594fSAndroid Build Coastguard Worker }
1055*795d594fSAndroid Build Coastguard Worker
1056*795d594fSAndroid Build Coastguard Worker return copy_block;
1057*795d594fSAndroid Build Coastguard Worker }
1058*795d594fSAndroid Build Coastguard Worker
CloneBasicBlocks()1059*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::CloneBasicBlocks() {
1060*795d594fSAndroid Build Coastguard Worker // By this time ReversePostOrder must be valid: in 'CloneBasicBlock' inputs of the copied
1061*795d594fSAndroid Build Coastguard Worker // instructions might be replaced by copies of the original inputs (depending where those inputs
1062*795d594fSAndroid Build Coastguard Worker // are defined). So the definitions of the original inputs must be visited before their original
1063*795d594fSAndroid Build Coastguard Worker // uses. The property of the reducible graphs "if 'A' dom 'B' then rpo_num('A') >= rpo_num('B')"
1064*795d594fSAndroid Build Coastguard Worker // guarantees that.
1065*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* orig_block : graph_->GetReversePostOrder()) {
1066*795d594fSAndroid Build Coastguard Worker if (!IsInOrigBBSet(orig_block)) {
1067*795d594fSAndroid Build Coastguard Worker continue;
1068*795d594fSAndroid Build Coastguard Worker }
1069*795d594fSAndroid Build Coastguard Worker HBasicBlock* copy_block = CloneBasicBlock(orig_block);
1070*795d594fSAndroid Build Coastguard Worker bb_map_->Put(orig_block, copy_block);
1071*795d594fSAndroid Build Coastguard Worker if (kSuperblockClonerLogging) {
1072*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "new block :" << copy_block->GetBlockId() << ": " << orig_block->GetBlockId();
1073*795d594fSAndroid Build Coastguard Worker }
1074*795d594fSAndroid Build Coastguard Worker }
1075*795d594fSAndroid Build Coastguard Worker }
1076*795d594fSAndroid Build Coastguard Worker
1077*795d594fSAndroid Build Coastguard Worker //
1078*795d594fSAndroid Build Coastguard Worker // Stand-alone methods.
1079*795d594fSAndroid Build Coastguard Worker //
1080*795d594fSAndroid Build Coastguard Worker
CollectRemappingInfoForPeelUnroll(bool to_unroll,HLoopInformation * loop_info,HEdgeSet * remap_orig_internal,HEdgeSet * remap_copy_internal,HEdgeSet * remap_incoming)1081*795d594fSAndroid Build Coastguard Worker void CollectRemappingInfoForPeelUnroll(bool to_unroll,
1082*795d594fSAndroid Build Coastguard Worker HLoopInformation* loop_info,
1083*795d594fSAndroid Build Coastguard Worker HEdgeSet* remap_orig_internal,
1084*795d594fSAndroid Build Coastguard Worker HEdgeSet* remap_copy_internal,
1085*795d594fSAndroid Build Coastguard Worker HEdgeSet* remap_incoming) {
1086*795d594fSAndroid Build Coastguard Worker DCHECK(loop_info != nullptr);
1087*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_header = loop_info->GetHeader();
1088*795d594fSAndroid Build Coastguard Worker // Set up remap_orig_internal edges set - set is empty.
1089*795d594fSAndroid Build Coastguard Worker // Set up remap_copy_internal edges set.
1090*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* back_edge_block : loop_info->GetBackEdges()) {
1091*795d594fSAndroid Build Coastguard Worker HEdge e = HEdge(back_edge_block, loop_header);
1092*795d594fSAndroid Build Coastguard Worker if (to_unroll) {
1093*795d594fSAndroid Build Coastguard Worker remap_orig_internal->insert(e);
1094*795d594fSAndroid Build Coastguard Worker remap_copy_internal->insert(e);
1095*795d594fSAndroid Build Coastguard Worker } else {
1096*795d594fSAndroid Build Coastguard Worker remap_copy_internal->insert(e);
1097*795d594fSAndroid Build Coastguard Worker }
1098*795d594fSAndroid Build Coastguard Worker }
1099*795d594fSAndroid Build Coastguard Worker
1100*795d594fSAndroid Build Coastguard Worker // Set up remap_incoming edges set.
1101*795d594fSAndroid Build Coastguard Worker if (!to_unroll) {
1102*795d594fSAndroid Build Coastguard Worker remap_incoming->insert(HEdge(loop_info->GetPreHeader(), loop_header));
1103*795d594fSAndroid Build Coastguard Worker }
1104*795d594fSAndroid Build Coastguard Worker }
1105*795d594fSAndroid Build Coastguard Worker
IsSubgraphConnected(SuperblockCloner::HBasicBlockSet * work_set,HGraph * graph)1106*795d594fSAndroid Build Coastguard Worker bool IsSubgraphConnected(SuperblockCloner::HBasicBlockSet* work_set, HGraph* graph) {
1107*795d594fSAndroid Build Coastguard Worker ArenaVector<HBasicBlock*> entry_blocks(
1108*795d594fSAndroid Build Coastguard Worker graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1109*795d594fSAndroid Build Coastguard Worker
1110*795d594fSAndroid Build Coastguard Worker // Find subgraph entry blocks.
1111*795d594fSAndroid Build Coastguard Worker for (uint32_t orig_block_id : work_set->Indexes()) {
1112*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = graph->GetBlocks()[orig_block_id];
1113*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* pred : block->GetPredecessors()) {
1114*795d594fSAndroid Build Coastguard Worker if (!work_set->IsBitSet(pred->GetBlockId())) {
1115*795d594fSAndroid Build Coastguard Worker entry_blocks.push_back(block);
1116*795d594fSAndroid Build Coastguard Worker break;
1117*795d594fSAndroid Build Coastguard Worker }
1118*795d594fSAndroid Build Coastguard Worker }
1119*795d594fSAndroid Build Coastguard Worker }
1120*795d594fSAndroid Build Coastguard Worker
1121*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* entry_block : entry_blocks) {
1122*795d594fSAndroid Build Coastguard Worker if (work_set->IsBitSet(entry_block->GetBlockId())) {
1123*795d594fSAndroid Build Coastguard Worker TraverseSubgraphForConnectivity(entry_block, work_set);
1124*795d594fSAndroid Build Coastguard Worker }
1125*795d594fSAndroid Build Coastguard Worker }
1126*795d594fSAndroid Build Coastguard Worker
1127*795d594fSAndroid Build Coastguard Worker // Return whether there are unvisited - unreachable - blocks.
1128*795d594fSAndroid Build Coastguard Worker return work_set->NumSetBits() == 0;
1129*795d594fSAndroid Build Coastguard Worker }
1130*795d594fSAndroid Build Coastguard Worker
FindCommonLoop(HLoopInformation * loop1,HLoopInformation * loop2)1131*795d594fSAndroid Build Coastguard Worker HLoopInformation* FindCommonLoop(HLoopInformation* loop1, HLoopInformation* loop2) {
1132*795d594fSAndroid Build Coastguard Worker if (loop1 == nullptr || loop2 == nullptr) {
1133*795d594fSAndroid Build Coastguard Worker return nullptr;
1134*795d594fSAndroid Build Coastguard Worker }
1135*795d594fSAndroid Build Coastguard Worker
1136*795d594fSAndroid Build Coastguard Worker if (loop1->IsIn(*loop2)) {
1137*795d594fSAndroid Build Coastguard Worker return loop2;
1138*795d594fSAndroid Build Coastguard Worker }
1139*795d594fSAndroid Build Coastguard Worker
1140*795d594fSAndroid Build Coastguard Worker HLoopInformation* current = loop1;
1141*795d594fSAndroid Build Coastguard Worker while (current != nullptr && !loop2->IsIn(*current)) {
1142*795d594fSAndroid Build Coastguard Worker current = current->GetPreHeader()->GetLoopInformation();
1143*795d594fSAndroid Build Coastguard Worker }
1144*795d594fSAndroid Build Coastguard Worker
1145*795d594fSAndroid Build Coastguard Worker return current;
1146*795d594fSAndroid Build Coastguard Worker }
1147*795d594fSAndroid Build Coastguard Worker
IsLoopClonable(HLoopInformation * loop_info)1148*795d594fSAndroid Build Coastguard Worker bool LoopClonerHelper::IsLoopClonable(HLoopInformation* loop_info) {
1149*795d594fSAndroid Build Coastguard Worker LoopClonerHelper helper(
1150*795d594fSAndroid Build Coastguard Worker loop_info, /* bb_map= */ nullptr, /* hir_map= */ nullptr, /* induction_range= */ nullptr);
1151*795d594fSAndroid Build Coastguard Worker return helper.IsLoopClonable();
1152*795d594fSAndroid Build Coastguard Worker }
1153*795d594fSAndroid Build Coastguard Worker
DoLoopTransformationImpl(TransformationKind transformation)1154*795d594fSAndroid Build Coastguard Worker HBasicBlock* LoopClonerHelper::DoLoopTransformationImpl(TransformationKind transformation) {
1155*795d594fSAndroid Build Coastguard Worker // For now do transformations only for natural loops.
1156*795d594fSAndroid Build Coastguard Worker DCHECK(!loop_info_->IsIrreducible());
1157*795d594fSAndroid Build Coastguard Worker
1158*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_header = loop_info_->GetHeader();
1159*795d594fSAndroid Build Coastguard Worker // Check that loop info is up-to-date.
1160*795d594fSAndroid Build Coastguard Worker DCHECK(loop_info_ == loop_header->GetLoopInformation());
1161*795d594fSAndroid Build Coastguard Worker HGraph* graph = loop_header->GetGraph();
1162*795d594fSAndroid Build Coastguard Worker
1163*795d594fSAndroid Build Coastguard Worker if (kSuperblockClonerLogging) {
1164*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "Method: " << graph->PrettyMethod();
1165*795d594fSAndroid Build Coastguard Worker std::ostringstream oss;
1166*795d594fSAndroid Build Coastguard Worker oss << "Scalar loop ";
1167*795d594fSAndroid Build Coastguard Worker switch (transformation) {
1168*795d594fSAndroid Build Coastguard Worker case TransformationKind::kPeeling:
1169*795d594fSAndroid Build Coastguard Worker oss << "peeling";
1170*795d594fSAndroid Build Coastguard Worker break;
1171*795d594fSAndroid Build Coastguard Worker case TransformationKind::kUnrolling:
1172*795d594fSAndroid Build Coastguard Worker oss<< "unrolling";
1173*795d594fSAndroid Build Coastguard Worker break;
1174*795d594fSAndroid Build Coastguard Worker case TransformationKind::kVersioning:
1175*795d594fSAndroid Build Coastguard Worker oss << "versioning";
1176*795d594fSAndroid Build Coastguard Worker break;
1177*795d594fSAndroid Build Coastguard Worker }
1178*795d594fSAndroid Build Coastguard Worker oss << " was applied to the loop <" << loop_header->GetBlockId() << ">.";
1179*795d594fSAndroid Build Coastguard Worker LOG(INFO) << oss.str();
1180*795d594fSAndroid Build Coastguard Worker }
1181*795d594fSAndroid Build Coastguard Worker
1182*795d594fSAndroid Build Coastguard Worker ArenaAllocator allocator(graph->GetAllocator()->GetArenaPool());
1183*795d594fSAndroid Build Coastguard Worker
1184*795d594fSAndroid Build Coastguard Worker HEdgeSet remap_orig_internal(graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1185*795d594fSAndroid Build Coastguard Worker HEdgeSet remap_copy_internal(graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1186*795d594fSAndroid Build Coastguard Worker HEdgeSet remap_incoming(graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1187*795d594fSAndroid Build Coastguard Worker
1188*795d594fSAndroid Build Coastguard Worker // No remapping needed for loop versioning.
1189*795d594fSAndroid Build Coastguard Worker if (transformation != TransformationKind::kVersioning) {
1190*795d594fSAndroid Build Coastguard Worker CollectRemappingInfoForPeelUnroll(transformation == TransformationKind::kUnrolling,
1191*795d594fSAndroid Build Coastguard Worker loop_info_,
1192*795d594fSAndroid Build Coastguard Worker &remap_orig_internal,
1193*795d594fSAndroid Build Coastguard Worker &remap_copy_internal,
1194*795d594fSAndroid Build Coastguard Worker &remap_incoming);
1195*795d594fSAndroid Build Coastguard Worker }
1196*795d594fSAndroid Build Coastguard Worker
1197*795d594fSAndroid Build Coastguard Worker cloner_.SetSuccessorRemappingInfo(&remap_orig_internal, &remap_copy_internal, &remap_incoming);
1198*795d594fSAndroid Build Coastguard Worker cloner_.Run();
1199*795d594fSAndroid Build Coastguard Worker cloner_.CleanUp();
1200*795d594fSAndroid Build Coastguard Worker
1201*795d594fSAndroid Build Coastguard Worker // Check that loop info is preserved.
1202*795d594fSAndroid Build Coastguard Worker DCHECK(loop_info_ == loop_header->GetLoopInformation());
1203*795d594fSAndroid Build Coastguard Worker
1204*795d594fSAndroid Build Coastguard Worker return loop_header;
1205*795d594fSAndroid Build Coastguard Worker }
1206*795d594fSAndroid Build Coastguard Worker
LoopClonerSimpleHelper(HLoopInformation * info,InductionVarRange * induction_range)1207*795d594fSAndroid Build Coastguard Worker LoopClonerSimpleHelper::LoopClonerSimpleHelper(HLoopInformation* info,
1208*795d594fSAndroid Build Coastguard Worker InductionVarRange* induction_range)
1209*795d594fSAndroid Build Coastguard Worker : bb_map_(std::less<HBasicBlock*>(),
1210*795d594fSAndroid Build Coastguard Worker info->GetHeader()->GetGraph()->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)),
1211*795d594fSAndroid Build Coastguard Worker hir_map_(std::less<HInstruction*>(),
1212*795d594fSAndroid Build Coastguard Worker info->GetHeader()->GetGraph()->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)),
1213*795d594fSAndroid Build Coastguard Worker helper_(info, &bb_map_, &hir_map_, induction_range) {}
1214*795d594fSAndroid Build Coastguard Worker
1215*795d594fSAndroid Build Coastguard Worker } // namespace art
1216*795d594fSAndroid Build Coastguard Worker
1217*795d594fSAndroid Build Coastguard Worker namespace std {
1218*795d594fSAndroid Build Coastguard Worker
operator <<(ostream & os,const art::HEdge & e)1219*795d594fSAndroid Build Coastguard Worker ostream& operator<<(ostream& os, const art::HEdge& e) {
1220*795d594fSAndroid Build Coastguard Worker e.Dump(os);
1221*795d594fSAndroid Build Coastguard Worker return os;
1222*795d594fSAndroid Build Coastguard Worker }
1223*795d594fSAndroid Build Coastguard Worker
1224*795d594fSAndroid Build Coastguard Worker } // namespace std
1225