blob: 4a574b07540678e3d362b4999d960871efb4d248 [file] [log] [blame]
Nicolas Geoffray818f2102014-02-18 16:43:35 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "nodes.h"
Calin Juravle77520bc2015-01-12 18:45:46 +000018
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010019#include "ssa_builder.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000020#include "utils/growable_array.h"
21
22namespace art {
23
24void HGraph::AddBlock(HBasicBlock* block) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +000025 block->SetBlockId(blocks_.Size());
Nicolas Geoffray818f2102014-02-18 16:43:35 +000026 blocks_.Add(block);
27}
28
Nicolas Geoffray804d0932014-05-02 08:46:00 +010029void HGraph::FindBackEdges(ArenaBitVector* visited) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000030 ArenaBitVector visiting(arena_, blocks_.Size(), false);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000031 VisitBlockForBackEdges(entry_block_, visited, &visiting);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000032}
33
Roland Levillainfc600dc2014-12-02 17:16:31 +000034static void RemoveAsUser(HInstruction* instruction) {
35 for (size_t i = 0; i < instruction->InputCount(); i++) {
36 instruction->InputAt(i)->RemoveUser(instruction, i);
37 }
38
39 HEnvironment* environment = instruction->GetEnvironment();
40 if (environment != nullptr) {
41 for (size_t i = 0, e = environment->Size(); i < e; ++i) {
David Brazdiled596192015-01-23 10:39:45 +000042 HUseListNode<HEnvironment*>* vreg_env_use = environment->GetInstructionEnvUseAt(i);
43 if (vreg_env_use != nullptr) {
44 HInstruction* vreg = environment->GetInstructionAt(i);
45 DCHECK(vreg != nullptr);
46 vreg->RemoveEnvironmentUser(vreg_env_use);
Roland Levillainfc600dc2014-12-02 17:16:31 +000047 }
48 }
49 }
50}
51
52void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const {
53 for (size_t i = 0; i < blocks_.Size(); ++i) {
54 if (!visited.IsBitSet(i)) {
55 HBasicBlock* block = blocks_.Get(i);
56 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
57 RemoveAsUser(it.Current());
58 }
59 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
60 RemoveAsUser(it.Current());
61 }
62 }
63 }
64}
65
Jean Christophe Beyler53d9da82014-12-04 13:28:25 -080066void HGraph::RemoveBlock(HBasicBlock* block) const {
67 for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
68 block->GetSuccessors().Get(j)->RemovePredecessor(block);
69 }
70 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
71 block->RemovePhi(it.Current()->AsPhi());
72 }
73 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
74 block->RemoveInstruction(it.Current());
75 }
76}
77
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000078void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010079 for (size_t i = 0; i < blocks_.Size(); ++i) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000080 if (!visited.IsBitSet(i)) {
Jean Christophe Beyler53d9da82014-12-04 13:28:25 -080081 RemoveBlock(blocks_.Get(i));
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000082 }
83 }
84}
85
86void HGraph::VisitBlockForBackEdges(HBasicBlock* block,
87 ArenaBitVector* visited,
Nicolas Geoffray804d0932014-05-02 08:46:00 +010088 ArenaBitVector* visiting) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +000089 int id = block->GetBlockId();
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000090 if (visited->IsBitSet(id)) return;
91
92 visited->SetBit(id);
93 visiting->SetBit(id);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010094 for (size_t i = 0; i < block->GetSuccessors().Size(); i++) {
95 HBasicBlock* successor = block->GetSuccessors().Get(i);
Nicolas Geoffray787c3072014-03-17 10:20:19 +000096 if (visiting->IsBitSet(successor->GetBlockId())) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000097 successor->AddBackEdge(block);
98 } else {
99 VisitBlockForBackEdges(successor, visited, visiting);
100 }
101 }
102 visiting->ClearBit(id);
103}
104
105void HGraph::BuildDominatorTree() {
106 ArenaBitVector visited(arena_, blocks_.Size(), false);
107
108 // (1) Find the back edges in the graph doing a DFS traversal.
109 FindBackEdges(&visited);
110
Roland Levillainfc600dc2014-12-02 17:16:31 +0000111 // (2) Remove instructions and phis from blocks not visited during
112 // the initial DFS as users from other instructions, so that
113 // users can be safely removed before uses later.
114 RemoveInstructionsAsUsersFromDeadBlocks(visited);
115
116 // (3) Remove blocks not visited during the initial DFS.
117 // Step (4) requires dead blocks to be removed from the
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000118 // predecessors list of live blocks.
119 RemoveDeadBlocks(visited);
120
Roland Levillainfc600dc2014-12-02 17:16:31 +0000121 // (4) Simplify the CFG now, so that we don't need to recompute
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100122 // dominators and the reverse post order.
123 SimplifyCFG();
124
Roland Levillainfc600dc2014-12-02 17:16:31 +0000125 // (5) Compute the immediate dominator of each block. We visit
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000126 // the successors of a block only when all its forward branches
127 // have been processed.
128 GrowableArray<size_t> visits(arena_, blocks_.Size());
129 visits.SetSize(blocks_.Size());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100130 reverse_post_order_.Add(entry_block_);
131 for (size_t i = 0; i < entry_block_->GetSuccessors().Size(); i++) {
132 VisitBlockForDominatorTree(entry_block_->GetSuccessors().Get(i), entry_block_, &visits);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000133 }
134}
135
136HBasicBlock* HGraph::FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const {
137 ArenaBitVector visited(arena_, blocks_.Size(), false);
138 // Walk the dominator tree of the first block and mark the visited blocks.
139 while (first != nullptr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000140 visited.SetBit(first->GetBlockId());
141 first = first->GetDominator();
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000142 }
143 // Walk the dominator tree of the second block until a marked block is found.
144 while (second != nullptr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000145 if (visited.IsBitSet(second->GetBlockId())) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000146 return second;
147 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000148 second = second->GetDominator();
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000149 }
150 LOG(ERROR) << "Could not find common dominator";
151 return nullptr;
152}
153
154void HGraph::VisitBlockForDominatorTree(HBasicBlock* block,
155 HBasicBlock* predecessor,
156 GrowableArray<size_t>* visits) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000157 if (block->GetDominator() == nullptr) {
158 block->SetDominator(predecessor);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000159 } else {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000160 block->SetDominator(FindCommonDominator(block->GetDominator(), predecessor));
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000161 }
162
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000163 visits->Increment(block->GetBlockId());
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000164 // Once all the forward edges have been visited, we know the immediate
165 // dominator of the block. We can then start visiting its successors.
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000166 if (visits->Get(block->GetBlockId()) ==
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100167 block->GetPredecessors().Size() - block->NumberOfBackEdges()) {
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100168 block->GetDominator()->AddDominatedBlock(block);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100169 reverse_post_order_.Add(block);
170 for (size_t i = 0; i < block->GetSuccessors().Size(); i++) {
171 VisitBlockForDominatorTree(block->GetSuccessors().Get(i), block, visits);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000172 }
173 }
174}
175
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000176void HGraph::TransformToSsa() {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100177 DCHECK(!reverse_post_order_.IsEmpty());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100178 SsaBuilder ssa_builder(this);
179 ssa_builder.BuildSsa();
180}
181
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100182void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
183 // Insert a new node between `block` and `successor` to split the
184 // critical edge.
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100185 HBasicBlock* new_block = new (arena_) HBasicBlock(this, successor->GetDexPc());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100186 AddBlock(new_block);
187 new_block->AddInstruction(new (arena_) HGoto());
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100188 block->ReplaceSuccessor(successor, new_block);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100189 new_block->AddSuccessor(successor);
190 if (successor->IsLoopHeader()) {
191 // If we split at a back edge boundary, make the new block the back edge.
192 HLoopInformation* info = successor->GetLoopInformation();
193 if (info->IsBackEdge(block)) {
194 info->RemoveBackEdge(block);
195 info->AddBackEdge(new_block);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100196 }
197 }
198}
199
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100200void HGraph::SimplifyLoop(HBasicBlock* header) {
201 HLoopInformation* info = header->GetLoopInformation();
202
203 // If there are more than one back edge, make them branch to the same block that
204 // will become the only back edge. This simplifies finding natural loops in the
205 // graph.
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100206 // Also, if the loop is a do/while (that is the back edge is an if), change the
207 // back edge to be a goto. This simplifies code generation of suspend cheks.
208 if (info->NumberOfBackEdges() > 1 || info->GetBackEdges().Get(0)->GetLastInstruction()->IsIf()) {
209 HBasicBlock* new_back_edge = new (arena_) HBasicBlock(this, header->GetDexPc());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100210 AddBlock(new_back_edge);
211 new_back_edge->AddInstruction(new (arena_) HGoto());
212 for (size_t pred = 0, e = info->GetBackEdges().Size(); pred < e; ++pred) {
213 HBasicBlock* back_edge = info->GetBackEdges().Get(pred);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100214 back_edge->ReplaceSuccessor(header, new_back_edge);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100215 }
216 info->ClearBackEdges();
217 info->AddBackEdge(new_back_edge);
218 new_back_edge->AddSuccessor(header);
219 }
220
221 // Make sure the loop has only one pre header. This simplifies SSA building by having
222 // to just look at the pre header to know which locals are initialized at entry of the
223 // loop.
224 size_t number_of_incomings = header->GetPredecessors().Size() - info->NumberOfBackEdges();
225 if (number_of_incomings != 1) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100226 HBasicBlock* pre_header = new (arena_) HBasicBlock(this, header->GetDexPc());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100227 AddBlock(pre_header);
228 pre_header->AddInstruction(new (arena_) HGoto());
229
230 ArenaBitVector back_edges(arena_, GetBlocks().Size(), false);
231 HBasicBlock* back_edge = info->GetBackEdges().Get(0);
232 for (size_t pred = 0; pred < header->GetPredecessors().Size(); ++pred) {
233 HBasicBlock* predecessor = header->GetPredecessors().Get(pred);
234 if (predecessor != back_edge) {
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100235 predecessor->ReplaceSuccessor(header, pre_header);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100236 pred--;
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100237 }
238 }
239 pre_header->AddSuccessor(header);
240 }
Nicolas Geoffray604c6e42014-09-17 12:08:44 +0100241
242 // Make sure the second predecessor of a loop header is the back edge.
243 if (header->GetPredecessors().Get(1) != info->GetBackEdges().Get(0)) {
244 header->SwapPredecessors();
245 }
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100246
247 // Place the suspend check at the beginning of the header, so that live registers
248 // will be known when allocating registers. Note that code generation can still
249 // generate the suspend check at the back edge, but needs to be careful with
250 // loop phi spill slots (which are not written to at back edge).
251 HInstruction* first_instruction = header->GetFirstInstruction();
252 if (!first_instruction->IsSuspendCheck()) {
253 HSuspendCheck* check = new (arena_) HSuspendCheck(header->GetDexPc());
254 header->InsertInstructionBefore(check, first_instruction);
255 first_instruction = check;
256 }
257 info->SetSuspendCheck(first_instruction->AsSuspendCheck());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100258}
259
260void HGraph::SimplifyCFG() {
261 // Simplify the CFG for future analysis, and code generation:
262 // (1): Split critical edges.
263 // (2): Simplify loops by having only one back edge, and one preheader.
264 for (size_t i = 0; i < blocks_.Size(); ++i) {
265 HBasicBlock* block = blocks_.Get(i);
266 if (block->GetSuccessors().Size() > 1) {
267 for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
268 HBasicBlock* successor = block->GetSuccessors().Get(j);
269 if (successor->GetPredecessors().Size() > 1) {
270 SplitCriticalEdge(block, successor);
271 --j;
272 }
273 }
274 }
275 if (block->IsLoopHeader()) {
276 SimplifyLoop(block);
277 }
278 }
279}
280
Nicolas Geoffrayf5370122014-12-02 11:51:19 +0000281bool HGraph::AnalyzeNaturalLoops() const {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100282 for (size_t i = 0; i < blocks_.Size(); ++i) {
283 HBasicBlock* block = blocks_.Get(i);
284 if (block->IsLoopHeader()) {
285 HLoopInformation* info = block->GetLoopInformation();
286 if (!info->Populate()) {
287 // Abort if the loop is non natural. We currently bailout in such cases.
288 return false;
289 }
290 }
291 }
292 return true;
293}
294
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000295HNullConstant* HGraph::GetNullConstant() {
296 if (cached_null_constant_ == nullptr) {
297 cached_null_constant_ = new (arena_) HNullConstant();
298 entry_block_->InsertInstructionBefore(cached_null_constant_,
299 entry_block_->GetLastInstruction());
300 }
301 return cached_null_constant_;
302}
303
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000304void HLoopInformation::Add(HBasicBlock* block) {
305 blocks_.SetBit(block->GetBlockId());
306}
307
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100308void HLoopInformation::PopulateRecursive(HBasicBlock* block) {
309 if (blocks_.IsBitSet(block->GetBlockId())) {
310 return;
311 }
312
313 blocks_.SetBit(block->GetBlockId());
314 block->SetInLoop(this);
315 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
316 PopulateRecursive(block->GetPredecessors().Get(i));
317 }
318}
319
320bool HLoopInformation::Populate() {
321 DCHECK_EQ(GetBackEdges().Size(), 1u);
322 HBasicBlock* back_edge = GetBackEdges().Get(0);
323 DCHECK(back_edge->GetDominator() != nullptr);
324 if (!header_->Dominates(back_edge)) {
325 // This loop is not natural. Do not bother going further.
326 return false;
327 }
328
329 // Populate this loop: starting with the back edge, recursively add predecessors
330 // that are not already part of that loop. Set the header as part of the loop
331 // to end the recursion.
332 // This is a recursive implementation of the algorithm described in
333 // "Advanced Compiler Design & Implementation" (Muchnick) p192.
334 blocks_.SetBit(header_->GetBlockId());
335 PopulateRecursive(back_edge);
336 return true;
337}
338
339HBasicBlock* HLoopInformation::GetPreHeader() const {
340 DCHECK_EQ(header_->GetPredecessors().Size(), 2u);
341 return header_->GetDominator();
342}
343
344bool HLoopInformation::Contains(const HBasicBlock& block) const {
345 return blocks_.IsBitSet(block.GetBlockId());
346}
347
348bool HLoopInformation::IsIn(const HLoopInformation& other) const {
349 return other.blocks_.IsBitSet(header_->GetBlockId());
350}
351
352bool HBasicBlock::Dominates(HBasicBlock* other) const {
353 // Walk up the dominator tree from `other`, to find out if `this`
354 // is an ancestor.
355 HBasicBlock* current = other;
356 while (current != nullptr) {
357 if (current == this) {
358 return true;
359 }
360 current = current->GetDominator();
361 }
362 return false;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100363}
364
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100365static void UpdateInputsUsers(HInstruction* instruction) {
366 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
367 instruction->InputAt(i)->AddUseAt(instruction, i);
368 }
369 // Environment should be created later.
370 DCHECK(!instruction->HasEnvironment());
371}
372
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100373void HBasicBlock::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
Roland Levillain476df552014-10-09 17:51:36 +0100374 DCHECK(!cursor->IsPhi());
375 DCHECK(!instruction->IsPhi());
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100376 DCHECK_EQ(instruction->GetId(), -1);
377 DCHECK_NE(cursor->GetId(), -1);
378 DCHECK_EQ(cursor->GetBlock(), this);
379 DCHECK(!instruction->IsControlFlow());
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100380 instruction->next_ = cursor;
381 instruction->previous_ = cursor->previous_;
382 cursor->previous_ = instruction;
383 if (GetFirstInstruction() == cursor) {
384 instructions_.first_instruction_ = instruction;
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100385 } else {
386 instruction->previous_->next_ = instruction;
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100387 }
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100388 instruction->SetBlock(this);
389 instruction->SetId(GetGraph()->GetNextInstructionId());
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100390 UpdateInputsUsers(instruction);
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100391}
392
Roland Levillainccc07a92014-09-16 14:48:16 +0100393void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
394 HInstruction* replacement) {
395 DCHECK(initial->GetBlock() == this);
396 InsertInstructionBefore(replacement, initial);
397 initial->ReplaceWith(replacement);
398 RemoveInstruction(initial);
399}
400
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100401static void Add(HInstructionList* instruction_list,
402 HBasicBlock* block,
403 HInstruction* instruction) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000404 DCHECK(instruction->GetBlock() == nullptr);
Nicolas Geoffray43c86422014-03-18 11:58:24 +0000405 DCHECK_EQ(instruction->GetId(), -1);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100406 instruction->SetBlock(block);
407 instruction->SetId(block->GetGraph()->GetNextInstructionId());
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100408 UpdateInputsUsers(instruction);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100409 instruction_list->AddInstruction(instruction);
410}
411
412void HBasicBlock::AddInstruction(HInstruction* instruction) {
413 Add(&instructions_, this, instruction);
414}
415
416void HBasicBlock::AddPhi(HPhi* phi) {
417 Add(&phis_, this, phi);
418}
419
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100420void HBasicBlock::InsertPhiAfter(HPhi* phi, HPhi* cursor) {
421 DCHECK_EQ(phi->GetId(), -1);
422 DCHECK_NE(cursor->GetId(), -1);
423 DCHECK_EQ(cursor->GetBlock(), this);
424 if (cursor->next_ == nullptr) {
425 cursor->next_ = phi;
426 phi->previous_ = cursor;
427 DCHECK(phi->next_ == nullptr);
428 } else {
429 phi->next_ = cursor->next_;
430 phi->previous_ = cursor;
431 cursor->next_ = phi;
432 phi->next_->previous_ = phi;
433 }
434 phi->SetBlock(this);
435 phi->SetId(GetGraph()->GetNextInstructionId());
436 UpdateInputsUsers(phi);
437}
438
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100439static void Remove(HInstructionList* instruction_list,
440 HBasicBlock* block,
441 HInstruction* instruction) {
442 DCHECK_EQ(block, instruction->GetBlock());
David Brazdiled596192015-01-23 10:39:45 +0000443 DCHECK(instruction->GetUses().IsEmpty());
444 DCHECK(instruction->GetEnvUses().IsEmpty());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100445 instruction->SetBlock(nullptr);
446 instruction_list->RemoveInstruction(instruction);
447
Roland Levillainfc600dc2014-12-02 17:16:31 +0000448 RemoveAsUser(instruction);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100449}
450
451void HBasicBlock::RemoveInstruction(HInstruction* instruction) {
452 Remove(&instructions_, this, instruction);
453}
454
455void HBasicBlock::RemovePhi(HPhi* phi) {
456 Remove(&phis_, this, phi);
457}
458
David Brazdiled596192015-01-23 10:39:45 +0000459void HEnvironment::CopyFrom(HEnvironment* env) {
460 for (size_t i = 0; i < env->Size(); i++) {
461 HInstruction* instruction = env->GetInstructionAt(i);
462 SetRawEnvAt(i, instruction);
463 if (instruction != nullptr) {
464 instruction->AddEnvUseAt(this, i);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100465 }
David Brazdiled596192015-01-23 10:39:45 +0000466 }
467}
468
469template <typename T>
470static void RemoveFromUseList(T user, size_t input_index, HUseList<T>* list) {
471 HUseListNode<T>* current;
472 for (HUseIterator<HInstruction*> use_it(*list); !use_it.Done(); use_it.Advance()) {
473 current = use_it.Current();
474 if (current->GetUser() == user && current->GetIndex() == input_index) {
475 list->Remove(current);
476 }
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100477 }
478}
479
Calin Juravle77520bc2015-01-12 18:45:46 +0000480HInstruction* HInstruction::GetNextDisregardingMoves() const {
481 HInstruction* next = GetNext();
482 while (next != nullptr && next->IsParallelMove()) {
483 next = next->GetNext();
484 }
485 return next;
486}
487
488HInstruction* HInstruction::GetPreviousDisregardingMoves() const {
489 HInstruction* previous = GetPrevious();
490 while (previous != nullptr && previous->IsParallelMove()) {
491 previous = previous->GetPrevious();
492 }
493 return previous;
494}
495
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100496void HInstruction::RemoveUser(HInstruction* user, size_t input_index) {
497 RemoveFromUseList(user, input_index, &uses_);
498}
499
David Brazdiled596192015-01-23 10:39:45 +0000500void HInstruction::RemoveEnvironmentUser(HUseListNode<HEnvironment*>* use) {
501 env_uses_.Remove(use);
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100502}
503
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100504void HInstructionList::AddInstruction(HInstruction* instruction) {
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000505 if (first_instruction_ == nullptr) {
506 DCHECK(last_instruction_ == nullptr);
507 first_instruction_ = last_instruction_ = instruction;
508 } else {
509 last_instruction_->next_ = instruction;
510 instruction->previous_ = last_instruction_;
511 last_instruction_ = instruction;
512 }
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000513}
514
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100515void HInstructionList::RemoveInstruction(HInstruction* instruction) {
516 if (instruction->previous_ != nullptr) {
517 instruction->previous_->next_ = instruction->next_;
518 }
519 if (instruction->next_ != nullptr) {
520 instruction->next_->previous_ = instruction->previous_;
521 }
522 if (instruction == first_instruction_) {
523 first_instruction_ = instruction->next_;
524 }
525 if (instruction == last_instruction_) {
526 last_instruction_ = instruction->previous_;
527 }
528}
529
Roland Levillain6b469232014-09-25 10:10:38 +0100530bool HInstructionList::Contains(HInstruction* instruction) const {
531 for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
532 if (it.Current() == instruction) {
533 return true;
534 }
535 }
536 return false;
537}
538
Roland Levillainccc07a92014-09-16 14:48:16 +0100539bool HInstructionList::FoundBefore(const HInstruction* instruction1,
540 const HInstruction* instruction2) const {
541 DCHECK_EQ(instruction1->GetBlock(), instruction2->GetBlock());
542 for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
543 if (it.Current() == instruction1) {
544 return true;
545 }
546 if (it.Current() == instruction2) {
547 return false;
548 }
549 }
550 LOG(FATAL) << "Did not find an order between two instructions of the same block.";
551 return true;
552}
553
Roland Levillain6c82d402014-10-13 16:10:27 +0100554bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
555 if (other_instruction == this) {
556 // An instruction does not strictly dominate itself.
557 return false;
558 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100559 HBasicBlock* block = GetBlock();
560 HBasicBlock* other_block = other_instruction->GetBlock();
561 if (block != other_block) {
562 return GetBlock()->Dominates(other_instruction->GetBlock());
563 } else {
564 // If both instructions are in the same block, ensure this
565 // instruction comes before `other_instruction`.
566 if (IsPhi()) {
567 if (!other_instruction->IsPhi()) {
568 // Phis appear before non phi-instructions so this instruction
569 // dominates `other_instruction`.
570 return true;
571 } else {
572 // There is no order among phis.
573 LOG(FATAL) << "There is no dominance between phis of a same block.";
574 return false;
575 }
576 } else {
577 // `this` is not a phi.
578 if (other_instruction->IsPhi()) {
579 // Phis appear before non phi-instructions so this instruction
580 // does not dominate `other_instruction`.
581 return false;
582 } else {
583 // Check whether this instruction comes before
584 // `other_instruction` in the instruction list.
585 return block->GetInstructions().FoundBefore(this, other_instruction);
586 }
587 }
588 }
589}
590
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100591void HInstruction::ReplaceWith(HInstruction* other) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100592 DCHECK(other != nullptr);
David Brazdiled596192015-01-23 10:39:45 +0000593 for (HUseIterator<HInstruction*> it(GetUses()); !it.Done(); it.Advance()) {
594 HUseListNode<HInstruction*>* current = it.Current();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100595 HInstruction* user = current->GetUser();
596 size_t input_index = current->GetIndex();
597 user->SetRawInputAt(input_index, other);
598 other->AddUseAt(user, input_index);
599 }
600
David Brazdiled596192015-01-23 10:39:45 +0000601 for (HUseIterator<HEnvironment*> it(GetEnvUses()); !it.Done(); it.Advance()) {
602 HUseListNode<HEnvironment*>* current = it.Current();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100603 HEnvironment* user = current->GetUser();
604 size_t input_index = current->GetIndex();
605 user->SetRawEnvAt(input_index, other);
606 other->AddEnvUseAt(user, input_index);
607 }
608
David Brazdiled596192015-01-23 10:39:45 +0000609 uses_.Clear();
610 env_uses_.Clear();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100611}
612
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100613void HInstruction::ReplaceInput(HInstruction* replacement, size_t index) {
614 InputAt(index)->RemoveUser(this, index);
615 SetRawInputAt(index, replacement);
616 replacement->AddUseAt(this, index);
617}
618
Nicolas Geoffray39468442014-09-02 15:17:15 +0100619size_t HInstruction::EnvironmentSize() const {
620 return HasEnvironment() ? environment_->Size() : 0;
621}
622
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100623void HPhi::AddInput(HInstruction* input) {
624 DCHECK(input->GetBlock() != nullptr);
625 inputs_.Add(input);
626 input->AddUseAt(this, inputs_.Size() - 1);
627}
628
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100629#define DEFINE_ACCEPT(name, super) \
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000630void H##name::Accept(HGraphVisitor* visitor) { \
631 visitor->Visit##name(this); \
632}
633
634FOR_EACH_INSTRUCTION(DEFINE_ACCEPT)
635
636#undef DEFINE_ACCEPT
637
638void HGraphVisitor::VisitInsertionOrder() {
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100639 const GrowableArray<HBasicBlock*>& blocks = graph_->GetBlocks();
640 for (size_t i = 0 ; i < blocks.Size(); i++) {
641 VisitBasicBlock(blocks.Get(i));
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000642 }
643}
644
Roland Levillain633021e2014-10-01 14:12:25 +0100645void HGraphVisitor::VisitReversePostOrder() {
646 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
647 VisitBasicBlock(it.Current());
648 }
649}
650
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000651void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100652 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100653 it.Current()->Accept(this);
654 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100655 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000656 it.Current()->Accept(this);
657 }
658}
659
Roland Levillain9240d6a2014-10-20 16:47:04 +0100660HConstant* HUnaryOperation::TryStaticEvaluation() const {
661 if (GetInput()->IsIntConstant()) {
662 int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
663 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
664 } else if (GetInput()->IsLongConstant()) {
Roland Levillainb762d2e2014-10-22 10:11:06 +0100665 // TODO: Implement static evaluation of long unary operations.
666 //
667 // Do not exit with a fatal condition here. Instead, simply
668 // return `nullptr' to notify the caller that this instruction
669 // cannot (yet) be statically evaluated.
Roland Levillain9240d6a2014-10-20 16:47:04 +0100670 return nullptr;
671 }
672 return nullptr;
673}
674
675HConstant* HBinaryOperation::TryStaticEvaluation() const {
Roland Levillain556c3d12014-09-18 15:25:07 +0100676 if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
677 int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
678 GetRight()->AsIntConstant()->GetValue());
Roland Levillain9240d6a2014-10-20 16:47:04 +0100679 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
Roland Levillain556c3d12014-09-18 15:25:07 +0100680 } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
681 int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
682 GetRight()->AsLongConstant()->GetValue());
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000683 if (GetResultType() == Primitive::kPrimLong) {
684 return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value);
685 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000686 DCHECK_EQ(GetResultType(), Primitive::kPrimInt);
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000687 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
688 }
Roland Levillain556c3d12014-09-18 15:25:07 +0100689 }
690 return nullptr;
691}
Dave Allison20dfc792014-06-16 20:44:29 -0700692
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100693bool HCondition::IsBeforeWhenDisregardMoves(HIf* if_) const {
Calin Juravle77520bc2015-01-12 18:45:46 +0000694 return this == if_->GetPreviousDisregardingMoves();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100695}
696
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100697bool HInstruction::Equals(HInstruction* other) const {
698 if (!InstructionTypeEquals(other)) return false;
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100699 DCHECK_EQ(GetKind(), other->GetKind());
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100700 if (!InstructionDataEquals(other)) return false;
701 if (GetType() != other->GetType()) return false;
702 if (InputCount() != other->InputCount()) return false;
703
704 for (size_t i = 0, e = InputCount(); i < e; ++i) {
705 if (InputAt(i) != other->InputAt(i)) return false;
706 }
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100707 DCHECK_EQ(ComputeHashCode(), other->ComputeHashCode());
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100708 return true;
709}
710
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700711std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs) {
712#define DECLARE_CASE(type, super) case HInstruction::k##type: os << #type; break;
713 switch (rhs) {
714 FOR_EACH_INSTRUCTION(DECLARE_CASE)
715 default:
716 os << "Unknown instruction kind " << static_cast<int>(rhs);
717 break;
718 }
719#undef DECLARE_CASE
720 return os;
721}
722
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000723void HInstruction::MoveBefore(HInstruction* cursor) {
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000724 next_->previous_ = previous_;
725 if (previous_ != nullptr) {
726 previous_->next_ = next_;
727 }
728 if (block_->instructions_.first_instruction_ == this) {
729 block_->instructions_.first_instruction_ = next_;
730 }
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000731 DCHECK_NE(block_->instructions_.last_instruction_, this);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000732
733 previous_ = cursor->previous_;
734 if (previous_ != nullptr) {
735 previous_->next_ = this;
736 }
737 next_ = cursor;
738 cursor->previous_ = this;
739 block_ = cursor->block_;
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000740
741 if (block_->instructions_.first_instruction_ == cursor) {
742 block_->instructions_.first_instruction_ = this;
743 }
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000744}
745
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000746HBasicBlock* HBasicBlock::SplitAfter(HInstruction* cursor) {
747 DCHECK(!cursor->IsControlFlow());
748 DCHECK_NE(instructions_.last_instruction_, cursor);
749 DCHECK_EQ(cursor->GetBlock(), this);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000750
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000751 HBasicBlock* new_block = new (GetGraph()->GetArena()) HBasicBlock(GetGraph(), GetDexPc());
752 new_block->instructions_.first_instruction_ = cursor->GetNext();
753 new_block->instructions_.last_instruction_ = instructions_.last_instruction_;
754 cursor->next_->previous_ = nullptr;
755 cursor->next_ = nullptr;
756 instructions_.last_instruction_ = cursor;
757
758 new_block->instructions_.SetBlockOfInstructions(new_block);
759 for (size_t i = 0, e = GetSuccessors().Size(); i < e; ++i) {
760 HBasicBlock* successor = GetSuccessors().Get(i);
761 new_block->successors_.Add(successor);
762 successor->predecessors_.Put(successor->GetPredecessorIndexOf(this), new_block);
763 }
764 successors_.Reset();
765
766 for (size_t i = 0, e = GetDominatedBlocks().Size(); i < e; ++i) {
767 HBasicBlock* dominated = GetDominatedBlocks().Get(i);
768 dominated->dominator_ = new_block;
769 new_block->dominated_blocks_.Add(dominated);
770 }
771 dominated_blocks_.Reset();
772 return new_block;
773}
774
775void HInstructionList::SetBlockOfInstructions(HBasicBlock* block) const {
776 for (HInstruction* current = first_instruction_;
777 current != nullptr;
778 current = current->GetNext()) {
779 current->SetBlock(block);
780 }
781}
782
783void HInstructionList::AddAfter(HInstruction* cursor, const HInstructionList& instruction_list) {
784 DCHECK(Contains(cursor));
785 if (!instruction_list.IsEmpty()) {
786 if (cursor == last_instruction_) {
787 last_instruction_ = instruction_list.last_instruction_;
788 } else {
789 cursor->next_->previous_ = instruction_list.last_instruction_;
790 }
791 instruction_list.last_instruction_->next_ = cursor->next_;
792 cursor->next_ = instruction_list.first_instruction_;
793 instruction_list.first_instruction_->previous_ = cursor;
794 }
795}
796
797void HInstructionList::Add(const HInstructionList& instruction_list) {
798 DCHECK(!IsEmpty());
799 AddAfter(last_instruction_, instruction_list);
800}
801
802void HBasicBlock::MergeWith(HBasicBlock* other) {
803 DCHECK(successors_.IsEmpty()) << "Unimplemented block merge scenario";
804 DCHECK(dominated_blocks_.IsEmpty()) << "Unimplemented block merge scenario";
805 DCHECK(other->GetDominator()->IsEntryBlock() && other->GetGraph() != graph_)
806 << "Unimplemented block merge scenario";
807 DCHECK(other->GetPhis().IsEmpty());
808
809 successors_.Reset();
810 dominated_blocks_.Reset();
811 instructions_.Add(other->GetInstructions());
812 other->GetInstructions().SetBlockOfInstructions(this);
813
814 while (!other->GetSuccessors().IsEmpty()) {
815 HBasicBlock* successor = other->GetSuccessors().Get(0);
816 successor->ReplacePredecessor(other, this);
817 }
818
819 for (size_t i = 0, e = other->GetDominatedBlocks().Size(); i < e; ++i) {
820 HBasicBlock* dominated = other->GetDominatedBlocks().Get(i);
821 dominated_blocks_.Add(dominated);
822 dominated->SetDominator(this);
823 }
824 other->dominated_blocks_.Reset();
825 other->dominator_ = nullptr;
826 other->graph_ = nullptr;
827}
828
829void HBasicBlock::ReplaceWith(HBasicBlock* other) {
830 while (!GetPredecessors().IsEmpty()) {
831 HBasicBlock* predecessor = GetPredecessors().Get(0);
832 predecessor->ReplaceSuccessor(this, other);
833 }
834 while (!GetSuccessors().IsEmpty()) {
835 HBasicBlock* successor = GetSuccessors().Get(0);
836 successor->ReplacePredecessor(this, other);
837 }
838 for (size_t i = 0; i < dominated_blocks_.Size(); ++i) {
839 other->AddDominatedBlock(dominated_blocks_.Get(i));
840 }
841 GetDominator()->ReplaceDominatedBlock(this, other);
842 other->SetDominator(GetDominator());
843 dominator_ = nullptr;
844 graph_ = nullptr;
845}
846
847// Create space in `blocks` for adding `number_of_new_blocks` entries
848// starting at location `at`. Blocks after `at` are moved accordingly.
849static void MakeRoomFor(GrowableArray<HBasicBlock*>* blocks,
850 size_t number_of_new_blocks,
851 size_t at) {
852 size_t old_size = blocks->Size();
853 size_t new_size = old_size + number_of_new_blocks;
854 blocks->SetSize(new_size);
855 for (size_t i = old_size - 1, j = new_size - 1; i > at; --i, --j) {
856 blocks->Put(j, blocks->Get(i));
857 }
858}
859
860void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000861 // Walk over the entry block and:
862 // - Move constants from the entry block to the outer_graph's entry block,
863 // - Replace HParameterValue instructions with their real value.
864 // - Remove suspend checks, that hold an environment.
865 int parameter_index = 0;
866 for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
867 HInstruction* current = it.Current();
868 if (current->IsConstant()) {
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000869 current->MoveBefore(outer_graph->GetEntryBlock()->GetLastInstruction());
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000870 } else if (current->IsParameterValue()) {
871 current->ReplaceWith(invoke->InputAt(parameter_index++));
872 } else {
873 DCHECK(current->IsGoto() || current->IsSuspendCheck());
874 entry_block_->RemoveInstruction(current);
875 }
876 }
877
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000878 if (GetBlocks().Size() == 3) {
Nicolas Geoffraybe31ff92015-02-04 14:52:20 +0000879 // Simple case of an entry block, a body block, and an exit block.
880 // Put the body block's instruction into `invoke`'s block.
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000881 HBasicBlock* body = GetBlocks().Get(1);
Nicolas Geoffraybe31ff92015-02-04 14:52:20 +0000882 DCHECK(GetBlocks().Get(0)->IsEntryBlock());
883 DCHECK(GetBlocks().Get(2)->IsExitBlock());
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000884 DCHECK(!body->IsExitBlock());
885 HInstruction* last = body->GetLastInstruction();
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000886
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000887 invoke->GetBlock()->instructions_.AddAfter(invoke, body->GetInstructions());
888 body->GetInstructions().SetBlockOfInstructions(invoke->GetBlock());
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000889
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000890 // Replace the invoke with the return value of the inlined graph.
891 if (last->IsReturn()) {
892 invoke->ReplaceWith(last->InputAt(0));
893 } else {
894 DCHECK(last->IsReturnVoid());
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000895 }
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000896
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000897 invoke->GetBlock()->RemoveInstruction(last);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000898 } else {
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000899 // Need to inline multiple blocks. We split `invoke`'s block
900 // into two blocks, merge the first block of the inlined graph into
Nicolas Geoffraybe31ff92015-02-04 14:52:20 +0000901 // the first half, and replace the exit block of the inlined graph
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000902 // with the second half.
903 ArenaAllocator* allocator = outer_graph->GetArena();
904 HBasicBlock* at = invoke->GetBlock();
905 HBasicBlock* to = at->SplitAfter(invoke);
906
907 HBasicBlock* first = entry_block_->GetSuccessors().Get(0);
908 DCHECK(!first->IsInLoop());
909 at->MergeWith(first);
910 exit_block_->ReplaceWith(to);
911
912 // Update all predecessors of the exit block (now the `to` block)
913 // to not `HReturn` but `HGoto` instead. Also collect the return
914 // values if any, and potentially make it a phi if there are multiple
915 // predecessors.
916 HInstruction* return_value = nullptr;
917 for (size_t i = 0, e = to->GetPredecessors().Size(); i < e; ++i) {
918 HBasicBlock* predecessor = to->GetPredecessors().Get(i);
919 HInstruction* last = predecessor->GetLastInstruction();
920 if (!last->IsReturnVoid()) {
921 if (return_value != nullptr) {
922 if (!return_value->IsPhi()) {
Nicolas Geoffraybe31ff92015-02-04 14:52:20 +0000923 HPhi* phi = new (allocator) HPhi(allocator, kNoRegNumber, 0, invoke->GetType());
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000924 to->AddPhi(phi);
Nicolas Geoffraybe31ff92015-02-04 14:52:20 +0000925 phi->AddInput(return_value);
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000926 return_value = phi;
927 }
928 return_value->AsPhi()->AddInput(last->InputAt(0));
929 } else {
930 return_value = last->InputAt(0);
931 }
932 }
933 predecessor->AddInstruction(new (allocator) HGoto());
934 predecessor->RemoveInstruction(last);
935 }
936
937 if (return_value != nullptr) {
938 invoke->ReplaceWith(return_value);
939 }
940
941 // Update the meta information surrounding blocks:
942 // (1) the graph they are now in,
943 // (2) the reverse post order of that graph,
944 // (3) the potential loop information they are now in.
945
946 // We don't add the entry block, the exit block, and the first block, which
947 // has been merged with `at`.
948 static constexpr int kNumberOfSkippedBlocksInCallee = 3;
949
950 // We add the `to` block.
951 static constexpr int kNumberOfNewBlocksInCaller = 1;
952 size_t blocks_added = (reverse_post_order_.Size() - kNumberOfSkippedBlocksInCallee)
953 + kNumberOfNewBlocksInCaller;
954
955 // Find the location of `at` in the outer graph's reverse post order. The new
956 // blocks will be added after it.
957 size_t index_of_at = 0;
958 while (outer_graph->reverse_post_order_.Get(index_of_at) != at) {
959 index_of_at++;
960 }
961 MakeRoomFor(&outer_graph->reverse_post_order_, blocks_added, index_of_at);
962
963 // Do a reverse post order of the blocks in the callee and do (1), (2),
964 // and (3) to the blocks that apply.
965 HLoopInformation* info = at->GetLoopInformation();
966 for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) {
967 HBasicBlock* current = it.Current();
968 if (current != exit_block_ && current != entry_block_ && current != first) {
969 DCHECK(!current->IsInLoop());
970 DCHECK(current->GetGraph() == this);
971 current->SetGraph(outer_graph);
972 outer_graph->AddBlock(current);
973 outer_graph->reverse_post_order_.Put(++index_of_at, current);
974 if (info != nullptr) {
975 info->Add(current);
976 current->SetLoopInformation(info);
977 }
978 }
979 }
980
981 // Do (1), (2), and (3) to `to`.
982 to->SetGraph(outer_graph);
983 outer_graph->AddBlock(to);
984 outer_graph->reverse_post_order_.Put(++index_of_at, to);
985 if (info != nullptr) {
986 info->Add(to);
987 to->SetLoopInformation(info);
988 if (info->IsBackEdge(at)) {
989 // Only `at` can become a back edge, as the inlined blocks
990 // are predecessors of `at`.
991 DCHECK_EQ(1u, info->NumberOfBackEdges());
992 info->ClearBackEdges();
993 info->AddBackEdge(to);
994 }
995 }
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000996 }
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000997
998 // Finally remove the invoke from the caller.
999 invoke->GetBlock()->RemoveInstruction(invoke);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001000}
1001
Nicolas Geoffray818f2102014-02-18 16:43:35 +00001002} // namespace art