| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_allocator.h" | 5 #include "vm/flow_graph_allocator.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 #include "vm/il_printer.h" | 9 #include "vm/il_printer.h" |
| 10 #include "vm/flow_graph.h" | 10 #include "vm/flow_graph.h" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 return (pos | 1); | 59 return (pos | 1); |
| 60 } | 60 } |
| 61 | 61 |
| 62 | 62 |
| 63 FlowGraphAllocator::FlowGraphAllocator(const FlowGraph& flow_graph) | 63 FlowGraphAllocator::FlowGraphAllocator(const FlowGraph& flow_graph) |
| 64 : flow_graph_(flow_graph), | 64 : flow_graph_(flow_graph), |
| 65 reaching_defs_(flow_graph), | 65 reaching_defs_(flow_graph), |
| 66 value_representations_(flow_graph.max_virtual_register_number()), | 66 value_representations_(flow_graph.max_virtual_register_number()), |
| 67 block_order_(flow_graph.reverse_postorder()), | 67 block_order_(flow_graph.reverse_postorder()), |
| 68 postorder_(flow_graph.postorder()), | 68 postorder_(flow_graph.postorder()), |
| 69 live_out_(block_order_.length()), | 69 liveness_(flow_graph), |
| 70 kill_(block_order_.length()), | |
| 71 live_in_(block_order_.length()), | |
| 72 vreg_count_(flow_graph.max_virtual_register_number()), | 70 vreg_count_(flow_graph.max_virtual_register_number()), |
| 73 live_ranges_(flow_graph.max_virtual_register_number()), | 71 live_ranges_(flow_graph.max_virtual_register_number()), |
| 74 cpu_regs_(), | 72 cpu_regs_(), |
| 75 fpu_regs_(), | 73 fpu_regs_(), |
| 76 blocked_cpu_registers_(), | 74 blocked_cpu_registers_(), |
| 77 blocked_fpu_registers_(), | 75 blocked_fpu_registers_(), |
| 78 cpu_spill_slot_count_(0) { | 76 cpu_spill_slot_count_(0) { |
| 79 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL); | 77 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL); |
| 80 for (intptr_t i = 0; i < vreg_count_; i++) { | 78 for (intptr_t i = 0; i < vreg_count_; i++) { |
| 81 value_representations_.Add(kNoRepresentation); | 79 value_representations_.Add(kNoRepresentation); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 109 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 107 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 110 BlockEntryInstr* block = block_order_[i]; | 108 BlockEntryInstr* block = block_order_[i]; |
| 111 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 109 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 112 Instruction* current = it.Current(); | 110 Instruction* current = it.Current(); |
| 113 if (!current->CanDeoptimize()) current->RemoveEnvironment(); | 111 if (!current->CanDeoptimize()) current->RemoveEnvironment(); |
| 114 } | 112 } |
| 115 } | 113 } |
| 116 } | 114 } |
| 117 | 115 |
| 118 | 116 |
| 119 void FlowGraphAllocator::ComputeInitialSets() { | 117 void SSALivenessAnalysis::ComputeInitialSets() { |
| 120 const intptr_t block_count = postorder_.length(); | 118 const intptr_t block_count = postorder_.length(); |
| 121 for (intptr_t i = 0; i < block_count; i++) { | 119 for (intptr_t i = 0; i < block_count; i++) { |
| 122 BlockEntryInstr* block = postorder_[i]; | 120 BlockEntryInstr* block = postorder_[i]; |
| 123 | 121 |
| 124 BitVector* kill = kill_[i]; | 122 BitVector* kill = kill_[i]; |
| 125 BitVector* live_in = live_in_[i]; | 123 BitVector* live_in = live_in_[i]; |
| 126 | 124 |
| 127 // Iterate backwards starting at the last instruction. | 125 // Iterate backwards starting at the last instruction. |
| 128 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 126 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 129 Instruction* current = it.Current(); | 127 Instruction* current = it.Current(); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 const intptr_t use = val->definition()->ssa_temp_index(); | 180 const intptr_t use = val->definition()->ssa_temp_index(); |
| 183 if (!kill_[pred->postorder_number()]->Contains(use)) { | 181 if (!kill_[pred->postorder_number()]->Contains(use)) { |
| 184 live_in_[pred->postorder_number()]->Add(use); | 182 live_in_[pred->postorder_number()]->Add(use); |
| 185 } | 183 } |
| 186 } | 184 } |
| 187 } | 185 } |
| 188 } | 186 } |
| 189 } | 187 } |
| 190 | 188 |
| 191 // Process initial definitions, ie, constants and incoming parameters. | 189 // Process initial definitions, ie, constants and incoming parameters. |
| 192 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); | 190 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); i++) { |
| 193 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { | 191 intptr_t vreg = (*graph_entry_->initial_definitions())[i]->ssa_temp_index(); |
| 194 intptr_t vreg = (*graph_entry->initial_definitions())[i]->ssa_temp_index(); | 192 kill_[graph_entry_->postorder_number()]->Add(vreg); |
| 195 kill_[graph_entry->postorder_number()]->Add(vreg); | 193 live_in_[graph_entry_->postorder_number()]->Remove(vreg); |
| 196 live_in_[graph_entry->postorder_number()]->Remove(vreg); | |
| 197 } | 194 } |
| 198 | 195 |
| 199 // Update initial live_in sets to match live_out sets. Has to be | 196 // Update initial live_in sets to match live_out sets. Has to be |
| 200 // done in a separate path because of backwards branches. | 197 // done in a separate path because of backwards branches. |
| 201 for (intptr_t i = 0; i < block_count; i++) { | 198 for (intptr_t i = 0; i < block_count; i++) { |
| 202 UpdateLiveIn(*postorder_[i]); | 199 UpdateLiveIn(*postorder_[i]); |
| 203 } | 200 } |
| 204 } | 201 } |
| 205 | 202 |
| 206 | 203 |
| 207 bool FlowGraphAllocator::UpdateLiveOut(const BlockEntryInstr& instr) { | |
| 208 BitVector* live_out = live_out_[instr.postorder_number()]; | |
| 209 bool changed = false; | |
| 210 Instruction* last = instr.last_instruction(); | |
| 211 ASSERT(last != NULL); | |
| 212 for (intptr_t i = 0; i < last->SuccessorCount(); i++) { | |
| 213 BlockEntryInstr* succ = last->SuccessorAt(i); | |
| 214 ASSERT(succ != NULL); | |
| 215 if (live_out->AddAll(live_in_[succ->postorder_number()])) { | |
| 216 changed = true; | |
| 217 } | |
| 218 } | |
| 219 return changed; | |
| 220 } | |
| 221 | |
| 222 | |
| 223 bool FlowGraphAllocator::UpdateLiveIn(const BlockEntryInstr& instr) { | |
| 224 BitVector* live_out = live_out_[instr.postorder_number()]; | |
| 225 BitVector* kill = kill_[instr.postorder_number()]; | |
| 226 BitVector* live_in = live_in_[instr.postorder_number()]; | |
| 227 return live_in->KillAndAdd(kill, live_out); | |
| 228 } | |
| 229 | |
| 230 | |
| 231 void FlowGraphAllocator::ComputeLiveInAndLiveOutSets() { | |
| 232 const intptr_t block_count = postorder_.length(); | |
| 233 bool changed; | |
| 234 do { | |
| 235 changed = false; | |
| 236 | |
| 237 for (intptr_t i = 0; i < block_count; i++) { | |
| 238 const BlockEntryInstr& block = *postorder_[i]; | |
| 239 | |
| 240 // Live-in set depends only on kill set which does not | |
| 241 // change in this loop and live-out set. If live-out | |
| 242 // set does not change there is no need to recompute | |
| 243 // live-in set. | |
| 244 if (UpdateLiveOut(block) && UpdateLiveIn(block)) { | |
| 245 changed = true; | |
| 246 } | |
| 247 } | |
| 248 } while (changed); | |
| 249 } | |
| 250 | |
| 251 | |
| 252 void FlowGraphAllocator::AnalyzeLiveness() { | |
| 253 const intptr_t block_count = postorder_.length(); | |
| 254 for (intptr_t i = 0; i < block_count; i++) { | |
| 255 live_out_.Add(new BitVector(vreg_count_)); | |
| 256 kill_.Add(new BitVector(vreg_count_)); | |
| 257 live_in_.Add(new BitVector(vreg_count_)); | |
| 258 } | |
| 259 | |
| 260 ComputeInitialSets(); | |
| 261 ComputeLiveInAndLiveOutSets(); | |
| 262 } | |
| 263 | |
| 264 | |
| 265 static void PrintBitVector(const char* tag, BitVector* v) { | |
| 266 OS::Print("%s:", tag); | |
| 267 for (BitVector::Iterator it(v); !it.Done(); it.Advance()) { | |
| 268 OS::Print(" %"Pd"", it.Current()); | |
| 269 } | |
| 270 OS::Print("\n"); | |
| 271 } | |
| 272 | |
| 273 | |
| 274 void FlowGraphAllocator::DumpLiveness() { | |
| 275 const intptr_t block_count = postorder_.length(); | |
| 276 for (intptr_t i = 0; i < block_count; i++) { | |
| 277 BlockEntryInstr* block = postorder_[i]; | |
| 278 OS::Print("block @%"Pd" -> ", block->block_id()); | |
| 279 | |
| 280 Instruction* last = block->last_instruction(); | |
| 281 for (intptr_t j = 0; j < last->SuccessorCount(); j++) { | |
| 282 BlockEntryInstr* succ = last->SuccessorAt(j); | |
| 283 OS::Print(" @%"Pd"", succ->block_id()); | |
| 284 } | |
| 285 OS::Print("\n"); | |
| 286 | |
| 287 PrintBitVector(" live out", live_out_[i]); | |
| 288 PrintBitVector(" kill", kill_[i]); | |
| 289 PrintBitVector(" live in", live_in_[i]); | |
| 290 } | |
| 291 } | |
| 292 | |
| 293 | |
| 294 void LiveRange::AddUse(intptr_t pos, Location* location_slot) { | 204 void LiveRange::AddUse(intptr_t pos, Location* location_slot) { |
| 295 ASSERT(location_slot != NULL); | 205 ASSERT(location_slot != NULL); |
| 296 ASSERT((first_use_interval_->start_ <= pos) && | 206 ASSERT((first_use_interval_->start_ <= pos) && |
| 297 (pos <= first_use_interval_->end_)); | 207 (pos <= first_use_interval_->end_)); |
| 298 if ((uses_ != NULL) && | 208 if ((uses_ != NULL) && |
| 299 (uses_->pos() == pos) && | 209 (uses_->pos() == pos) && |
| 300 (uses_->location_slot() == location_slot)) { | 210 (uses_->location_slot() == location_slot)) { |
| 301 return; | 211 return; |
| 302 } | 212 } |
| 303 uses_ = new UsePosition(pos, uses_, location_slot); | 213 uses_ = new UsePosition(pos, uses_, location_slot); |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 515 ASSERT(postorder_.Last()->IsGraphEntry()); | 425 ASSERT(postorder_.Last()->IsGraphEntry()); |
| 516 BitVector* current_interference_set = NULL; | 426 BitVector* current_interference_set = NULL; |
| 517 for (intptr_t i = 0; i < (block_count - 1); i++) { | 427 for (intptr_t i = 0; i < (block_count - 1); i++) { |
| 518 BlockEntryInstr* block = postorder_[i]; | 428 BlockEntryInstr* block = postorder_[i]; |
| 519 | 429 |
| 520 BlockInfo* block_info = BlockInfoAt(block->start_pos()); | 430 BlockInfo* block_info = BlockInfoAt(block->start_pos()); |
| 521 | 431 |
| 522 // For every SSA value that is live out of this block, create an interval | 432 // For every SSA value that is live out of this block, create an interval |
| 523 // that covers the whole block. It will be shortened if we encounter a | 433 // that covers the whole block. It will be shortened if we encounter a |
| 524 // definition of this value in this block. | 434 // definition of this value in this block. |
| 525 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { | 435 for (BitVector::Iterator it(liveness_.GetLiveOutSetAt(i)); |
| 436 !it.Done(); |
| 437 it.Advance()) { |
| 526 LiveRange* range = GetLiveRange(it.Current()); | 438 LiveRange* range = GetLiveRange(it.Current()); |
| 527 range->AddUseInterval(block->start_pos(), block->end_pos()); | 439 range->AddUseInterval(block->start_pos(), block->end_pos()); |
| 528 } | 440 } |
| 529 | 441 |
| 530 BlockInfo* loop_header = block_info->loop_header(); | 442 BlockInfo* loop_header = block_info->loop_header(); |
| 531 if ((loop_header != NULL) && (loop_header->last_block() == block)) { | 443 if ((loop_header != NULL) && (loop_header->last_block() == block)) { |
| 532 current_interference_set = | 444 current_interference_set = |
| 533 new BitVector(flow_graph_.max_virtual_register_number()); | 445 new BitVector(flow_graph_.max_virtual_register_number()); |
| 534 ASSERT(loop_header->backedge_interference() == NULL); | 446 ASSERT(loop_header->backedge_interference() == NULL); |
| 535 loop_header->set_backedge_interference( | 447 loop_header->set_backedge_interference( |
| (...skipping 11 matching lines...) Expand all Loading... |
| 547 if (!current->IsParallelMove()) { | 459 if (!current->IsParallelMove()) { |
| 548 ProcessOneInstruction(block, current, current_interference_set); | 460 ProcessOneInstruction(block, current, current_interference_set); |
| 549 } | 461 } |
| 550 current = current->previous(); | 462 current = current->previous(); |
| 551 } | 463 } |
| 552 | 464 |
| 553 | 465 |
| 554 // Check if any values live into the loop can be spilled for free. | 466 // Check if any values live into the loop can be spilled for free. |
| 555 if (block_info->is_loop_header()) { | 467 if (block_info->is_loop_header()) { |
| 556 current_interference_set = NULL; | 468 current_interference_set = NULL; |
| 557 for (BitVector::Iterator it(live_in_[i]); !it.Done(); it.Advance()) { | 469 for (BitVector::Iterator it(liveness_.GetLiveInSetAt(i)); |
| 470 !it.Done(); |
| 471 it.Advance()) { |
| 558 LiveRange* range = GetLiveRange(it.Current()); | 472 LiveRange* range = GetLiveRange(it.Current()); |
| 559 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { | 473 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { |
| 560 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); | 474 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); |
| 561 } | 475 } |
| 562 } | 476 } |
| 563 } | 477 } |
| 564 | 478 |
| 565 ConnectIncomingPhiMoves(block); | 479 ConnectIncomingPhiMoves(block); |
| 566 } | 480 } |
| 567 | 481 |
| (...skipping 1798 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2366 sibling->assigned_location(), | 2280 sibling->assigned_location(), |
| 2367 range->assigned_location()); | 2281 range->assigned_location()); |
| 2368 } | 2282 } |
| 2369 range = sibling; | 2283 range = sibling; |
| 2370 } | 2284 } |
| 2371 } | 2285 } |
| 2372 | 2286 |
| 2373 // Resolve non-linear control flow across branches. | 2287 // Resolve non-linear control flow across branches. |
| 2374 for (intptr_t i = 1; i < block_order_.length(); i++) { | 2288 for (intptr_t i = 1; i < block_order_.length(); i++) { |
| 2375 BlockEntryInstr* block = block_order_[i]; | 2289 BlockEntryInstr* block = block_order_[i]; |
| 2376 BitVector* live = live_in_[block->postorder_number()]; | 2290 BitVector* live = liveness_.GetLiveInSet(block); |
| 2377 for (BitVector::Iterator it(live); !it.Done(); it.Advance()) { | 2291 for (BitVector::Iterator it(live); !it.Done(); it.Advance()) { |
| 2378 LiveRange* range = GetLiveRange(it.Current()); | 2292 LiveRange* range = GetLiveRange(it.Current()); |
| 2379 for (intptr_t j = 0; j < block->PredecessorCount(); j++) { | 2293 for (intptr_t j = 0; j < block->PredecessorCount(); j++) { |
| 2380 ConnectSplitSiblings(range, block->PredecessorAt(j), block); | 2294 ConnectSplitSiblings(range, block->PredecessorAt(j), block); |
| 2381 } | 2295 } |
| 2382 } | 2296 } |
| 2383 } | 2297 } |
| 2384 | 2298 |
| 2385 // Eagerly spill values. | 2299 // Eagerly spill values. |
| 2386 // TODO(vegorov): if value is spilled on the cold path (e.g. by the call) | 2300 // TODO(vegorov): if value is spilled on the cold path (e.g. by the call) |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2433 } | 2347 } |
| 2434 } | 2348 } |
| 2435 } | 2349 } |
| 2436 | 2350 |
| 2437 | 2351 |
| 2438 void FlowGraphAllocator::AllocateRegisters() { | 2352 void FlowGraphAllocator::AllocateRegisters() { |
| 2439 CollectRepresentations(); | 2353 CollectRepresentations(); |
| 2440 | 2354 |
| 2441 EliminateEnvironments(); | 2355 EliminateEnvironments(); |
| 2442 | 2356 |
| 2443 AnalyzeLiveness(); | 2357 liveness_.Analyze(); |
| 2444 | 2358 |
| 2445 NumberInstructions(); | 2359 NumberInstructions(); |
| 2446 | 2360 |
| 2447 DiscoverLoops(); | 2361 DiscoverLoops(); |
| 2448 | 2362 |
| 2449 BuildLiveRanges(); | 2363 BuildLiveRanges(); |
| 2450 | 2364 |
| 2451 if (FLAG_print_ssa_liveness) { | 2365 if (FLAG_print_ssa_liveness) { |
| 2452 DumpLiveness(); | 2366 liveness_.Dump(); |
| 2453 } | 2367 } |
| 2454 | 2368 |
| 2455 if (FLAG_print_ssa_liveranges) { | 2369 if (FLAG_print_ssa_liveranges) { |
| 2456 const Function& function = flow_graph_.parsed_function().function(); | 2370 const Function& function = flow_graph_.parsed_function().function(); |
| 2457 | 2371 |
| 2458 OS::Print("-- [before ssa allocator] ranges [%s] ---------\n", | 2372 OS::Print("-- [before ssa allocator] ranges [%s] ---------\n", |
| 2459 function.ToFullyQualifiedCString()); | 2373 function.ToFullyQualifiedCString()); |
| 2460 PrintLiveRanges(); | 2374 PrintLiveRanges(); |
| 2461 OS::Print("----------------------------------------------\n"); | 2375 OS::Print("----------------------------------------------\n"); |
| 2462 | 2376 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2503 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2417 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2504 function.ToFullyQualifiedCString()); | 2418 function.ToFullyQualifiedCString()); |
| 2505 FlowGraphPrinter printer(flow_graph_, true); | 2419 FlowGraphPrinter printer(flow_graph_, true); |
| 2506 printer.PrintBlocks(); | 2420 printer.PrintBlocks(); |
| 2507 OS::Print("----------------------------------------------\n"); | 2421 OS::Print("----------------------------------------------\n"); |
| 2508 } | 2422 } |
| 2509 } | 2423 } |
| 2510 | 2424 |
| 2511 | 2425 |
| 2512 } // namespace dart | 2426 } // namespace dart |
| OLD | NEW |