blob: cd36598171d76beace62671d4764077247d72060 [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 Geoffray276d9da2015-02-02 18:24:11 +0000295void HLoopInformation::Add(HBasicBlock* block) {
296 blocks_.SetBit(block->GetBlockId());
297}
298
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100299void HLoopInformation::PopulateRecursive(HBasicBlock* block) {
300 if (blocks_.IsBitSet(block->GetBlockId())) {
301 return;
302 }
303
304 blocks_.SetBit(block->GetBlockId());
305 block->SetInLoop(this);
306 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
307 PopulateRecursive(block->GetPredecessors().Get(i));
308 }
309}
310
311bool HLoopInformation::Populate() {
312 DCHECK_EQ(GetBackEdges().Size(), 1u);
313 HBasicBlock* back_edge = GetBackEdges().Get(0);
314 DCHECK(back_edge->GetDominator() != nullptr);
315 if (!header_->Dominates(back_edge)) {
316 // This loop is not natural. Do not bother going further.
317 return false;
318 }
319
320 // Populate this loop: starting with the back edge, recursively add predecessors
321 // that are not already part of that loop. Set the header as part of the loop
322 // to end the recursion.
323 // This is a recursive implementation of the algorithm described in
324 // "Advanced Compiler Design & Implementation" (Muchnick) p192.
325 blocks_.SetBit(header_->GetBlockId());
326 PopulateRecursive(back_edge);
327 return true;
328}
329
330HBasicBlock* HLoopInformation::GetPreHeader() const {
331 DCHECK_EQ(header_->GetPredecessors().Size(), 2u);
332 return header_->GetDominator();
333}
334
335bool HLoopInformation::Contains(const HBasicBlock& block) const {
336 return blocks_.IsBitSet(block.GetBlockId());
337}
338
339bool HLoopInformation::IsIn(const HLoopInformation& other) const {
340 return other.blocks_.IsBitSet(header_->GetBlockId());
341}
342
343bool HBasicBlock::Dominates(HBasicBlock* other) const {
344 // Walk up the dominator tree from `other`, to find out if `this`
345 // is an ancestor.
346 HBasicBlock* current = other;
347 while (current != nullptr) {
348 if (current == this) {
349 return true;
350 }
351 current = current->GetDominator();
352 }
353 return false;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100354}
355
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100356static void UpdateInputsUsers(HInstruction* instruction) {
357 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
358 instruction->InputAt(i)->AddUseAt(instruction, i);
359 }
360 // Environment should be created later.
361 DCHECK(!instruction->HasEnvironment());
362}
363
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100364void HBasicBlock::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
Roland Levillain476df552014-10-09 17:51:36 +0100365 DCHECK(!cursor->IsPhi());
366 DCHECK(!instruction->IsPhi());
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100367 DCHECK_EQ(instruction->GetId(), -1);
368 DCHECK_NE(cursor->GetId(), -1);
369 DCHECK_EQ(cursor->GetBlock(), this);
370 DCHECK(!instruction->IsControlFlow());
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100371 instruction->next_ = cursor;
372 instruction->previous_ = cursor->previous_;
373 cursor->previous_ = instruction;
374 if (GetFirstInstruction() == cursor) {
375 instructions_.first_instruction_ = instruction;
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100376 } else {
377 instruction->previous_->next_ = instruction;
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100378 }
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100379 instruction->SetBlock(this);
380 instruction->SetId(GetGraph()->GetNextInstructionId());
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100381 UpdateInputsUsers(instruction);
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100382}
383
Roland Levillainccc07a92014-09-16 14:48:16 +0100384void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
385 HInstruction* replacement) {
386 DCHECK(initial->GetBlock() == this);
387 InsertInstructionBefore(replacement, initial);
388 initial->ReplaceWith(replacement);
389 RemoveInstruction(initial);
390}
391
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100392static void Add(HInstructionList* instruction_list,
393 HBasicBlock* block,
394 HInstruction* instruction) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000395 DCHECK(instruction->GetBlock() == nullptr);
Nicolas Geoffray43c86422014-03-18 11:58:24 +0000396 DCHECK_EQ(instruction->GetId(), -1);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100397 instruction->SetBlock(block);
398 instruction->SetId(block->GetGraph()->GetNextInstructionId());
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100399 UpdateInputsUsers(instruction);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100400 instruction_list->AddInstruction(instruction);
401}
402
403void HBasicBlock::AddInstruction(HInstruction* instruction) {
404 Add(&instructions_, this, instruction);
405}
406
407void HBasicBlock::AddPhi(HPhi* phi) {
408 Add(&phis_, this, phi);
409}
410
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100411void HBasicBlock::InsertPhiAfter(HPhi* phi, HPhi* cursor) {
412 DCHECK_EQ(phi->GetId(), -1);
413 DCHECK_NE(cursor->GetId(), -1);
414 DCHECK_EQ(cursor->GetBlock(), this);
415 if (cursor->next_ == nullptr) {
416 cursor->next_ = phi;
417 phi->previous_ = cursor;
418 DCHECK(phi->next_ == nullptr);
419 } else {
420 phi->next_ = cursor->next_;
421 phi->previous_ = cursor;
422 cursor->next_ = phi;
423 phi->next_->previous_ = phi;
424 }
425 phi->SetBlock(this);
426 phi->SetId(GetGraph()->GetNextInstructionId());
427 UpdateInputsUsers(phi);
428}
429
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100430static void Remove(HInstructionList* instruction_list,
431 HBasicBlock* block,
432 HInstruction* instruction) {
433 DCHECK_EQ(block, instruction->GetBlock());
David Brazdiled596192015-01-23 10:39:45 +0000434 DCHECK(instruction->GetUses().IsEmpty());
435 DCHECK(instruction->GetEnvUses().IsEmpty());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100436 instruction->SetBlock(nullptr);
437 instruction_list->RemoveInstruction(instruction);
438
Roland Levillainfc600dc2014-12-02 17:16:31 +0000439 RemoveAsUser(instruction);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100440}
441
442void HBasicBlock::RemoveInstruction(HInstruction* instruction) {
443 Remove(&instructions_, this, instruction);
444}
445
446void HBasicBlock::RemovePhi(HPhi* phi) {
447 Remove(&phis_, this, phi);
448}
449
David Brazdiled596192015-01-23 10:39:45 +0000450void HEnvironment::CopyFrom(HEnvironment* env) {
451 for (size_t i = 0; i < env->Size(); i++) {
452 HInstruction* instruction = env->GetInstructionAt(i);
453 SetRawEnvAt(i, instruction);
454 if (instruction != nullptr) {
455 instruction->AddEnvUseAt(this, i);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100456 }
David Brazdiled596192015-01-23 10:39:45 +0000457 }
458}
459
460template <typename T>
461static void RemoveFromUseList(T user, size_t input_index, HUseList<T>* list) {
462 HUseListNode<T>* current;
463 for (HUseIterator<HInstruction*> use_it(*list); !use_it.Done(); use_it.Advance()) {
464 current = use_it.Current();
465 if (current->GetUser() == user && current->GetIndex() == input_index) {
466 list->Remove(current);
467 }
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100468 }
469}
470
Calin Juravle77520bc2015-01-12 18:45:46 +0000471HInstruction* HInstruction::GetNextDisregardingMoves() const {
472 HInstruction* next = GetNext();
473 while (next != nullptr && next->IsParallelMove()) {
474 next = next->GetNext();
475 }
476 return next;
477}
478
479HInstruction* HInstruction::GetPreviousDisregardingMoves() const {
480 HInstruction* previous = GetPrevious();
481 while (previous != nullptr && previous->IsParallelMove()) {
482 previous = previous->GetPrevious();
483 }
484 return previous;
485}
486
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100487void HInstruction::RemoveUser(HInstruction* user, size_t input_index) {
488 RemoveFromUseList(user, input_index, &uses_);
489}
490
David Brazdiled596192015-01-23 10:39:45 +0000491void HInstruction::RemoveEnvironmentUser(HUseListNode<HEnvironment*>* use) {
492 env_uses_.Remove(use);
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100493}
494
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100495void HInstructionList::AddInstruction(HInstruction* instruction) {
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000496 if (first_instruction_ == nullptr) {
497 DCHECK(last_instruction_ == nullptr);
498 first_instruction_ = last_instruction_ = instruction;
499 } else {
500 last_instruction_->next_ = instruction;
501 instruction->previous_ = last_instruction_;
502 last_instruction_ = instruction;
503 }
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000504}
505
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100506void HInstructionList::RemoveInstruction(HInstruction* instruction) {
507 if (instruction->previous_ != nullptr) {
508 instruction->previous_->next_ = instruction->next_;
509 }
510 if (instruction->next_ != nullptr) {
511 instruction->next_->previous_ = instruction->previous_;
512 }
513 if (instruction == first_instruction_) {
514 first_instruction_ = instruction->next_;
515 }
516 if (instruction == last_instruction_) {
517 last_instruction_ = instruction->previous_;
518 }
519}
520
Roland Levillain6b469232014-09-25 10:10:38 +0100521bool HInstructionList::Contains(HInstruction* instruction) const {
522 for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
523 if (it.Current() == instruction) {
524 return true;
525 }
526 }
527 return false;
528}
529
Roland Levillainccc07a92014-09-16 14:48:16 +0100530bool HInstructionList::FoundBefore(const HInstruction* instruction1,
531 const HInstruction* instruction2) const {
532 DCHECK_EQ(instruction1->GetBlock(), instruction2->GetBlock());
533 for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
534 if (it.Current() == instruction1) {
535 return true;
536 }
537 if (it.Current() == instruction2) {
538 return false;
539 }
540 }
541 LOG(FATAL) << "Did not find an order between two instructions of the same block.";
542 return true;
543}
544
Roland Levillain6c82d402014-10-13 16:10:27 +0100545bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
546 if (other_instruction == this) {
547 // An instruction does not strictly dominate itself.
548 return false;
549 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100550 HBasicBlock* block = GetBlock();
551 HBasicBlock* other_block = other_instruction->GetBlock();
552 if (block != other_block) {
553 return GetBlock()->Dominates(other_instruction->GetBlock());
554 } else {
555 // If both instructions are in the same block, ensure this
556 // instruction comes before `other_instruction`.
557 if (IsPhi()) {
558 if (!other_instruction->IsPhi()) {
559 // Phis appear before non phi-instructions so this instruction
560 // dominates `other_instruction`.
561 return true;
562 } else {
563 // There is no order among phis.
564 LOG(FATAL) << "There is no dominance between phis of a same block.";
565 return false;
566 }
567 } else {
568 // `this` is not a phi.
569 if (other_instruction->IsPhi()) {
570 // Phis appear before non phi-instructions so this instruction
571 // does not dominate `other_instruction`.
572 return false;
573 } else {
574 // Check whether this instruction comes before
575 // `other_instruction` in the instruction list.
576 return block->GetInstructions().FoundBefore(this, other_instruction);
577 }
578 }
579 }
580}
581
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100582void HInstruction::ReplaceWith(HInstruction* other) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100583 DCHECK(other != nullptr);
David Brazdiled596192015-01-23 10:39:45 +0000584 for (HUseIterator<HInstruction*> it(GetUses()); !it.Done(); it.Advance()) {
585 HUseListNode<HInstruction*>* current = it.Current();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100586 HInstruction* user = current->GetUser();
587 size_t input_index = current->GetIndex();
588 user->SetRawInputAt(input_index, other);
589 other->AddUseAt(user, input_index);
590 }
591
David Brazdiled596192015-01-23 10:39:45 +0000592 for (HUseIterator<HEnvironment*> it(GetEnvUses()); !it.Done(); it.Advance()) {
593 HUseListNode<HEnvironment*>* current = it.Current();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100594 HEnvironment* user = current->GetUser();
595 size_t input_index = current->GetIndex();
596 user->SetRawEnvAt(input_index, other);
597 other->AddEnvUseAt(user, input_index);
598 }
599
David Brazdiled596192015-01-23 10:39:45 +0000600 uses_.Clear();
601 env_uses_.Clear();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100602}
603
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100604void HInstruction::ReplaceInput(HInstruction* replacement, size_t index) {
605 InputAt(index)->RemoveUser(this, index);
606 SetRawInputAt(index, replacement);
607 replacement->AddUseAt(this, index);
608}
609
Nicolas Geoffray39468442014-09-02 15:17:15 +0100610size_t HInstruction::EnvironmentSize() const {
611 return HasEnvironment() ? environment_->Size() : 0;
612}
613
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100614void HPhi::AddInput(HInstruction* input) {
615 DCHECK(input->GetBlock() != nullptr);
616 inputs_.Add(input);
617 input->AddUseAt(this, inputs_.Size() - 1);
618}
619
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100620#define DEFINE_ACCEPT(name, super) \
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000621void H##name::Accept(HGraphVisitor* visitor) { \
622 visitor->Visit##name(this); \
623}
624
625FOR_EACH_INSTRUCTION(DEFINE_ACCEPT)
626
627#undef DEFINE_ACCEPT
628
629void HGraphVisitor::VisitInsertionOrder() {
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100630 const GrowableArray<HBasicBlock*>& blocks = graph_->GetBlocks();
631 for (size_t i = 0 ; i < blocks.Size(); i++) {
632 VisitBasicBlock(blocks.Get(i));
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000633 }
634}
635
Roland Levillain633021e2014-10-01 14:12:25 +0100636void HGraphVisitor::VisitReversePostOrder() {
637 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
638 VisitBasicBlock(it.Current());
639 }
640}
641
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000642void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100643 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100644 it.Current()->Accept(this);
645 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100646 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000647 it.Current()->Accept(this);
648 }
649}
650
Roland Levillain9240d6a2014-10-20 16:47:04 +0100651HConstant* HUnaryOperation::TryStaticEvaluation() const {
652 if (GetInput()->IsIntConstant()) {
653 int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
654 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
655 } else if (GetInput()->IsLongConstant()) {
Roland Levillainb762d2e2014-10-22 10:11:06 +0100656 // TODO: Implement static evaluation of long unary operations.
657 //
658 // Do not exit with a fatal condition here. Instead, simply
659 // return `nullptr' to notify the caller that this instruction
660 // cannot (yet) be statically evaluated.
Roland Levillain9240d6a2014-10-20 16:47:04 +0100661 return nullptr;
662 }
663 return nullptr;
664}
665
666HConstant* HBinaryOperation::TryStaticEvaluation() const {
Roland Levillain556c3d12014-09-18 15:25:07 +0100667 if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
668 int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
669 GetRight()->AsIntConstant()->GetValue());
Roland Levillain9240d6a2014-10-20 16:47:04 +0100670 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
Roland Levillain556c3d12014-09-18 15:25:07 +0100671 } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
672 int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
673 GetRight()->AsLongConstant()->GetValue());
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000674 if (GetResultType() == Primitive::kPrimLong) {
675 return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value);
676 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000677 DCHECK_EQ(GetResultType(), Primitive::kPrimInt);
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000678 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
679 }
Roland Levillain556c3d12014-09-18 15:25:07 +0100680 }
681 return nullptr;
682}
Dave Allison20dfc792014-06-16 20:44:29 -0700683
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100684bool HCondition::IsBeforeWhenDisregardMoves(HIf* if_) const {
Calin Juravle77520bc2015-01-12 18:45:46 +0000685 return this == if_->GetPreviousDisregardingMoves();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100686}
687
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100688bool HInstruction::Equals(HInstruction* other) const {
689 if (!InstructionTypeEquals(other)) return false;
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100690 DCHECK_EQ(GetKind(), other->GetKind());
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100691 if (!InstructionDataEquals(other)) return false;
692 if (GetType() != other->GetType()) return false;
693 if (InputCount() != other->InputCount()) return false;
694
695 for (size_t i = 0, e = InputCount(); i < e; ++i) {
696 if (InputAt(i) != other->InputAt(i)) return false;
697 }
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100698 DCHECK_EQ(ComputeHashCode(), other->ComputeHashCode());
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100699 return true;
700}
701
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700702std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs) {
703#define DECLARE_CASE(type, super) case HInstruction::k##type: os << #type; break;
704 switch (rhs) {
705 FOR_EACH_INSTRUCTION(DECLARE_CASE)
706 default:
707 os << "Unknown instruction kind " << static_cast<int>(rhs);
708 break;
709 }
710#undef DECLARE_CASE
711 return os;
712}
713
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000714void HInstruction::MoveBefore(HInstruction* cursor) {
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000715 next_->previous_ = previous_;
716 if (previous_ != nullptr) {
717 previous_->next_ = next_;
718 }
719 if (block_->instructions_.first_instruction_ == this) {
720 block_->instructions_.first_instruction_ = next_;
721 }
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000722 DCHECK_NE(block_->instructions_.last_instruction_, this);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000723
724 previous_ = cursor->previous_;
725 if (previous_ != nullptr) {
726 previous_->next_ = this;
727 }
728 next_ = cursor;
729 cursor->previous_ = this;
730 block_ = cursor->block_;
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000731
732 if (block_->instructions_.first_instruction_ == cursor) {
733 block_->instructions_.first_instruction_ = this;
734 }
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000735}
736
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000737HBasicBlock* HBasicBlock::SplitAfter(HInstruction* cursor) {
738 DCHECK(!cursor->IsControlFlow());
739 DCHECK_NE(instructions_.last_instruction_, cursor);
740 DCHECK_EQ(cursor->GetBlock(), this);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000741
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000742 HBasicBlock* new_block = new (GetGraph()->GetArena()) HBasicBlock(GetGraph(), GetDexPc());
743 new_block->instructions_.first_instruction_ = cursor->GetNext();
744 new_block->instructions_.last_instruction_ = instructions_.last_instruction_;
745 cursor->next_->previous_ = nullptr;
746 cursor->next_ = nullptr;
747 instructions_.last_instruction_ = cursor;
748
749 new_block->instructions_.SetBlockOfInstructions(new_block);
750 for (size_t i = 0, e = GetSuccessors().Size(); i < e; ++i) {
751 HBasicBlock* successor = GetSuccessors().Get(i);
752 new_block->successors_.Add(successor);
753 successor->predecessors_.Put(successor->GetPredecessorIndexOf(this), new_block);
754 }
755 successors_.Reset();
756
757 for (size_t i = 0, e = GetDominatedBlocks().Size(); i < e; ++i) {
758 HBasicBlock* dominated = GetDominatedBlocks().Get(i);
759 dominated->dominator_ = new_block;
760 new_block->dominated_blocks_.Add(dominated);
761 }
762 dominated_blocks_.Reset();
763 return new_block;
764}
765
766void HInstructionList::SetBlockOfInstructions(HBasicBlock* block) const {
767 for (HInstruction* current = first_instruction_;
768 current != nullptr;
769 current = current->GetNext()) {
770 current->SetBlock(block);
771 }
772}
773
774void HInstructionList::AddAfter(HInstruction* cursor, const HInstructionList& instruction_list) {
775 DCHECK(Contains(cursor));
776 if (!instruction_list.IsEmpty()) {
777 if (cursor == last_instruction_) {
778 last_instruction_ = instruction_list.last_instruction_;
779 } else {
780 cursor->next_->previous_ = instruction_list.last_instruction_;
781 }
782 instruction_list.last_instruction_->next_ = cursor->next_;
783 cursor->next_ = instruction_list.first_instruction_;
784 instruction_list.first_instruction_->previous_ = cursor;
785 }
786}
787
788void HInstructionList::Add(const HInstructionList& instruction_list) {
789 DCHECK(!IsEmpty());
790 AddAfter(last_instruction_, instruction_list);
791}
792
793void HBasicBlock::MergeWith(HBasicBlock* other) {
794 DCHECK(successors_.IsEmpty()) << "Unimplemented block merge scenario";
795 DCHECK(dominated_blocks_.IsEmpty()) << "Unimplemented block merge scenario";
796 DCHECK(other->GetDominator()->IsEntryBlock() && other->GetGraph() != graph_)
797 << "Unimplemented block merge scenario";
798 DCHECK(other->GetPhis().IsEmpty());
799
800 successors_.Reset();
801 dominated_blocks_.Reset();
802 instructions_.Add(other->GetInstructions());
803 other->GetInstructions().SetBlockOfInstructions(this);
804
805 while (!other->GetSuccessors().IsEmpty()) {
806 HBasicBlock* successor = other->GetSuccessors().Get(0);
807 successor->ReplacePredecessor(other, this);
808 }
809
810 for (size_t i = 0, e = other->GetDominatedBlocks().Size(); i < e; ++i) {
811 HBasicBlock* dominated = other->GetDominatedBlocks().Get(i);
812 dominated_blocks_.Add(dominated);
813 dominated->SetDominator(this);
814 }
815 other->dominated_blocks_.Reset();
816 other->dominator_ = nullptr;
817 other->graph_ = nullptr;
818}
819
820void HBasicBlock::ReplaceWith(HBasicBlock* other) {
821 while (!GetPredecessors().IsEmpty()) {
822 HBasicBlock* predecessor = GetPredecessors().Get(0);
823 predecessor->ReplaceSuccessor(this, other);
824 }
825 while (!GetSuccessors().IsEmpty()) {
826 HBasicBlock* successor = GetSuccessors().Get(0);
827 successor->ReplacePredecessor(this, other);
828 }
829 for (size_t i = 0; i < dominated_blocks_.Size(); ++i) {
830 other->AddDominatedBlock(dominated_blocks_.Get(i));
831 }
832 GetDominator()->ReplaceDominatedBlock(this, other);
833 other->SetDominator(GetDominator());
834 dominator_ = nullptr;
835 graph_ = nullptr;
836}
837
838// Create space in `blocks` for adding `number_of_new_blocks` entries
839// starting at location `at`. Blocks after `at` are moved accordingly.
840static void MakeRoomFor(GrowableArray<HBasicBlock*>* blocks,
841 size_t number_of_new_blocks,
842 size_t at) {
843 size_t old_size = blocks->Size();
844 size_t new_size = old_size + number_of_new_blocks;
845 blocks->SetSize(new_size);
846 for (size_t i = old_size - 1, j = new_size - 1; i > at; --i, --j) {
847 blocks->Put(j, blocks->Get(i));
848 }
849}
850
851void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000852 // Walk over the entry block and:
853 // - Move constants from the entry block to the outer_graph's entry block,
854 // - Replace HParameterValue instructions with their real value.
855 // - Remove suspend checks, that hold an environment.
856 int parameter_index = 0;
857 for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
858 HInstruction* current = it.Current();
859 if (current->IsConstant()) {
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000860 current->MoveBefore(outer_graph->GetEntryBlock()->GetLastInstruction());
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000861 } else if (current->IsParameterValue()) {
862 current->ReplaceWith(invoke->InputAt(parameter_index++));
863 } else {
864 DCHECK(current->IsGoto() || current->IsSuspendCheck());
865 entry_block_->RemoveInstruction(current);
866 }
867 }
868
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000869 if (GetBlocks().Size() == 3) {
Nicolas Geoffraybe31ff92015-02-04 14:52:20 +0000870 // Simple case of an entry block, a body block, and an exit block.
871 // Put the body block's instruction into `invoke`'s block.
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000872 HBasicBlock* body = GetBlocks().Get(1);
Nicolas Geoffraybe31ff92015-02-04 14:52:20 +0000873 DCHECK(GetBlocks().Get(0)->IsEntryBlock());
874 DCHECK(GetBlocks().Get(2)->IsExitBlock());
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000875 DCHECK(!body->IsExitBlock());
876 HInstruction* last = body->GetLastInstruction();
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000877
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000878 invoke->GetBlock()->instructions_.AddAfter(invoke, body->GetInstructions());
879 body->GetInstructions().SetBlockOfInstructions(invoke->GetBlock());
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000880
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000881 // Replace the invoke with the return value of the inlined graph.
882 if (last->IsReturn()) {
883 invoke->ReplaceWith(last->InputAt(0));
884 } else {
885 DCHECK(last->IsReturnVoid());
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000886 }
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000887
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000888 invoke->GetBlock()->RemoveInstruction(last);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000889 } else {
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000890 // Need to inline multiple blocks. We split `invoke`'s block
891 // into two blocks, merge the first block of the inlined graph into
Nicolas Geoffraybe31ff92015-02-04 14:52:20 +0000892 // the first half, and replace the exit block of the inlined graph
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000893 // with the second half.
894 ArenaAllocator* allocator = outer_graph->GetArena();
895 HBasicBlock* at = invoke->GetBlock();
896 HBasicBlock* to = at->SplitAfter(invoke);
897
898 HBasicBlock* first = entry_block_->GetSuccessors().Get(0);
899 DCHECK(!first->IsInLoop());
900 at->MergeWith(first);
901 exit_block_->ReplaceWith(to);
902
903 // Update all predecessors of the exit block (now the `to` block)
904 // to not `HReturn` but `HGoto` instead. Also collect the return
905 // values if any, and potentially make it a phi if there are multiple
906 // predecessors.
907 HInstruction* return_value = nullptr;
908 for (size_t i = 0, e = to->GetPredecessors().Size(); i < e; ++i) {
909 HBasicBlock* predecessor = to->GetPredecessors().Get(i);
910 HInstruction* last = predecessor->GetLastInstruction();
911 if (!last->IsReturnVoid()) {
912 if (return_value != nullptr) {
913 if (!return_value->IsPhi()) {
Nicolas Geoffraybe31ff92015-02-04 14:52:20 +0000914 HPhi* phi = new (allocator) HPhi(allocator, kNoRegNumber, 0, invoke->GetType());
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000915 to->AddPhi(phi);
Nicolas Geoffraybe31ff92015-02-04 14:52:20 +0000916 phi->AddInput(return_value);
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000917 return_value = phi;
918 }
919 return_value->AsPhi()->AddInput(last->InputAt(0));
920 } else {
921 return_value = last->InputAt(0);
922 }
923 }
924 predecessor->AddInstruction(new (allocator) HGoto());
925 predecessor->RemoveInstruction(last);
926 }
927
928 if (return_value != nullptr) {
929 invoke->ReplaceWith(return_value);
930 }
931
932 // Update the meta information surrounding blocks:
933 // (1) the graph they are now in,
934 // (2) the reverse post order of that graph,
935 // (3) the potential loop information they are now in.
936
937 // We don't add the entry block, the exit block, and the first block, which
938 // has been merged with `at`.
939 static constexpr int kNumberOfSkippedBlocksInCallee = 3;
940
941 // We add the `to` block.
942 static constexpr int kNumberOfNewBlocksInCaller = 1;
943 size_t blocks_added = (reverse_post_order_.Size() - kNumberOfSkippedBlocksInCallee)
944 + kNumberOfNewBlocksInCaller;
945
946 // Find the location of `at` in the outer graph's reverse post order. The new
947 // blocks will be added after it.
948 size_t index_of_at = 0;
949 while (outer_graph->reverse_post_order_.Get(index_of_at) != at) {
950 index_of_at++;
951 }
952 MakeRoomFor(&outer_graph->reverse_post_order_, blocks_added, index_of_at);
953
954 // Do a reverse post order of the blocks in the callee and do (1), (2),
955 // and (3) to the blocks that apply.
956 HLoopInformation* info = at->GetLoopInformation();
957 for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) {
958 HBasicBlock* current = it.Current();
959 if (current != exit_block_ && current != entry_block_ && current != first) {
960 DCHECK(!current->IsInLoop());
961 DCHECK(current->GetGraph() == this);
962 current->SetGraph(outer_graph);
963 outer_graph->AddBlock(current);
964 outer_graph->reverse_post_order_.Put(++index_of_at, current);
965 if (info != nullptr) {
966 info->Add(current);
967 current->SetLoopInformation(info);
968 }
969 }
970 }
971
972 // Do (1), (2), and (3) to `to`.
973 to->SetGraph(outer_graph);
974 outer_graph->AddBlock(to);
975 outer_graph->reverse_post_order_.Put(++index_of_at, to);
976 if (info != nullptr) {
977 info->Add(to);
978 to->SetLoopInformation(info);
979 if (info->IsBackEdge(at)) {
980 // Only `at` can become a back edge, as the inlined blocks
981 // are predecessors of `at`.
982 DCHECK_EQ(1u, info->NumberOfBackEdges());
983 info->ClearBackEdges();
984 info->AddBackEdge(to);
985 }
986 }
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000987 }
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000988
989 // Finally remove the invoke from the caller.
990 invoke->GetBlock()->RemoveInstruction(invoke);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000991}
992
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000993} // namespace art