blob: 5fd75f652d91ce04ed5445bc6ea4f6c32ad8bf9c [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
295void HLoopInformation::PopulateRecursive(HBasicBlock* block) {
296 if (blocks_.IsBitSet(block->GetBlockId())) {
297 return;
298 }
299
300 blocks_.SetBit(block->GetBlockId());
301 block->SetInLoop(this);
302 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
303 PopulateRecursive(block->GetPredecessors().Get(i));
304 }
305}
306
307bool HLoopInformation::Populate() {
308 DCHECK_EQ(GetBackEdges().Size(), 1u);
309 HBasicBlock* back_edge = GetBackEdges().Get(0);
310 DCHECK(back_edge->GetDominator() != nullptr);
311 if (!header_->Dominates(back_edge)) {
312 // This loop is not natural. Do not bother going further.
313 return false;
314 }
315
316 // Populate this loop: starting with the back edge, recursively add predecessors
317 // that are not already part of that loop. Set the header as part of the loop
318 // to end the recursion.
319 // This is a recursive implementation of the algorithm described in
320 // "Advanced Compiler Design & Implementation" (Muchnick) p192.
321 blocks_.SetBit(header_->GetBlockId());
322 PopulateRecursive(back_edge);
323 return true;
324}
325
326HBasicBlock* HLoopInformation::GetPreHeader() const {
327 DCHECK_EQ(header_->GetPredecessors().Size(), 2u);
328 return header_->GetDominator();
329}
330
331bool HLoopInformation::Contains(const HBasicBlock& block) const {
332 return blocks_.IsBitSet(block.GetBlockId());
333}
334
335bool HLoopInformation::IsIn(const HLoopInformation& other) const {
336 return other.blocks_.IsBitSet(header_->GetBlockId());
337}
338
339bool HBasicBlock::Dominates(HBasicBlock* other) const {
340 // Walk up the dominator tree from `other`, to find out if `this`
341 // is an ancestor.
342 HBasicBlock* current = other;
343 while (current != nullptr) {
344 if (current == this) {
345 return true;
346 }
347 current = current->GetDominator();
348 }
349 return false;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100350}
351
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100352static void UpdateInputsUsers(HInstruction* instruction) {
353 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
354 instruction->InputAt(i)->AddUseAt(instruction, i);
355 }
356 // Environment should be created later.
357 DCHECK(!instruction->HasEnvironment());
358}
359
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100360void HBasicBlock::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
Roland Levillain476df552014-10-09 17:51:36 +0100361 DCHECK(!cursor->IsPhi());
362 DCHECK(!instruction->IsPhi());
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100363 DCHECK_EQ(instruction->GetId(), -1);
364 DCHECK_NE(cursor->GetId(), -1);
365 DCHECK_EQ(cursor->GetBlock(), this);
366 DCHECK(!instruction->IsControlFlow());
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100367 instruction->next_ = cursor;
368 instruction->previous_ = cursor->previous_;
369 cursor->previous_ = instruction;
370 if (GetFirstInstruction() == cursor) {
371 instructions_.first_instruction_ = instruction;
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100372 } else {
373 instruction->previous_->next_ = instruction;
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100374 }
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100375 instruction->SetBlock(this);
376 instruction->SetId(GetGraph()->GetNextInstructionId());
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100377 UpdateInputsUsers(instruction);
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100378}
379
Roland Levillainccc07a92014-09-16 14:48:16 +0100380void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
381 HInstruction* replacement) {
382 DCHECK(initial->GetBlock() == this);
383 InsertInstructionBefore(replacement, initial);
384 initial->ReplaceWith(replacement);
385 RemoveInstruction(initial);
386}
387
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100388static void Add(HInstructionList* instruction_list,
389 HBasicBlock* block,
390 HInstruction* instruction) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000391 DCHECK(instruction->GetBlock() == nullptr);
Nicolas Geoffray43c86422014-03-18 11:58:24 +0000392 DCHECK_EQ(instruction->GetId(), -1);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100393 instruction->SetBlock(block);
394 instruction->SetId(block->GetGraph()->GetNextInstructionId());
Nicolas Geoffray191c4b12014-10-07 14:14:27 +0100395 UpdateInputsUsers(instruction);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100396 instruction_list->AddInstruction(instruction);
397}
398
399void HBasicBlock::AddInstruction(HInstruction* instruction) {
400 Add(&instructions_, this, instruction);
401}
402
403void HBasicBlock::AddPhi(HPhi* phi) {
404 Add(&phis_, this, phi);
405}
406
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100407void HBasicBlock::InsertPhiAfter(HPhi* phi, HPhi* cursor) {
408 DCHECK_EQ(phi->GetId(), -1);
409 DCHECK_NE(cursor->GetId(), -1);
410 DCHECK_EQ(cursor->GetBlock(), this);
411 if (cursor->next_ == nullptr) {
412 cursor->next_ = phi;
413 phi->previous_ = cursor;
414 DCHECK(phi->next_ == nullptr);
415 } else {
416 phi->next_ = cursor->next_;
417 phi->previous_ = cursor;
418 cursor->next_ = phi;
419 phi->next_->previous_ = phi;
420 }
421 phi->SetBlock(this);
422 phi->SetId(GetGraph()->GetNextInstructionId());
423 UpdateInputsUsers(phi);
424}
425
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100426static void Remove(HInstructionList* instruction_list,
427 HBasicBlock* block,
428 HInstruction* instruction) {
429 DCHECK_EQ(block, instruction->GetBlock());
David Brazdiled596192015-01-23 10:39:45 +0000430 DCHECK(instruction->GetUses().IsEmpty());
431 DCHECK(instruction->GetEnvUses().IsEmpty());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100432 instruction->SetBlock(nullptr);
433 instruction_list->RemoveInstruction(instruction);
434
Roland Levillainfc600dc2014-12-02 17:16:31 +0000435 RemoveAsUser(instruction);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100436}
437
438void HBasicBlock::RemoveInstruction(HInstruction* instruction) {
439 Remove(&instructions_, this, instruction);
440}
441
442void HBasicBlock::RemovePhi(HPhi* phi) {
443 Remove(&phis_, this, phi);
444}
445
David Brazdiled596192015-01-23 10:39:45 +0000446void HEnvironment::CopyFrom(HEnvironment* env) {
447 for (size_t i = 0; i < env->Size(); i++) {
448 HInstruction* instruction = env->GetInstructionAt(i);
449 SetRawEnvAt(i, instruction);
450 if (instruction != nullptr) {
451 instruction->AddEnvUseAt(this, i);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100452 }
David Brazdiled596192015-01-23 10:39:45 +0000453 }
454}
455
456template <typename T>
457static void RemoveFromUseList(T user, size_t input_index, HUseList<T>* list) {
458 HUseListNode<T>* current;
459 for (HUseIterator<HInstruction*> use_it(*list); !use_it.Done(); use_it.Advance()) {
460 current = use_it.Current();
461 if (current->GetUser() == user && current->GetIndex() == input_index) {
462 list->Remove(current);
463 }
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100464 }
465}
466
Calin Juravle77520bc2015-01-12 18:45:46 +0000467HInstruction* HInstruction::GetNextDisregardingMoves() const {
468 HInstruction* next = GetNext();
469 while (next != nullptr && next->IsParallelMove()) {
470 next = next->GetNext();
471 }
472 return next;
473}
474
475HInstruction* HInstruction::GetPreviousDisregardingMoves() const {
476 HInstruction* previous = GetPrevious();
477 while (previous != nullptr && previous->IsParallelMove()) {
478 previous = previous->GetPrevious();
479 }
480 return previous;
481}
482
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100483void HInstruction::RemoveUser(HInstruction* user, size_t input_index) {
484 RemoveFromUseList(user, input_index, &uses_);
485}
486
David Brazdiled596192015-01-23 10:39:45 +0000487void HInstruction::RemoveEnvironmentUser(HUseListNode<HEnvironment*>* use) {
488 env_uses_.Remove(use);
Nicolas Geoffray724c9632014-09-22 12:27:27 +0100489}
490
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100491void HInstructionList::AddInstruction(HInstruction* instruction) {
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000492 if (first_instruction_ == nullptr) {
493 DCHECK(last_instruction_ == nullptr);
494 first_instruction_ = last_instruction_ = instruction;
495 } else {
496 last_instruction_->next_ = instruction;
497 instruction->previous_ = last_instruction_;
498 last_instruction_ = instruction;
499 }
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000500}
501
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100502void HInstructionList::RemoveInstruction(HInstruction* instruction) {
503 if (instruction->previous_ != nullptr) {
504 instruction->previous_->next_ = instruction->next_;
505 }
506 if (instruction->next_ != nullptr) {
507 instruction->next_->previous_ = instruction->previous_;
508 }
509 if (instruction == first_instruction_) {
510 first_instruction_ = instruction->next_;
511 }
512 if (instruction == last_instruction_) {
513 last_instruction_ = instruction->previous_;
514 }
515}
516
Roland Levillain6b469232014-09-25 10:10:38 +0100517bool HInstructionList::Contains(HInstruction* instruction) const {
518 for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
519 if (it.Current() == instruction) {
520 return true;
521 }
522 }
523 return false;
524}
525
Roland Levillainccc07a92014-09-16 14:48:16 +0100526bool HInstructionList::FoundBefore(const HInstruction* instruction1,
527 const HInstruction* instruction2) const {
528 DCHECK_EQ(instruction1->GetBlock(), instruction2->GetBlock());
529 for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
530 if (it.Current() == instruction1) {
531 return true;
532 }
533 if (it.Current() == instruction2) {
534 return false;
535 }
536 }
537 LOG(FATAL) << "Did not find an order between two instructions of the same block.";
538 return true;
539}
540
Roland Levillain6c82d402014-10-13 16:10:27 +0100541bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
542 if (other_instruction == this) {
543 // An instruction does not strictly dominate itself.
544 return false;
545 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100546 HBasicBlock* block = GetBlock();
547 HBasicBlock* other_block = other_instruction->GetBlock();
548 if (block != other_block) {
549 return GetBlock()->Dominates(other_instruction->GetBlock());
550 } else {
551 // If both instructions are in the same block, ensure this
552 // instruction comes before `other_instruction`.
553 if (IsPhi()) {
554 if (!other_instruction->IsPhi()) {
555 // Phis appear before non phi-instructions so this instruction
556 // dominates `other_instruction`.
557 return true;
558 } else {
559 // There is no order among phis.
560 LOG(FATAL) << "There is no dominance between phis of a same block.";
561 return false;
562 }
563 } else {
564 // `this` is not a phi.
565 if (other_instruction->IsPhi()) {
566 // Phis appear before non phi-instructions so this instruction
567 // does not dominate `other_instruction`.
568 return false;
569 } else {
570 // Check whether this instruction comes before
571 // `other_instruction` in the instruction list.
572 return block->GetInstructions().FoundBefore(this, other_instruction);
573 }
574 }
575 }
576}
577
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100578void HInstruction::ReplaceWith(HInstruction* other) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100579 DCHECK(other != nullptr);
David Brazdiled596192015-01-23 10:39:45 +0000580 for (HUseIterator<HInstruction*> it(GetUses()); !it.Done(); it.Advance()) {
581 HUseListNode<HInstruction*>* current = it.Current();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100582 HInstruction* user = current->GetUser();
583 size_t input_index = current->GetIndex();
584 user->SetRawInputAt(input_index, other);
585 other->AddUseAt(user, input_index);
586 }
587
David Brazdiled596192015-01-23 10:39:45 +0000588 for (HUseIterator<HEnvironment*> it(GetEnvUses()); !it.Done(); it.Advance()) {
589 HUseListNode<HEnvironment*>* current = it.Current();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100590 HEnvironment* user = current->GetUser();
591 size_t input_index = current->GetIndex();
592 user->SetRawEnvAt(input_index, other);
593 other->AddEnvUseAt(user, input_index);
594 }
595
David Brazdiled596192015-01-23 10:39:45 +0000596 uses_.Clear();
597 env_uses_.Clear();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100598}
599
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100600void HInstruction::ReplaceInput(HInstruction* replacement, size_t index) {
601 InputAt(index)->RemoveUser(this, index);
602 SetRawInputAt(index, replacement);
603 replacement->AddUseAt(this, index);
604}
605
Nicolas Geoffray39468442014-09-02 15:17:15 +0100606size_t HInstruction::EnvironmentSize() const {
607 return HasEnvironment() ? environment_->Size() : 0;
608}
609
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100610void HPhi::AddInput(HInstruction* input) {
611 DCHECK(input->GetBlock() != nullptr);
612 inputs_.Add(input);
613 input->AddUseAt(this, inputs_.Size() - 1);
614}
615
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100616#define DEFINE_ACCEPT(name, super) \
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000617void H##name::Accept(HGraphVisitor* visitor) { \
618 visitor->Visit##name(this); \
619}
620
621FOR_EACH_INSTRUCTION(DEFINE_ACCEPT)
622
623#undef DEFINE_ACCEPT
624
625void HGraphVisitor::VisitInsertionOrder() {
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100626 const GrowableArray<HBasicBlock*>& blocks = graph_->GetBlocks();
627 for (size_t i = 0 ; i < blocks.Size(); i++) {
628 VisitBasicBlock(blocks.Get(i));
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000629 }
630}
631
Roland Levillain633021e2014-10-01 14:12:25 +0100632void HGraphVisitor::VisitReversePostOrder() {
633 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
634 VisitBasicBlock(it.Current());
635 }
636}
637
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000638void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100639 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100640 it.Current()->Accept(this);
641 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100642 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000643 it.Current()->Accept(this);
644 }
645}
646
Roland Levillain9240d6a2014-10-20 16:47:04 +0100647HConstant* HUnaryOperation::TryStaticEvaluation() const {
648 if (GetInput()->IsIntConstant()) {
649 int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
650 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
651 } else if (GetInput()->IsLongConstant()) {
Roland Levillainb762d2e2014-10-22 10:11:06 +0100652 // TODO: Implement static evaluation of long unary operations.
653 //
654 // Do not exit with a fatal condition here. Instead, simply
655 // return `nullptr' to notify the caller that this instruction
656 // cannot (yet) be statically evaluated.
Roland Levillain9240d6a2014-10-20 16:47:04 +0100657 return nullptr;
658 }
659 return nullptr;
660}
661
662HConstant* HBinaryOperation::TryStaticEvaluation() const {
Roland Levillain556c3d12014-09-18 15:25:07 +0100663 if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
664 int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
665 GetRight()->AsIntConstant()->GetValue());
Roland Levillain9240d6a2014-10-20 16:47:04 +0100666 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
Roland Levillain556c3d12014-09-18 15:25:07 +0100667 } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
668 int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
669 GetRight()->AsLongConstant()->GetValue());
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000670 if (GetResultType() == Primitive::kPrimLong) {
671 return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value);
672 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000673 DCHECK_EQ(GetResultType(), Primitive::kPrimInt);
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000674 return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
675 }
Roland Levillain556c3d12014-09-18 15:25:07 +0100676 }
677 return nullptr;
678}
Dave Allison20dfc792014-06-16 20:44:29 -0700679
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100680bool HCondition::IsBeforeWhenDisregardMoves(HIf* if_) const {
Calin Juravle77520bc2015-01-12 18:45:46 +0000681 return this == if_->GetPreviousDisregardingMoves();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100682}
683
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100684bool HInstruction::Equals(HInstruction* other) const {
685 if (!InstructionTypeEquals(other)) return false;
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100686 DCHECK_EQ(GetKind(), other->GetKind());
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100687 if (!InstructionDataEquals(other)) return false;
688 if (GetType() != other->GetType()) return false;
689 if (InputCount() != other->InputCount()) return false;
690
691 for (size_t i = 0, e = InputCount(); i < e; ++i) {
692 if (InputAt(i) != other->InputAt(i)) return false;
693 }
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100694 DCHECK_EQ(ComputeHashCode(), other->ComputeHashCode());
Nicolas Geoffray065bf772014-09-03 14:51:22 +0100695 return true;
696}
697
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700698std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs) {
699#define DECLARE_CASE(type, super) case HInstruction::k##type: os << #type; break;
700 switch (rhs) {
701 FOR_EACH_INSTRUCTION(DECLARE_CASE)
702 default:
703 os << "Unknown instruction kind " << static_cast<int>(rhs);
704 break;
705 }
706#undef DECLARE_CASE
707 return os;
708}
709
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000710void HInstruction::MoveBefore(HInstruction* cursor) {
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000711 next_->previous_ = previous_;
712 if (previous_ != nullptr) {
713 previous_->next_ = next_;
714 }
715 if (block_->instructions_.first_instruction_ == this) {
716 block_->instructions_.first_instruction_ = next_;
717 }
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000718 DCHECK_NE(block_->instructions_.last_instruction_, this);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000719
720 previous_ = cursor->previous_;
721 if (previous_ != nullptr) {
722 previous_->next_ = this;
723 }
724 next_ = cursor;
725 cursor->previous_ = this;
726 block_ = cursor->block_;
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000727
728 if (block_->instructions_.first_instruction_ == cursor) {
729 block_->instructions_.first_instruction_ = this;
730 }
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000731}
732
733void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
734 // We currently only support graphs with one entry block, one body block, and one exit block.
735 DCHECK_EQ(GetBlocks().Size(), 3u);
736
737 // Walk over the entry block and:
738 // - Move constants from the entry block to the outer_graph's entry block,
739 // - Replace HParameterValue instructions with their real value.
740 // - Remove suspend checks, that hold an environment.
741 int parameter_index = 0;
742 for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
743 HInstruction* current = it.Current();
744 if (current->IsConstant()) {
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000745 current->MoveBefore(outer_graph->GetEntryBlock()->GetLastInstruction());
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000746 } else if (current->IsParameterValue()) {
747 current->ReplaceWith(invoke->InputAt(parameter_index++));
748 } else {
749 DCHECK(current->IsGoto() || current->IsSuspendCheck());
750 entry_block_->RemoveInstruction(current);
751 }
752 }
753
754 // Insert the body's instructions except the last, just after the `invoke`
755 // instruction.
756 HBasicBlock* body = GetBlocks().Get(1);
757 DCHECK(!body->IsExitBlock());
758 HInstruction* last = body->GetLastInstruction();
759 HInstruction* first = body->GetFirstInstruction();
760
761 if (first != last) {
762 HInstruction* antelast = last->GetPrevious();
763
764 // Update the instruction list of the body to only contain the last
765 // instruction.
766 last->previous_ = nullptr;
767 body->instructions_.first_instruction_ = last;
768 body->instructions_.last_instruction_ = last;
769
770 // Update the instruction list of the `invoke`'s block to now contain the
771 // body's instructions.
772 antelast->next_ = invoke->GetNext();
773 antelast->next_->previous_ = antelast;
774 first->previous_ = invoke;
775 invoke->next_ = first;
776
777 // Update the block pointer of all instructions.
778 for (HInstruction* current = antelast; current != invoke; current = current->GetPrevious()) {
779 current->SetBlock(invoke->GetBlock());
780 }
781 }
782
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000783 // Replace the invoke with the return value of the inlined graph.
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000784 if (last->IsReturn()) {
785 invoke->ReplaceWith(last->InputAt(0));
786 body->RemoveInstruction(last);
787 } else {
788 DCHECK(last->IsReturnVoid());
789 }
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000790
791 // Finally remove the invoke from the caller.
792 invoke->GetBlock()->RemoveInstruction(invoke);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000793}
794
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000795} // namespace art