blob: 2b3ac1ac4abd665b3f3b4d224692cc1549fdf1ef [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"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010018#include "ssa_builder.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000019#include "utils/growable_array.h"
20
21namespace art {
22
23void HGraph::AddBlock(HBasicBlock* block) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +000024 block->SetBlockId(blocks_.Size());
Nicolas Geoffray818f2102014-02-18 16:43:35 +000025 blocks_.Add(block);
26}
27
Nicolas Geoffray804d0932014-05-02 08:46:00 +010028void HGraph::FindBackEdges(ArenaBitVector* visited) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000029 ArenaBitVector visiting(arena_, blocks_.Size(), false);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000030 VisitBlockForBackEdges(entry_block_, visited, &visiting);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000031}
32
Roland Levillainfc600dc2014-12-02 17:16:31 +000033static void RemoveAsUser(HInstruction* instruction) {
34 for (size_t i = 0; i < instruction->InputCount(); i++) {
35 instruction->InputAt(i)->RemoveUser(instruction, i);
36 }
37
38 HEnvironment* environment = instruction->GetEnvironment();
39 if (environment != nullptr) {
40 for (size_t i = 0, e = environment->Size(); i < e; ++i) {
41 HInstruction* vreg = environment->GetInstructionAt(i);
42 if (vreg != nullptr) {
43 vreg->RemoveEnvironmentUser(environment, i);
44 }
45 }
46 }
47}
48
49void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const {
50 for (size_t i = 0; i < blocks_.Size(); ++i) {
51 if (!visited.IsBitSet(i)) {
52 HBasicBlock* block = blocks_.Get(i);
53 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
54 RemoveAsUser(it.Current());
55 }
56 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
57 RemoveAsUser(it.Current());
58 }
59 }
60 }
61}
62
Jean Christophe Beyler53d9da82014-12-04 13:28:25 -080063void HGraph::RemoveBlock(HBasicBlock* block) const {
64 for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
65 block->GetSuccessors().Get(j)->RemovePredecessor(block);
66 }
67 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
68 block->RemovePhi(it.Current()->AsPhi());
69 }
70 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
71 block->RemoveInstruction(it.Current());
72 }
73}
74
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000075void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010076 for (size_t i = 0; i < blocks_.Size(); ++i) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000077 if (!visited.IsBitSet(i)) {
Jean Christophe Beyler53d9da82014-12-04 13:28:25 -080078 RemoveBlock(blocks_.Get(i));
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000079 }
80 }
81}
82
83void HGraph::VisitBlockForBackEdges(HBasicBlock* block,
84 ArenaBitVector* visited,
Nicolas Geoffray804d0932014-05-02 08:46:00 +010085 ArenaBitVector* visiting) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +000086 int id = block->GetBlockId();
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000087 if (visited->IsBitSet(id)) return;
88
89 visited->SetBit(id);
90 visiting->SetBit(id);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010091 for (size_t i = 0; i < block->GetSuccessors().Size(); i++) {
92 HBasicBlock* successor = block->GetSuccessors().Get(i);
Nicolas Geoffray787c3072014-03-17 10:20:19 +000093 if (visiting->IsBitSet(successor->GetBlockId())) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000094 successor->AddBackEdge(block);
95 } else {
96 VisitBlockForBackEdges(successor, visited, visiting);
97 }
98 }
99 visiting->ClearBit(id);
100}
101
102void HGraph::BuildDominatorTree() {
103 ArenaBitVector visited(arena_, blocks_.Size(), false);
104
105 // (1) Find the back edges in the graph doing a DFS traversal.
106 FindBackEdges(&visited);
107
Roland Levillainfc600dc2014-12-02 17:16:31 +0000108 // (2) Remove instructions and phis from blocks not visited during
109 // the initial DFS as users from other instructions, so that
110 // users can be safely removed before uses later.
111 RemoveInstructionsAsUsersFromDeadBlocks(visited);
112
113 // (3) Remove blocks not visited during the initial DFS.
114 // Step (4) requires dead blocks to be removed from the
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000115 // predecessors list of live blocks.
116 RemoveDeadBlocks(visited);
117
Roland Levillainfc600dc2014-12-02 17:16:31 +0000118 // (4) Simplify the CFG now, so that we don't need to recompute
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100119 // dominators and the reverse post order.
120 SimplifyCFG();
121
Roland Levillainfc600dc2014-12-02 17:16:31 +0000122 // (5) Compute the immediate dominator of each block. We visit
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000123 // the successors of a block only when all its forward branches
124 // have been processed.
125 GrowableArray<size_t> visits(arena_, blocks_.Size());
126 visits.SetSize(blocks_.Size());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100127 reverse_post_order_.Add(entry_block_);
128 for (size_t i = 0; i < entry_block_->GetSuccessors().Size(); i++) {
129 VisitBlockForDominatorTree(entry_block_->GetSuccessors().Get(i), entry_block_, &visits);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000130 }
131}
132
133HBasicBlock* HGraph::FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const {
134 ArenaBitVector visited(arena_, blocks_.Size(), false);
135 // Walk the dominator tree of the first block and mark the visited blocks.
136 while (first != nullptr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000137 visited.SetBit(first->GetBlockId());
138 first = first->GetDominator();
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000139 }
140 // Walk the dominator tree of the second block until a marked block is found.
141 while (second != nullptr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000142 if (visited.IsBitSet(second->GetBlockId())) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000143 return second;
144 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000145 second = second->GetDominator();
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000146 }
147 LOG(ERROR) << "Could not find common dominator";
148 return nullptr;
149}
150
151void HGraph::VisitBlockForDominatorTree(HBasicBlock* block,
152 HBasicBlock* predecessor,
153 GrowableArray<size_t>* visits) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000154 if (block->GetDominator() == nullptr) {
155 block->SetDominator(predecessor);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000156 } else {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000157 block->SetDominator(FindCommonDominator(block->GetDominator(), predecessor));
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000158 }
159
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000160 visits->Increment(block->GetBlockId());
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000161 // Once all the forward edges have been visited, we know the immediate
162 // dominator of the block. We can then start visiting its successors.
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000163 if (visits->Get(block->GetBlockId()) ==
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100164 block->GetPredecessors().Size() - block->NumberOfBackEdges()) {
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100165 block->GetDominator()->AddDominatedBlock(block);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100166 reverse_post_order_.Add(block);
167 for (size_t i = 0; i < block->GetSuccessors().Size(); i++) {
168 VisitBlockForDominatorTree(block->GetSuccessors().Get(i), block, visits);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000169 }
170 }
171}
172
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000173void HGraph::TransformToSsa() {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100174 DCHECK(!reverse_post_order_.IsEmpty());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100175 SsaBuilder ssa_builder(this);
176 ssa_builder.BuildSsa();
177}
178
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100179void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
180 // Insert a new node between `block` and `successor` to split the
181 // critical edge.
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100182 HBasicBlock* new_block = new (arena_) HBasicBlock(this, successor->GetDexPc());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100183 AddBlock(new_block);
184 new_block->AddInstruction(new (arena_) HGoto());
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100185 block->ReplaceSuccessor(successor, new_block);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100186 new_block->AddSuccessor(successor);
187 if (successor->IsLoopHeader()) {
188 // If we split at a back edge boundary, make the new block the back edge.
189 HLoopInformation* info = successor->GetLoopInformation();
190 if (info->IsBackEdge(block)) {
191 info->RemoveBackEdge(block);
192 info->AddBackEdge(new_block);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100193 }
194 }
195}
196
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100197void HGraph::SimplifyLoop(HBasicBlock* header) {
198 HLoopInformation* info = header->GetLoopInformation();
199
200 // If there are more than one back edge, make them branch to the same block that
201 // will become the only back edge. This simplifies finding natural loops in the
202 // graph.
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100203 // Also, if the loop is a do/while (that is the back edge is an if), change the
204 // back edge to be a goto. This simplifies code generation of suspend cheks.
205 if (info->NumberOfBackEdges() > 1 || info->GetBackEdges().Get(0)->GetLastInstruction()->IsIf()) {
206 HBasicBlock* new_back_edge = new (arena_) HBasicBlock(this, header->GetDexPc());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100207 AddBlock(new_back_edge);
208 new_back_edge->AddInstruction(new (arena_) HGoto());
209 for (size_t pred = 0, e = info->GetBackEdges().Size(); pred < e; ++pred) {
210 HBasicBlock* back_edge = info->GetBackEdges().Get(pred);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100211 back_edge->ReplaceSuccessor(header, new_back_edge);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100212 }
213 info->ClearBackEdges();
214 info->AddBackEdge(new_back_edge);
215 new_back_edge->AddSuccessor(header);
216 }
217
218 // Make sure the loop has only one pre header. This simplifies SSA building by having
219 // to just look at the pre header to know which locals are initialized at entry of the
220 // loop.
221 size_t number_of_incomings = header->GetPredecessors().Size() - info->NumberOfBackEdges();
222 if (number_of_incomings != 1) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100223 HBasicBlock* pre_header = new (arena_) HBasicBlock(this, header->GetDexPc());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100224 AddBlock(pre_header);
225 pre_header->AddInstruction(new (arena_) HGoto());
226
227 ArenaBitVector back_edges(arena_, GetBlocks().Size(), false);
228 HBasicBlock* back_edge = info->GetBackEdges().Get(0);
229 for (size_t pred = 0; pred < header->GetPredecessors().Size(); ++pred) {
230 HBasicBlock* predecessor = header->GetPredecessors().Get(pred);
231 if (predecessor != back_edge) {
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100232 predecessor->ReplaceSuccessor(header, pre_header);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100233 pred--;
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100234 }
235 }
236 pre_header->AddSuccessor(header);
237 }
Nicolas Geoffray604c6e42014-09-17 12:08:44 +0100238
239 // Make sure the second predecessor of a loop header is the back edge.
240 if (header->GetPredecessors().Get(1) != info->GetBackEdges().Get(0)) {
241 header->SwapPredecessors();
242 }
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100243
244 // Place the suspend check at the beginning of the header, so that live registers
245 // will be known when allocating registers. Note that code generation can still
246 // generate the suspend check at the back edge, but needs to be careful with
247 // loop phi spill slots (which are not written to at back edge).
248 HInstruction* first_instruction = header->GetFirstInstruction();
249 if (!first_instruction->IsSuspendCheck()) {
250 HSuspendCheck* check = new (arena_) HSuspendCheck(header->GetDexPc());
251 header->InsertInstructionBefore(check, first_instruction);
252 first_instruction = check;
253 }
254 info->SetSuspendCheck(first_instruction->AsSuspendCheck());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100255}
256
257void HGraph::SimplifyCFG() {
258 // Simplify the CFG for future analysis, and code generation:
259 // (1): Split critical edges.
260 // (2): Simplify loops by having only one back edge, and one preheader.
261 for (size_t i = 0; i < blocks_.Size(); ++i) {
262 HBasicBlock* block = blocks_.Get(i);
263 if (block->GetSuccessors().Size() > 1) {
264 for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
265 HBasicBlock* successor = block->GetSuccessors().Get(j);
266 if (successor->GetPredecessors().Size() > 1) {
267 SplitCriticalEdge(block, successor);
268 --j;
269 }
270 }
271 }
272 if (block->IsLoopHeader()) {
273 SimplifyLoop(block);
274 }
275 }
276}
277
Nicolas Geoffrayf5370122014-12-02 11:51:19 +0000278bool HGraph::AnalyzeNaturalLoops() const {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100279 for (size_t i = 0; i < blocks_.Size(); ++i) {
280 HBasicBlock* block = blocks_.Get(i);
281 if (block->IsLoopHeader()) {
282 HLoopInformation* info = block->GetLoopInformation();
283 if (!info->Populate()) {
284 // Abort if the loop is non natural. We currently bailout in such cases.
285 return false;
286 }
287 }
288 }
289 return true;
290}
291
292void HLoopInformation::PopulateRecursive(HBasicBlock* block) {
293 if (blocks_.IsBitSet(block->GetBlockId())) {
294 return;
295 }
296
297 blocks_.SetBit(block->GetBlockId());
298 block->SetInLoop(this);
299 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
300 PopulateRecursive(block->GetPredecessors().Get(i));
301 }
302}
303
304bool HLoopInformation::Populate() {
305 DCHECK_EQ(GetBackEdges().Size(), 1u);
306 HBasicBlock* back_edge = GetBackEdges().Get(0);
307 DCHECK(back_edge->GetDominator() != nullptr);
308 if (!header_->Dominates(back_edge)) {
309 // This loop is not natural. Do not bother going further.
310 return false;
311 }
312
313 // Populate this loop: starting with the back edge, recursively add predecessors
314 // that are not already part of that loop. Set the header as part of the loop
315 // to end the recursion.
316 // This is a recursive implementation of the algorithm described in
317 // "Advanced Compiler Design & Implementation" (Muchnick) p192.
318 blocks_.SetBit(header_->GetBlockId());
319 PopulateRecursive(back_edge);
320 return true;
321}
322
323HBasicBlock* HLoopInformation::GetPreHeader() const {
324 DCHECK_EQ(header_->GetPredecessors().Size(), 2u);
325 return header_->GetDominator();
326}
327
328bool HLoopInformation::Contains(const HBasicBlock& block) const {
329 return blocks_.IsBitSet(block.GetBlockId());
330}
331
332bool HLoopInformation::IsIn(const HLoopInformation& other) const {
333 return other.blocks_.IsBitSet(header_->GetBlockId());
334}
335
336bool HBasicBlock::Dominates(HBasicBlock* other) const {
337 // Walk up the dominator tree from `other`, to find out if `this`
338 // is an ancestor.
339 HBasicBlock* current = other;
340 while (current != nullptr) {
341 if (current == this) {
342 return true;
343 }
344 current = current->GetDominator();
345 }
346 return false;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100347}
348
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100349static void UpdateInputsUsers(HInstruction* instruction) {
350 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
351 instruction->InputAt(i)->AddUseAt(instruction, i);
352 }
353 // Environment should be created later.
354 DCHECK(!instruction->HasEnvironment());
355}
356
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100357void HBasicBlock::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
Roland Levillain476df552014-10-09 17:51:36 +0100358 DCHECK(!cursor->IsPhi());
359 DCHECK(!instruction->IsPhi());
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100360 DCHECK_EQ(instruction->GetId(), -1);
361 DCHECK_NE(cursor->GetId(), -1);
362 DCHECK_EQ(cursor->GetBlock(), this);
363 DCHECK(!instruction->IsControlFlow());
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100364 instruction->next_ = cursor;
365 instruction->previous_ = cursor->previous_;
366 cursor->previous_ = instruction;
367 if (GetFirstInstruction() == cursor) {
368 instructions_.first_instruction_ = instruction;
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100369 } else {
370 instruction->previous_->next_ = instruction;
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100371 }
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100372 instruction->SetBlock(this);
373 instruction->SetId(GetGraph()->GetNextInstructionId());
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100374 UpdateInputsUsers(instruction);
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100375}
376
Roland Levillainccc07a92014-09-16 14:48:16 +0100377void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
378 HInstruction* replacement) {
379 DCHECK(initial->GetBlock() == this);
380 InsertInstructionBefore(replacement, initial);
381 initial->ReplaceWith(replacement);
382 RemoveInstruction(initial);
383}
384
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100385static void Add(HInstructionList* instruction_list,
386 HBasicBlock* block,
387 HInstruction* instruction) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000388 DCHECK(instruction->GetBlock() == nullptr);
Nicolas Geoffray43c86422014-03-18 11:58:24 +0000389 DCHECK_EQ(instruction->GetId(), -1);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100390 instruction->SetBlock(block);
391 instruction->SetId(block->GetGraph()->GetNextInstructionId());
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100392 UpdateInputsUsers(instruction);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100393 instruction_list->AddInstruction(instruction);
394}
395
396void HBasicBlock::AddInstruction(HInstruction* instruction) {
397 Add(&instructions_, this, instruction);
398}
399
400void HBasicBlock::AddPhi(HPhi* phi) {
401 Add(&phis_, this, phi);
402}
403
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100404void HBasicBlock::InsertPhiAfter(HPhi* phi, HPhi* cursor) {
405 DCHECK_EQ(phi->GetId(), -1);
406 DCHECK_NE(cursor->GetId(), -1);
407 DCHECK_EQ(cursor->GetBlock(), this);
408 if (cursor->next_ == nullptr) {
409 cursor->next_ = phi;
410 phi->previous_ = cursor;
411 DCHECK(phi->next_ == nullptr);
412 } else {
413 phi->next_ = cursor->next_;
414 phi->previous_ = cursor;
415 cursor->next_ = phi;
416 phi->next_->previous_ = phi;
417 }
418 phi->SetBlock(this);
419 phi->SetId(GetGraph()->GetNextInstructionId());
420 UpdateInputsUsers(phi);
421}
422
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100423static void Remove(HInstructionList* instruction_list,
424 HBasicBlock* block,
425 HInstruction* instruction) {
426 DCHECK_EQ(block, instruction->GetBlock());
427 DCHECK(instruction->GetUses() == nullptr);
428 DCHECK(instruction->GetEnvUses() == nullptr);
429 instruction->SetBlock(nullptr);
430 instruction_list->RemoveInstruction(instruction);
431
Roland Levillainfc600dc2014-12-02 17:16:31 +0000432 RemoveAsUser(instruction);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100433}
434
435void HBasicBlock::RemoveInstruction(HInstruction* instruction) {
436 Remove(&instructions_, this, instruction);
437}
438
439void HBasicBlock::RemovePhi(HPhi* phi) {
440 Remove(&phis_, this, phi);
441}
442
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100443template <typename T>
444static void RemoveFromUseList(T* user,
445 size_t input_index,
446 HUseListNode<T>** list) {
447 HUseListNode<T>* previous = nullptr;
448 HUseListNode<T>* current = *list;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100449 while (current != nullptr) {
450 if (current->GetUser() == user && current->GetIndex() == input_index) {
451 if (previous == NULL) {
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100452 *list = current->GetTail();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100453 } else {
454 previous->SetTail(current->GetTail());
455 }
456 }
457 previous = current;
458 current = current->GetTail();
459 }
460}
461
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100462void HInstruction::RemoveUser(HInstruction* user, size_t input_index) {
463 RemoveFromUseList(user, input_index, &uses_);
464}
465
466void HInstruction::RemoveEnvironmentUser(HEnvironment* user, size_t input_index) {
467 RemoveFromUseList(user, input_index, &env_uses_);
468}
469
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100470void HInstructionList::AddInstruction(HInstruction* instruction) {
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000471 if (first_instruction_ == nullptr) {
472 DCHECK(last_instruction_ == nullptr);
473 first_instruction_ = last_instruction_ = instruction;
474 } else {
475 last_instruction_->next_ = instruction;
476 instruction->previous_ = last_instruction_;
477 last_instruction_ = instruction;
478 }
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000479}
480
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100481void HInstructionList::RemoveInstruction(HInstruction* instruction) {
482 if (instruction->previous_ != nullptr) {
483 instruction->previous_->next_ = instruction->next_;
484 }
485 if (instruction->next_ != nullptr) {
486 instruction->next_->previous_ = instruction->previous_;
487 }
488 if (instruction == first_instruction_) {
489 first_instruction_ = instruction->next_;
490 }
491 if (instruction == last_instruction_) {
492 last_instruction_ = instruction->previous_;
493 }
494}
495
Roland Levillain6b469232014-09-25 10:10:38 +0100496bool HInstructionList::Contains(HInstruction* instruction) const {
497 for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
498 if (it.Current() == instruction) {
499 return true;
500 }
501 }
502 return false;
503}
504
Roland Levillainccc07a92014-09-16 14:48:16 +0100505bool HInstructionList::FoundBefore(const HInstruction* instruction1,
506 const HInstruction* instruction2) const {
507 DCHECK_EQ(instruction1->GetBlock(), instruction2->GetBlock());
508 for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
509 if (it.Current() == instruction1) {
510 return true;
511 }
512 if (it.Current() == instruction2) {
513 return false;
514 }
515 }
516 LOG(FATAL) << "Did not find an order between two instructions of the same block.";
517 return true;
518}
519
Roland Levillain6c82d402014-10-13 16:10:27 +0100520bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
521 if (other_instruction == this) {
522 // An instruction does not strictly dominate itself.
523 return false;
524 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100525 HBasicBlock* block = GetBlock();
526 HBasicBlock* other_block = other_instruction->GetBlock();
527 if (block != other_block) {
528 return GetBlock()->Dominates(other_instruction->GetBlock());
529 } else {
530 // If both instructions are in the same block, ensure this
531 // instruction comes before `other_instruction`.
532 if (IsPhi()) {
533 if (!other_instruction->IsPhi()) {
534 // Phis appear before non phi-instructions so this instruction
535 // dominates `other_instruction`.
536 return true;
537 } else {
538 // There is no order among phis.
539 LOG(FATAL) << "There is no dominance between phis of a same block.";
540 return false;
541 }
542 } else {
543 // `this` is not a phi.
544 if (other_instruction->IsPhi()) {
545 // Phis appear before non phi-instructions so this instruction
546 // does not dominate `other_instruction`.
547 return false;
548 } else {
549 // Check whether this instruction comes before
550 // `other_instruction` in the instruction list.
551 return block->GetInstructions().FoundBefore(this, other_instruction);
552 }
553 }
554 }
555}
556
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100557void HInstruction::ReplaceWith(HInstruction* other) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100558 DCHECK(other != nullptr);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100559 for (HUseIterator<HInstruction> it(GetUses()); !it.Done(); it.Advance()) {
560 HUseListNode<HInstruction>* current = it.Current();
561 HInstruction* user = current->GetUser();
562 size_t input_index = current->GetIndex();
563 user->SetRawInputAt(input_index, other);
564 other->AddUseAt(user, input_index);
565 }
566
567 for (HUseIterator<HEnvironment> it(GetEnvUses()); !it.Done(); it.Advance()) {
568 HUseListNode<HEnvironment>* current = it.Current();
569 HEnvironment* user = current->GetUser();
570 size_t input_index = current->GetIndex();
571 user->SetRawEnvAt(input_index, other);
572 other->AddEnvUseAt(user, input_index);
573 }
574
575 uses_ = nullptr;
576 env_uses_ = nullptr;
577}
578
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100579void HInstruction::ReplaceInput(HInstruction* replacement, size_t index) {
580 InputAt(index)->RemoveUser(this, index);
581 SetRawInputAt(index, replacement);
582 replacement->AddUseAt(this, index);
583}
584
Nicolas Geoffray39468442014-09-02 15:17:15 +0100585size_t HInstruction::EnvironmentSize() const {
586 return HasEnvironment() ? environment_->Size() : 0;
587}
588
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100589void HPhi::AddInput(HInstruction* input) {
590 DCHECK(input->GetBlock() != nullptr);
591 inputs_.Add(input);
592 input->AddUseAt(this, inputs_.Size() - 1);
593}
594
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100595#define DEFINE_ACCEPT(name, super) \
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000596void H##name::Accept(HGraphVisitor* visitor) { \
597 visitor->Visit##name(this); \
598}
599
600FOR_EACH_INSTRUCTION(DEFINE_ACCEPT)
601
602#undef DEFINE_ACCEPT
603
604void HGraphVisitor::VisitInsertionOrder() {
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100605 const GrowableArray<HBasicBlock*>& blocks = graph_->GetBlocks();
606 for (size_t i = 0 ; i < blocks.Size(); i++) {
607 VisitBasicBlock(blocks.Get(i));
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000608 }
609}
610
Roland Levillain633021e2014-10-01 14:12:25 +0100611void HGraphVisitor::VisitReversePostOrder() {
612 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
613 VisitBasicBlock(it.Current());
614 }
615}
616
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000617void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100618 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100619 it.Current()->Accept(this);
620 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100621 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000622 it.Current()->Accept(this);
623 }
624}
625
Roland Levillain9240d6a2014-10-20 16:47:04 +0100626HConstant* HUnaryOperation::TryStaticEvaluation() const {
627 if (GetInput()->IsIntConstant()) {
628 int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
629 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
630 } else if (GetInput()->IsLongConstant()) {
Roland Levillainb762d2e2014-10-22 10:11:06 +0100631 // TODO: Implement static evaluation of long unary operations.
632 //
633 // Do not exit with a fatal condition here. Instead, simply
634 // return `nullptr' to notify the caller that this instruction
635 // cannot (yet) be statically evaluated.
Roland Levillain9240d6a2014-10-20 16:47:04 +0100636 return nullptr;
637 }
638 return nullptr;
639}
640
641HConstant* HBinaryOperation::TryStaticEvaluation() const {
Roland Levillain556c3d12014-09-18 15:25:07 +0100642 if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
643 int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
644 GetRight()->AsIntConstant()->GetValue());
Roland Levillain9240d6a2014-10-20 16:47:04 +0100645 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
Roland Levillain556c3d12014-09-18 15:25:07 +0100646 } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
647 int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
648 GetRight()->AsLongConstant()->GetValue());
Roland Levillain9240d6a2014-10-20 16:47:04 +0100649 return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value);
Roland Levillain556c3d12014-09-18 15:25:07 +0100650 }
651 return nullptr;
652}
Dave Allison20dfc792014-06-16 20:44:29 -0700653
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100654bool HCondition::IsBeforeWhenDisregardMoves(HIf* if_) const {
655 HInstruction* previous = if_->GetPrevious();
656 while (previous != nullptr && previous->IsParallelMove()) {
657 previous = previous->GetPrevious();
658 }
659 return previous == this;
660}
661
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100662bool HInstruction::Equals(HInstruction* other) const {
663 if (!InstructionTypeEquals(other)) return false;
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100664 DCHECK_EQ(GetKind(), other->GetKind());
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100665 if (!InstructionDataEquals(other)) return false;
666 if (GetType() != other->GetType()) return false;
667 if (InputCount() != other->InputCount()) return false;
668
669 for (size_t i = 0, e = InputCount(); i < e; ++i) {
670 if (InputAt(i) != other->InputAt(i)) return false;
671 }
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100672 DCHECK_EQ(ComputeHashCode(), other->ComputeHashCode());
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100673 return true;
674}
675
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700676std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs) {
677#define DECLARE_CASE(type, super) case HInstruction::k##type: os << #type; break;
678 switch (rhs) {
679 FOR_EACH_INSTRUCTION(DECLARE_CASE)
680 default:
681 os << "Unknown instruction kind " << static_cast<int>(rhs);
682 break;
683 }
684#undef DECLARE_CASE
685 return os;
686}
687
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000688void HInstruction::InsertBefore(HInstruction* cursor) {
689 next_->previous_ = previous_;
690 if (previous_ != nullptr) {
691 previous_->next_ = next_;
692 }
693 if (block_->instructions_.first_instruction_ == this) {
694 block_->instructions_.first_instruction_ = next_;
695 }
696
697 previous_ = cursor->previous_;
698 if (previous_ != nullptr) {
699 previous_->next_ = this;
700 }
701 next_ = cursor;
702 cursor->previous_ = this;
703 block_ = cursor->block_;
704}
705
706void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
707 // We currently only support graphs with one entry block, one body block, and one exit block.
708 DCHECK_EQ(GetBlocks().Size(), 3u);
709
710 // Walk over the entry block and:
711 // - Move constants from the entry block to the outer_graph's entry block,
712 // - Replace HParameterValue instructions with their real value.
713 // - Remove suspend checks, that hold an environment.
714 int parameter_index = 0;
715 for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
716 HInstruction* current = it.Current();
717 if (current->IsConstant()) {
718 current->InsertBefore(outer_graph->GetEntryBlock()->GetLastInstruction());
719 } else if (current->IsParameterValue()) {
720 current->ReplaceWith(invoke->InputAt(parameter_index++));
721 } else {
722 DCHECK(current->IsGoto() || current->IsSuspendCheck());
723 entry_block_->RemoveInstruction(current);
724 }
725 }
726
727 // Insert the body's instructions except the last, just after the `invoke`
728 // instruction.
729 HBasicBlock* body = GetBlocks().Get(1);
730 DCHECK(!body->IsExitBlock());
731 HInstruction* last = body->GetLastInstruction();
732 HInstruction* first = body->GetFirstInstruction();
733
734 if (first != last) {
735 HInstruction* antelast = last->GetPrevious();
736
737 // Update the instruction list of the body to only contain the last
738 // instruction.
739 last->previous_ = nullptr;
740 body->instructions_.first_instruction_ = last;
741 body->instructions_.last_instruction_ = last;
742
743 // Update the instruction list of the `invoke`'s block to now contain the
744 // body's instructions.
745 antelast->next_ = invoke->GetNext();
746 antelast->next_->previous_ = antelast;
747 first->previous_ = invoke;
748 invoke->next_ = first;
749
750 // Update the block pointer of all instructions.
751 for (HInstruction* current = antelast; current != invoke; current = current->GetPrevious()) {
752 current->SetBlock(invoke->GetBlock());
753 }
754 }
755
756 // Finally, replace the invoke with the return value of the inlined graph.
757 if (last->IsReturn()) {
758 invoke->ReplaceWith(last->InputAt(0));
759 body->RemoveInstruction(last);
760 } else {
761 DCHECK(last->IsReturnVoid());
762 }
763}
764
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000765} // namespace art