blob: ade31380ec5feed7147173e1ea3d321f846de712 [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
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000063void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010064 for (size_t i = 0; i < blocks_.Size(); ++i) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000065 if (!visited.IsBitSet(i)) {
66 HBasicBlock* block = blocks_.Get(i);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010067 for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010068 block->GetSuccessors().Get(j)->RemovePredecessor(block);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010069 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010070 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010071 block->RemovePhi(it.Current()->AsPhi());
72 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010073 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010074 block->RemoveInstruction(it.Current());
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000075 }
76 }
77 }
78}
79
80void HGraph::VisitBlockForBackEdges(HBasicBlock* block,
81 ArenaBitVector* visited,
Nicolas Geoffray804d0932014-05-02 08:46:00 +010082 ArenaBitVector* visiting) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +000083 int id = block->GetBlockId();
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000084 if (visited->IsBitSet(id)) return;
85
86 visited->SetBit(id);
87 visiting->SetBit(id);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010088 for (size_t i = 0; i < block->GetSuccessors().Size(); i++) {
89 HBasicBlock* successor = block->GetSuccessors().Get(i);
Nicolas Geoffray787c3072014-03-17 10:20:19 +000090 if (visiting->IsBitSet(successor->GetBlockId())) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000091 successor->AddBackEdge(block);
92 } else {
93 VisitBlockForBackEdges(successor, visited, visiting);
94 }
95 }
96 visiting->ClearBit(id);
97}
98
99void HGraph::BuildDominatorTree() {
100 ArenaBitVector visited(arena_, blocks_.Size(), false);
101
102 // (1) Find the back edges in the graph doing a DFS traversal.
103 FindBackEdges(&visited);
104
Roland Levillainfc600dc2014-12-02 17:16:31 +0000105 // (2) Remove instructions and phis from blocks not visited during
106 // the initial DFS as users from other instructions, so that
107 // users can be safely removed before uses later.
108 RemoveInstructionsAsUsersFromDeadBlocks(visited);
109
110 // (3) Remove blocks not visited during the initial DFS.
111 // Step (4) requires dead blocks to be removed from the
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000112 // predecessors list of live blocks.
113 RemoveDeadBlocks(visited);
114
Roland Levillainfc600dc2014-12-02 17:16:31 +0000115 // (4) Simplify the CFG now, so that we don't need to recompute
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100116 // dominators and the reverse post order.
117 SimplifyCFG();
118
Roland Levillainfc600dc2014-12-02 17:16:31 +0000119 // (5) Compute the immediate dominator of each block. We visit
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000120 // the successors of a block only when all its forward branches
121 // have been processed.
122 GrowableArray<size_t> visits(arena_, blocks_.Size());
123 visits.SetSize(blocks_.Size());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100124 reverse_post_order_.Add(entry_block_);
125 for (size_t i = 0; i < entry_block_->GetSuccessors().Size(); i++) {
126 VisitBlockForDominatorTree(entry_block_->GetSuccessors().Get(i), entry_block_, &visits);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000127 }
128}
129
130HBasicBlock* HGraph::FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const {
131 ArenaBitVector visited(arena_, blocks_.Size(), false);
132 // Walk the dominator tree of the first block and mark the visited blocks.
133 while (first != nullptr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000134 visited.SetBit(first->GetBlockId());
135 first = first->GetDominator();
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000136 }
137 // Walk the dominator tree of the second block until a marked block is found.
138 while (second != nullptr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000139 if (visited.IsBitSet(second->GetBlockId())) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000140 return second;
141 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000142 second = second->GetDominator();
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000143 }
144 LOG(ERROR) << "Could not find common dominator";
145 return nullptr;
146}
147
148void HGraph::VisitBlockForDominatorTree(HBasicBlock* block,
149 HBasicBlock* predecessor,
150 GrowableArray<size_t>* visits) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000151 if (block->GetDominator() == nullptr) {
152 block->SetDominator(predecessor);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000153 } else {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000154 block->SetDominator(FindCommonDominator(block->GetDominator(), predecessor));
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000155 }
156
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000157 visits->Increment(block->GetBlockId());
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000158 // Once all the forward edges have been visited, we know the immediate
159 // dominator of the block. We can then start visiting its successors.
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000160 if (visits->Get(block->GetBlockId()) ==
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100161 block->GetPredecessors().Size() - block->NumberOfBackEdges()) {
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100162 block->GetDominator()->AddDominatedBlock(block);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100163 reverse_post_order_.Add(block);
164 for (size_t i = 0; i < block->GetSuccessors().Size(); i++) {
165 VisitBlockForDominatorTree(block->GetSuccessors().Get(i), block, visits);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000166 }
167 }
168}
169
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000170void HGraph::TransformToSsa() {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100171 DCHECK(!reverse_post_order_.IsEmpty());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100172 SsaBuilder ssa_builder(this);
173 ssa_builder.BuildSsa();
174}
175
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100176void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
177 // Insert a new node between `block` and `successor` to split the
178 // critical edge.
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100179 HBasicBlock* new_block = new (arena_) HBasicBlock(this, successor->GetDexPc());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100180 AddBlock(new_block);
181 new_block->AddInstruction(new (arena_) HGoto());
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100182 block->ReplaceSuccessor(successor, new_block);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100183 new_block->AddSuccessor(successor);
184 if (successor->IsLoopHeader()) {
185 // If we split at a back edge boundary, make the new block the back edge.
186 HLoopInformation* info = successor->GetLoopInformation();
187 if (info->IsBackEdge(block)) {
188 info->RemoveBackEdge(block);
189 info->AddBackEdge(new_block);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100190 }
191 }
192}
193
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100194void HGraph::SimplifyLoop(HBasicBlock* header) {
195 HLoopInformation* info = header->GetLoopInformation();
196
197 // If there are more than one back edge, make them branch to the same block that
198 // will become the only back edge. This simplifies finding natural loops in the
199 // graph.
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100200 // Also, if the loop is a do/while (that is the back edge is an if), change the
201 // back edge to be a goto. This simplifies code generation of suspend cheks.
202 if (info->NumberOfBackEdges() > 1 || info->GetBackEdges().Get(0)->GetLastInstruction()->IsIf()) {
203 HBasicBlock* new_back_edge = new (arena_) HBasicBlock(this, header->GetDexPc());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100204 AddBlock(new_back_edge);
205 new_back_edge->AddInstruction(new (arena_) HGoto());
206 for (size_t pred = 0, e = info->GetBackEdges().Size(); pred < e; ++pred) {
207 HBasicBlock* back_edge = info->GetBackEdges().Get(pred);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100208 back_edge->ReplaceSuccessor(header, new_back_edge);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100209 }
210 info->ClearBackEdges();
211 info->AddBackEdge(new_back_edge);
212 new_back_edge->AddSuccessor(header);
213 }
214
215 // Make sure the loop has only one pre header. This simplifies SSA building by having
216 // to just look at the pre header to know which locals are initialized at entry of the
217 // loop.
218 size_t number_of_incomings = header->GetPredecessors().Size() - info->NumberOfBackEdges();
219 if (number_of_incomings != 1) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100220 HBasicBlock* pre_header = new (arena_) HBasicBlock(this, header->GetDexPc());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100221 AddBlock(pre_header);
222 pre_header->AddInstruction(new (arena_) HGoto());
223
224 ArenaBitVector back_edges(arena_, GetBlocks().Size(), false);
225 HBasicBlock* back_edge = info->GetBackEdges().Get(0);
226 for (size_t pred = 0; pred < header->GetPredecessors().Size(); ++pred) {
227 HBasicBlock* predecessor = header->GetPredecessors().Get(pred);
228 if (predecessor != back_edge) {
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100229 predecessor->ReplaceSuccessor(header, pre_header);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100230 pred--;
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100231 }
232 }
233 pre_header->AddSuccessor(header);
234 }
Nicolas Geoffray604c6e42014-09-17 12:08:44 +0100235
236 // Make sure the second predecessor of a loop header is the back edge.
237 if (header->GetPredecessors().Get(1) != info->GetBackEdges().Get(0)) {
238 header->SwapPredecessors();
239 }
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100240
241 // Place the suspend check at the beginning of the header, so that live registers
242 // will be known when allocating registers. Note that code generation can still
243 // generate the suspend check at the back edge, but needs to be careful with
244 // loop phi spill slots (which are not written to at back edge).
245 HInstruction* first_instruction = header->GetFirstInstruction();
246 if (!first_instruction->IsSuspendCheck()) {
247 HSuspendCheck* check = new (arena_) HSuspendCheck(header->GetDexPc());
248 header->InsertInstructionBefore(check, first_instruction);
249 first_instruction = check;
250 }
251 info->SetSuspendCheck(first_instruction->AsSuspendCheck());
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100252}
253
254void HGraph::SimplifyCFG() {
255 // Simplify the CFG for future analysis, and code generation:
256 // (1): Split critical edges.
257 // (2): Simplify loops by having only one back edge, and one preheader.
258 for (size_t i = 0; i < blocks_.Size(); ++i) {
259 HBasicBlock* block = blocks_.Get(i);
260 if (block->GetSuccessors().Size() > 1) {
261 for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
262 HBasicBlock* successor = block->GetSuccessors().Get(j);
263 if (successor->GetPredecessors().Size() > 1) {
264 SplitCriticalEdge(block, successor);
265 --j;
266 }
267 }
268 }
269 if (block->IsLoopHeader()) {
270 SimplifyLoop(block);
271 }
272 }
273}
274
Nicolas Geoffrayf5370122014-12-02 11:51:19 +0000275bool HGraph::AnalyzeNaturalLoops() const {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100276 for (size_t i = 0; i < blocks_.Size(); ++i) {
277 HBasicBlock* block = blocks_.Get(i);
278 if (block->IsLoopHeader()) {
279 HLoopInformation* info = block->GetLoopInformation();
280 if (!info->Populate()) {
281 // Abort if the loop is non natural. We currently bailout in such cases.
282 return false;
283 }
284 }
285 }
286 return true;
287}
288
289void HLoopInformation::PopulateRecursive(HBasicBlock* block) {
290 if (blocks_.IsBitSet(block->GetBlockId())) {
291 return;
292 }
293
294 blocks_.SetBit(block->GetBlockId());
295 block->SetInLoop(this);
296 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
297 PopulateRecursive(block->GetPredecessors().Get(i));
298 }
299}
300
301bool HLoopInformation::Populate() {
302 DCHECK_EQ(GetBackEdges().Size(), 1u);
303 HBasicBlock* back_edge = GetBackEdges().Get(0);
304 DCHECK(back_edge->GetDominator() != nullptr);
305 if (!header_->Dominates(back_edge)) {
306 // This loop is not natural. Do not bother going further.
307 return false;
308 }
309
310 // Populate this loop: starting with the back edge, recursively add predecessors
311 // that are not already part of that loop. Set the header as part of the loop
312 // to end the recursion.
313 // This is a recursive implementation of the algorithm described in
314 // "Advanced Compiler Design & Implementation" (Muchnick) p192.
315 blocks_.SetBit(header_->GetBlockId());
316 PopulateRecursive(back_edge);
317 return true;
318}
319
320HBasicBlock* HLoopInformation::GetPreHeader() const {
321 DCHECK_EQ(header_->GetPredecessors().Size(), 2u);
322 return header_->GetDominator();
323}
324
325bool HLoopInformation::Contains(const HBasicBlock& block) const {
326 return blocks_.IsBitSet(block.GetBlockId());
327}
328
329bool HLoopInformation::IsIn(const HLoopInformation& other) const {
330 return other.blocks_.IsBitSet(header_->GetBlockId());
331}
332
333bool HBasicBlock::Dominates(HBasicBlock* other) const {
334 // Walk up the dominator tree from `other`, to find out if `this`
335 // is an ancestor.
336 HBasicBlock* current = other;
337 while (current != nullptr) {
338 if (current == this) {
339 return true;
340 }
341 current = current->GetDominator();
342 }
343 return false;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100344}
345
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100346static void UpdateInputsUsers(HInstruction* instruction) {
347 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
348 instruction->InputAt(i)->AddUseAt(instruction, i);
349 }
350 // Environment should be created later.
351 DCHECK(!instruction->HasEnvironment());
352}
353
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100354void HBasicBlock::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
Roland Levillain476df552014-10-09 17:51:36 +0100355 DCHECK(!cursor->IsPhi());
356 DCHECK(!instruction->IsPhi());
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100357 DCHECK_EQ(instruction->GetId(), -1);
358 DCHECK_NE(cursor->GetId(), -1);
359 DCHECK_EQ(cursor->GetBlock(), this);
360 DCHECK(!instruction->IsControlFlow());
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100361 instruction->next_ = cursor;
362 instruction->previous_ = cursor->previous_;
363 cursor->previous_ = instruction;
364 if (GetFirstInstruction() == cursor) {
365 instructions_.first_instruction_ = instruction;
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100366 } else {
367 instruction->previous_->next_ = instruction;
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100368 }
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100369 instruction->SetBlock(this);
370 instruction->SetId(GetGraph()->GetNextInstructionId());
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100371 UpdateInputsUsers(instruction);
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100372}
373
Roland Levillainccc07a92014-09-16 14:48:16 +0100374void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
375 HInstruction* replacement) {
376 DCHECK(initial->GetBlock() == this);
377 InsertInstructionBefore(replacement, initial);
378 initial->ReplaceWith(replacement);
379 RemoveInstruction(initial);
380}
381
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100382static void Add(HInstructionList* instruction_list,
383 HBasicBlock* block,
384 HInstruction* instruction) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000385 DCHECK(instruction->GetBlock() == nullptr);
Nicolas Geoffray43c86422014-03-18 11:58:24 +0000386 DCHECK_EQ(instruction->GetId(), -1);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100387 instruction->SetBlock(block);
388 instruction->SetId(block->GetGraph()->GetNextInstructionId());
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100389 UpdateInputsUsers(instruction);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100390 instruction_list->AddInstruction(instruction);
391}
392
393void HBasicBlock::AddInstruction(HInstruction* instruction) {
394 Add(&instructions_, this, instruction);
395}
396
397void HBasicBlock::AddPhi(HPhi* phi) {
398 Add(&phis_, this, phi);
399}
400
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100401void HBasicBlock::InsertPhiAfter(HPhi* phi, HPhi* cursor) {
402 DCHECK_EQ(phi->GetId(), -1);
403 DCHECK_NE(cursor->GetId(), -1);
404 DCHECK_EQ(cursor->GetBlock(), this);
405 if (cursor->next_ == nullptr) {
406 cursor->next_ = phi;
407 phi->previous_ = cursor;
408 DCHECK(phi->next_ == nullptr);
409 } else {
410 phi->next_ = cursor->next_;
411 phi->previous_ = cursor;
412 cursor->next_ = phi;
413 phi->next_->previous_ = phi;
414 }
415 phi->SetBlock(this);
416 phi->SetId(GetGraph()->GetNextInstructionId());
417 UpdateInputsUsers(phi);
418}
419
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100420static void Remove(HInstructionList* instruction_list,
421 HBasicBlock* block,
422 HInstruction* instruction) {
423 DCHECK_EQ(block, instruction->GetBlock());
424 DCHECK(instruction->GetUses() == nullptr);
425 DCHECK(instruction->GetEnvUses() == nullptr);
426 instruction->SetBlock(nullptr);
427 instruction_list->RemoveInstruction(instruction);
428
Roland Levillainfc600dc2014-12-02 17:16:31 +0000429 RemoveAsUser(instruction);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100430}
431
432void HBasicBlock::RemoveInstruction(HInstruction* instruction) {
433 Remove(&instructions_, this, instruction);
434}
435
436void HBasicBlock::RemovePhi(HPhi* phi) {
437 Remove(&phis_, this, phi);
438}
439
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100440template <typename T>
441static void RemoveFromUseList(T* user,
442 size_t input_index,
443 HUseListNode<T>** list) {
444 HUseListNode<T>* previous = nullptr;
445 HUseListNode<T>* current = *list;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100446 while (current != nullptr) {
447 if (current->GetUser() == user && current->GetIndex() == input_index) {
448 if (previous == NULL) {
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100449 *list = current->GetTail();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100450 } else {
451 previous->SetTail(current->GetTail());
452 }
453 }
454 previous = current;
455 current = current->GetTail();
456 }
457}
458
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100459void HInstruction::RemoveUser(HInstruction* user, size_t input_index) {
460 RemoveFromUseList(user, input_index, &uses_);
461}
462
463void HInstruction::RemoveEnvironmentUser(HEnvironment* user, size_t input_index) {
464 RemoveFromUseList(user, input_index, &env_uses_);
465}
466
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100467void HInstructionList::AddInstruction(HInstruction* instruction) {
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000468 if (first_instruction_ == nullptr) {
469 DCHECK(last_instruction_ == nullptr);
470 first_instruction_ = last_instruction_ = instruction;
471 } else {
472 last_instruction_->next_ = instruction;
473 instruction->previous_ = last_instruction_;
474 last_instruction_ = instruction;
475 }
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000476}
477
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100478void HInstructionList::RemoveInstruction(HInstruction* instruction) {
479 if (instruction->previous_ != nullptr) {
480 instruction->previous_->next_ = instruction->next_;
481 }
482 if (instruction->next_ != nullptr) {
483 instruction->next_->previous_ = instruction->previous_;
484 }
485 if (instruction == first_instruction_) {
486 first_instruction_ = instruction->next_;
487 }
488 if (instruction == last_instruction_) {
489 last_instruction_ = instruction->previous_;
490 }
491}
492
Roland Levillain6b469232014-09-25 10:10:38 +0100493bool HInstructionList::Contains(HInstruction* instruction) const {
494 for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
495 if (it.Current() == instruction) {
496 return true;
497 }
498 }
499 return false;
500}
501
Roland Levillainccc07a92014-09-16 14:48:16 +0100502bool HInstructionList::FoundBefore(const HInstruction* instruction1,
503 const HInstruction* instruction2) const {
504 DCHECK_EQ(instruction1->GetBlock(), instruction2->GetBlock());
505 for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
506 if (it.Current() == instruction1) {
507 return true;
508 }
509 if (it.Current() == instruction2) {
510 return false;
511 }
512 }
513 LOG(FATAL) << "Did not find an order between two instructions of the same block.";
514 return true;
515}
516
Roland Levillain6c82d402014-10-13 16:10:27 +0100517bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
518 if (other_instruction == this) {
519 // An instruction does not strictly dominate itself.
520 return false;
521 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100522 HBasicBlock* block = GetBlock();
523 HBasicBlock* other_block = other_instruction->GetBlock();
524 if (block != other_block) {
525 return GetBlock()->Dominates(other_instruction->GetBlock());
526 } else {
527 // If both instructions are in the same block, ensure this
528 // instruction comes before `other_instruction`.
529 if (IsPhi()) {
530 if (!other_instruction->IsPhi()) {
531 // Phis appear before non phi-instructions so this instruction
532 // dominates `other_instruction`.
533 return true;
534 } else {
535 // There is no order among phis.
536 LOG(FATAL) << "There is no dominance between phis of a same block.";
537 return false;
538 }
539 } else {
540 // `this` is not a phi.
541 if (other_instruction->IsPhi()) {
542 // Phis appear before non phi-instructions so this instruction
543 // does not dominate `other_instruction`.
544 return false;
545 } else {
546 // Check whether this instruction comes before
547 // `other_instruction` in the instruction list.
548 return block->GetInstructions().FoundBefore(this, other_instruction);
549 }
550 }
551 }
552}
553
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100554void HInstruction::ReplaceWith(HInstruction* other) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100555 DCHECK(other != nullptr);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100556 for (HUseIterator<HInstruction> it(GetUses()); !it.Done(); it.Advance()) {
557 HUseListNode<HInstruction>* current = it.Current();
558 HInstruction* user = current->GetUser();
559 size_t input_index = current->GetIndex();
560 user->SetRawInputAt(input_index, other);
561 other->AddUseAt(user, input_index);
562 }
563
564 for (HUseIterator<HEnvironment> it(GetEnvUses()); !it.Done(); it.Advance()) {
565 HUseListNode<HEnvironment>* current = it.Current();
566 HEnvironment* user = current->GetUser();
567 size_t input_index = current->GetIndex();
568 user->SetRawEnvAt(input_index, other);
569 other->AddEnvUseAt(user, input_index);
570 }
571
572 uses_ = nullptr;
573 env_uses_ = nullptr;
574}
575
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100576void HInstruction::ReplaceInput(HInstruction* replacement, size_t index) {
577 InputAt(index)->RemoveUser(this, index);
578 SetRawInputAt(index, replacement);
579 replacement->AddUseAt(this, index);
580}
581
Nicolas Geoffray39468442014-09-02 15:17:15 +0100582size_t HInstruction::EnvironmentSize() const {
583 return HasEnvironment() ? environment_->Size() : 0;
584}
585
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100586void HPhi::AddInput(HInstruction* input) {
587 DCHECK(input->GetBlock() != nullptr);
588 inputs_.Add(input);
589 input->AddUseAt(this, inputs_.Size() - 1);
590}
591
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100592#define DEFINE_ACCEPT(name, super) \
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000593void H##name::Accept(HGraphVisitor* visitor) { \
594 visitor->Visit##name(this); \
595}
596
597FOR_EACH_INSTRUCTION(DEFINE_ACCEPT)
598
599#undef DEFINE_ACCEPT
600
601void HGraphVisitor::VisitInsertionOrder() {
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100602 const GrowableArray<HBasicBlock*>& blocks = graph_->GetBlocks();
603 for (size_t i = 0 ; i < blocks.Size(); i++) {
604 VisitBasicBlock(blocks.Get(i));
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000605 }
606}
607
Roland Levillain633021e2014-10-01 14:12:25 +0100608void HGraphVisitor::VisitReversePostOrder() {
609 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
610 VisitBasicBlock(it.Current());
611 }
612}
613
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000614void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100615 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100616 it.Current()->Accept(this);
617 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100618 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000619 it.Current()->Accept(this);
620 }
621}
622
Roland Levillain9240d6a2014-10-20 16:47:04 +0100623HConstant* HUnaryOperation::TryStaticEvaluation() const {
624 if (GetInput()->IsIntConstant()) {
625 int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
626 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
627 } else if (GetInput()->IsLongConstant()) {
Roland Levillainb762d2e2014-10-22 10:11:06 +0100628 // TODO: Implement static evaluation of long unary operations.
629 //
630 // Do not exit with a fatal condition here. Instead, simply
631 // return `nullptr' to notify the caller that this instruction
632 // cannot (yet) be statically evaluated.
Roland Levillain9240d6a2014-10-20 16:47:04 +0100633 return nullptr;
634 }
635 return nullptr;
636}
637
638HConstant* HBinaryOperation::TryStaticEvaluation() const {
Roland Levillain556c3d12014-09-18 15:25:07 +0100639 if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
640 int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
641 GetRight()->AsIntConstant()->GetValue());
Roland Levillain9240d6a2014-10-20 16:47:04 +0100642 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
Roland Levillain556c3d12014-09-18 15:25:07 +0100643 } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
644 int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
645 GetRight()->AsLongConstant()->GetValue());
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000646 if (GetResultType() == Primitive::kPrimLong) {
647 return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value);
648 } else {
Nicolas Geoffrayc399fdc2015-01-21 12:42:57 +0000649 DCHECK(GetResultType() == Primitive::kPrimInt);
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000650 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
651 }
Roland Levillain556c3d12014-09-18 15:25:07 +0100652 }
653 return nullptr;
654}
Dave Allison20dfc792014-06-16 20:44:29 -0700655
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100656bool HCondition::IsBeforeWhenDisregardMoves(HIf* if_) const {
657 HInstruction* previous = if_->GetPrevious();
658 while (previous != nullptr && previous->IsParallelMove()) {
659 previous = previous->GetPrevious();
660 }
661 return previous == this;
662}
663
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100664bool HInstruction::Equals(HInstruction* other) const {
665 if (!InstructionTypeEquals(other)) return false;
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100666 DCHECK_EQ(GetKind(), other->GetKind());
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100667 if (!InstructionDataEquals(other)) return false;
668 if (GetType() != other->GetType()) return false;
669 if (InputCount() != other->InputCount()) return false;
670
671 for (size_t i = 0, e = InputCount(); i < e; ++i) {
672 if (InputAt(i) != other->InputAt(i)) return false;
673 }
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100674 DCHECK_EQ(ComputeHashCode(), other->ComputeHashCode());
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100675 return true;
676}
677
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700678std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs) {
679#define DECLARE_CASE(type, super) case HInstruction::k##type: os << #type; break;
680 switch (rhs) {
681 FOR_EACH_INSTRUCTION(DECLARE_CASE)
682 default:
683 os << "Unknown instruction kind " << static_cast<int>(rhs);
684 break;
685 }
686#undef DECLARE_CASE
687 return os;
688}
689
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000690void HInstruction::InsertBefore(HInstruction* cursor) {
691 next_->previous_ = previous_;
692 if (previous_ != nullptr) {
693 previous_->next_ = next_;
694 }
695 if (block_->instructions_.first_instruction_ == this) {
696 block_->instructions_.first_instruction_ = next_;
697 }
698
699 previous_ = cursor->previous_;
700 if (previous_ != nullptr) {
701 previous_->next_ = this;
702 }
703 next_ = cursor;
704 cursor->previous_ = this;
705 block_ = cursor->block_;
706}
707
708void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
709 // We currently only support graphs with one entry block, one body block, and one exit block.
710 DCHECK_EQ(GetBlocks().Size(), 3u);
711
712 // Walk over the entry block and:
713 // - Move constants from the entry block to the outer_graph's entry block,
714 // - Replace HParameterValue instructions with their real value.
715 // - Remove suspend checks, that hold an environment.
716 int parameter_index = 0;
717 for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
718 HInstruction* current = it.Current();
719 if (current->IsConstant()) {
720 current->InsertBefore(outer_graph->GetEntryBlock()->GetLastInstruction());
721 } else if (current->IsParameterValue()) {
722 current->ReplaceWith(invoke->InputAt(parameter_index++));
723 } else {
724 DCHECK(current->IsGoto() || current->IsSuspendCheck());
725 entry_block_->RemoveInstruction(current);
726 }
727 }
728
729 // Insert the body's instructions except the last, just after the `invoke`
730 // instruction.
731 HBasicBlock* body = GetBlocks().Get(1);
732 DCHECK(!body->IsExitBlock());
733 HInstruction* last = body->GetLastInstruction();
734 HInstruction* first = body->GetFirstInstruction();
735
736 if (first != last) {
737 HInstruction* antelast = last->GetPrevious();
738
739 // Update the instruction list of the body to only contain the last
740 // instruction.
741 last->previous_ = nullptr;
742 body->instructions_.first_instruction_ = last;
743 body->instructions_.last_instruction_ = last;
744
745 // Update the instruction list of the `invoke`'s block to now contain the
746 // body's instructions.
747 antelast->next_ = invoke->GetNext();
748 antelast->next_->previous_ = antelast;
749 first->previous_ = invoke;
750 invoke->next_ = first;
751
752 // Update the block pointer of all instructions.
753 for (HInstruction* current = antelast; current != invoke; current = current->GetPrevious()) {
754 current->SetBlock(invoke->GetBlock());
755 }
756 }
757
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000758 // Replace the invoke with the return value of the inlined graph.
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000759 if (last->IsReturn()) {
760 invoke->ReplaceWith(last->InputAt(0));
761 body->RemoveInstruction(last);
762 } else {
763 DCHECK(last->IsReturnVoid());
764 }
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000765
766 // Finally remove the invoke from the caller.
767 invoke->GetBlock()->RemoveInstruction(invoke);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000768}
769
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000770} // namespace art