| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); | 357 GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); |
| 358 if (flags.Contains(changes_flag)) { | 358 if (flags.Contains(changes_flag)) { |
| 359 if (data_[i] == NULL) count_++; | 359 if (data_[i] == NULL) count_++; |
| 360 data_[i] = instr; | 360 data_[i] = instr; |
| 361 } | 361 } |
| 362 } | 362 } |
| 363 } | 363 } |
| 364 | 364 |
| 365 | 365 |
| 366 HGlobalValueNumberingPhase::HGlobalValueNumberingPhase(HGraph* graph) | 366 HGlobalValueNumberingPhase::HGlobalValueNumberingPhase(HGraph* graph) |
| 367 : HPhase("H_Global value numbering", graph), | 367 : HPhase("H_Global value numbering", graph), |
| 368 removed_side_effects_(false), | 368 removed_side_effects_(false), |
| 369 block_side_effects_(graph->blocks()->length(), zone()), | 369 block_side_effects_(graph->blocks()->length(), zone()), |
| 370 loop_side_effects_(graph->blocks()->length(), zone()), | 370 loop_side_effects_(graph->blocks()->length(), zone()), |
| 371 visited_on_paths_(graph->blocks()->length(), zone()) { | 371 visited_on_paths_(graph->blocks()->length(), zone()) { |
| 372 ASSERT(!AllowHandleAllocation::IsAllowed()); | 372 ASSERT(!AllowHandleAllocation::IsAllowed()); |
| 373 block_side_effects_.AddBlock(GVNFlagSet(), graph->blocks()->length(), | 373 block_side_effects_.AddBlock(GVNFlagSet(), graph->blocks()->length(), |
| 374 zone()); | |
| 375 loop_side_effects_.AddBlock(GVNFlagSet(), graph->blocks()->length(), | |
| 376 zone()); | 374 zone()); |
| 375 loop_side_effects_.AddBlock(GVNFlagSet(), graph->blocks()->length(), |
| 376 zone()); |
| 377 } |
| 378 |
| 379 |
| 380 void HGlobalValueNumberingPhase::Run() { |
| 381 ASSERT(!removed_side_effects_); |
| 382 for (int i = FLAG_gvn_iterations; i > 0; --i) { |
| 383 // Compute the side effects. |
| 384 ComputeBlockSideEffects(); |
| 385 |
| 386 // Perform loop invariant code motion if requested. |
| 387 if (FLAG_loop_invariant_code_motion) LoopInvariantCodeMotion(); |
| 388 |
| 389 // Perform the actual value numbering. |
| 390 AnalyzeGraph(); |
| 391 |
| 392 // Continue GVN if we removed any side effects. |
| 393 if (!removed_side_effects_) break; |
| 394 removed_side_effects_ = false; |
| 395 |
| 396 // Clear all side effects. |
| 397 ASSERT_EQ(block_side_effects_.length(), graph()->blocks()->length()); |
| 398 ASSERT_EQ(loop_side_effects_.length(), graph()->blocks()->length()); |
| 399 for (int i = 0; i < graph()->blocks()->length(); ++i) { |
| 400 block_side_effects_[i].RemoveAll(); |
| 401 loop_side_effects_[i].RemoveAll(); |
| 402 } |
| 403 visited_on_paths_.Clear(); |
| 377 } | 404 } |
| 378 | |
| 379 void HGlobalValueNumberingPhase::Analyze() { | |
| 380 removed_side_effects_ = false; | |
| 381 ComputeBlockSideEffects(); | |
| 382 if (FLAG_loop_invariant_code_motion) { | |
| 383 LoopInvariantCodeMotion(); | |
| 384 } | |
| 385 AnalyzeGraph(); | |
| 386 } | 405 } |
| 387 | 406 |
| 388 | 407 |
| 389 void HGlobalValueNumberingPhase::ComputeBlockSideEffects() { | 408 void HGlobalValueNumberingPhase::ComputeBlockSideEffects() { |
| 390 // The Analyze phase of GVN can be called multiple times. Clear loop side | |
| 391 // effects before computing them to erase the contents from previous Analyze | |
| 392 // passes. | |
| 393 for (int i = 0; i < loop_side_effects_.length(); ++i) { | |
| 394 loop_side_effects_[i].RemoveAll(); | |
| 395 } | |
| 396 for (int i = graph()->blocks()->length() - 1; i >= 0; --i) { | 409 for (int i = graph()->blocks()->length() - 1; i >= 0; --i) { |
| 397 // Compute side effects for the block. | 410 // Compute side effects for the block. |
| 398 HBasicBlock* block = graph()->blocks()->at(i); | 411 HBasicBlock* block = graph()->blocks()->at(i); |
| 399 GVNFlagSet side_effects; | 412 GVNFlagSet side_effects; |
| 400 if (block->IsReachable() && !block->IsDeoptimizing()) { | 413 if (block->IsReachable() && !block->IsDeoptimizing()) { |
| 401 int id = block->block_id(); | 414 int id = block->block_id(); |
| 402 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | 415 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 403 HInstruction* instr = it.Current(); | 416 HInstruction* instr = it.Current(); |
| 404 side_effects.Add(instr->ChangesFlags()); | 417 side_effects.Add(instr->ChangesFlags()); |
| 405 } | 418 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 419 loop_side_effects_[parent_block->block_id()].Add(side_effects); | 432 loop_side_effects_[parent_block->block_id()].Add(side_effects); |
| 420 with_parent = parent_block; | 433 with_parent = parent_block; |
| 421 } while (with_parent->HasParentLoopHeader()); | 434 } while (with_parent->HasParentLoopHeader()); |
| 422 } | 435 } |
| 423 } | 436 } |
| 424 } | 437 } |
| 425 } | 438 } |
| 426 | 439 |
| 427 | 440 |
| 428 SmartArrayPointer<char> GetGVNFlagsString(GVNFlagSet flags) { | 441 SmartArrayPointer<char> GetGVNFlagsString(GVNFlagSet flags) { |
| 429 char underlying_buffer[kLastFlag * 128]; | 442 char underlying_buffer[kNumberOfFlags * 128]; |
| 430 Vector<char> buffer(underlying_buffer, sizeof(underlying_buffer)); | 443 Vector<char> buffer(underlying_buffer, sizeof(underlying_buffer)); |
| 431 #if DEBUG | 444 #if DEBUG |
| 432 int offset = 0; | 445 int offset = 0; |
| 433 const char* separator = ""; | 446 const char* separator = ""; |
| 434 const char* comma = ", "; | 447 const char* comma = ", "; |
| 435 buffer[0] = 0; | 448 buffer[0] = 0; |
| 436 uint32_t set_depends_on = 0; | 449 uint32_t set_depends_on = 0; |
| 437 uint32_t set_changes = 0; | 450 uint32_t set_changes = 0; |
| 438 for (int bit = 0; bit < kLastFlag; ++bit) { | 451 for (int bit = 0; bit < kNumberOfFlags; ++bit) { |
| 439 if (flags.Contains(static_cast<GVNFlag>(bit))) { | 452 if (flags.Contains(static_cast<GVNFlag>(bit))) { |
| 440 if (bit % 2 == 0) { | 453 if (bit % 2 == 0) { |
| 441 set_changes++; | 454 set_changes++; |
| 442 } else { | 455 } else { |
| 443 set_depends_on++; | 456 set_depends_on++; |
| 444 } | 457 } |
| 445 } | 458 } |
| 446 } | 459 } |
| 447 bool positive_changes = set_changes < (kLastFlag / 2); | 460 bool positive_changes = set_changes < (kNumberOfFlags / 2); |
| 448 bool positive_depends_on = set_depends_on < (kLastFlag / 2); | 461 bool positive_depends_on = set_depends_on < (kNumberOfFlags / 2); |
| 449 if (set_changes > 0) { | 462 if (set_changes > 0) { |
| 450 if (positive_changes) { | 463 if (positive_changes) { |
| 451 offset += OS::SNPrintF(buffer + offset, "changes ["); | 464 offset += OS::SNPrintF(buffer + offset, "changes ["); |
| 452 } else { | 465 } else { |
| 453 offset += OS::SNPrintF(buffer + offset, "changes all except ["); | 466 offset += OS::SNPrintF(buffer + offset, "changes all except ["); |
| 454 } | 467 } |
| 455 for (int bit = 0; bit < kLastFlag; ++bit) { | 468 for (int bit = 0; bit < kNumberOfFlags; ++bit) { |
| 456 if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_changes) { | 469 if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_changes) { |
| 457 switch (static_cast<GVNFlag>(bit)) { | 470 switch (static_cast<GVNFlag>(bit)) { |
| 458 #define DECLARE_FLAG(type) \ | 471 #define DECLARE_FLAG(type) \ |
| 459 case kChanges##type: \ | 472 case kChanges##type: \ |
| 460 offset += OS::SNPrintF(buffer + offset, separator); \ | 473 offset += OS::SNPrintF(buffer + offset, separator); \ |
| 461 offset += OS::SNPrintF(buffer + offset, #type); \ | 474 offset += OS::SNPrintF(buffer + offset, #type); \ |
| 462 separator = comma; \ | 475 separator = comma; \ |
| 463 break; | 476 break; |
| 464 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) | 477 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) |
| 465 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) | 478 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) |
| 466 #undef DECLARE_FLAG | 479 #undef DECLARE_FLAG |
| 467 default: | 480 default: |
| 468 break; | 481 break; |
| 469 } | 482 } |
| 470 } | 483 } |
| 471 } | 484 } |
| 472 offset += OS::SNPrintF(buffer + offset, "]"); | 485 offset += OS::SNPrintF(buffer + offset, "]"); |
| 473 } | 486 } |
| 474 if (set_depends_on > 0) { | 487 if (set_depends_on > 0) { |
| 475 separator = ""; | 488 separator = ""; |
| 476 if (set_changes > 0) { | 489 if (set_changes > 0) { |
| 477 offset += OS::SNPrintF(buffer + offset, ", "); | 490 offset += OS::SNPrintF(buffer + offset, ", "); |
| 478 } | 491 } |
| 479 if (positive_depends_on) { | 492 if (positive_depends_on) { |
| 480 offset += OS::SNPrintF(buffer + offset, "depends on ["); | 493 offset += OS::SNPrintF(buffer + offset, "depends on ["); |
| 481 } else { | 494 } else { |
| 482 offset += OS::SNPrintF(buffer + offset, "depends on all except ["); | 495 offset += OS::SNPrintF(buffer + offset, "depends on all except ["); |
| 483 } | 496 } |
| 484 for (int bit = 0; bit < kLastFlag; ++bit) { | 497 for (int bit = 0; bit < kNumberOfFlags; ++bit) { |
| 485 if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_depends_on) { | 498 if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_depends_on) { |
| 486 switch (static_cast<GVNFlag>(bit)) { | 499 switch (static_cast<GVNFlag>(bit)) { |
| 487 #define DECLARE_FLAG(type) \ | 500 #define DECLARE_FLAG(type) \ |
| 488 case kDependsOn##type: \ | 501 case kDependsOn##type: \ |
| 489 offset += OS::SNPrintF(buffer + offset, separator); \ | 502 offset += OS::SNPrintF(buffer + offset, separator); \ |
| 490 offset += OS::SNPrintF(buffer + offset, #type); \ | 503 offset += OS::SNPrintF(buffer + offset, #type); \ |
| 491 separator = comma; \ | 504 separator = comma; \ |
| 492 break; | 505 break; |
| 493 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) | 506 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) |
| 494 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) | 507 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 515 TRACE_GVN_1("Using optimistic loop invariant code motion: %s\n", | 528 TRACE_GVN_1("Using optimistic loop invariant code motion: %s\n", |
| 516 graph()->use_optimistic_licm() ? "yes" : "no"); | 529 graph()->use_optimistic_licm() ? "yes" : "no"); |
| 517 for (int i = graph()->blocks()->length() - 1; i >= 0; --i) { | 530 for (int i = graph()->blocks()->length() - 1; i >= 0; --i) { |
| 518 HBasicBlock* block = graph()->blocks()->at(i); | 531 HBasicBlock* block = graph()->blocks()->at(i); |
| 519 if (block->IsLoopHeader()) { | 532 if (block->IsLoopHeader()) { |
| 520 GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; | 533 GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; |
| 521 TRACE_GVN_2("Try loop invariant motion for block B%d %s\n", | 534 TRACE_GVN_2("Try loop invariant motion for block B%d %s\n", |
| 522 block->block_id(), | 535 block->block_id(), |
| 523 GetGVNFlagsString(side_effects).get()); | 536 GetGVNFlagsString(side_effects).get()); |
| 524 | 537 |
| 525 GVNFlagSet accumulated_first_time_depends; | |
| 526 GVNFlagSet accumulated_first_time_changes; | |
| 527 HBasicBlock* last = block->loop_information()->GetLastBackEdge(); | 538 HBasicBlock* last = block->loop_information()->GetLastBackEdge(); |
| 528 for (int j = block->block_id(); j <= last->block_id(); ++j) { | 539 for (int j = block->block_id(); j <= last->block_id(); ++j) { |
| 529 ProcessLoopBlock(graph()->blocks()->at(j), block, side_effects, | 540 ProcessLoopBlock(graph()->blocks()->at(j), block, side_effects); |
| 530 &accumulated_first_time_depends, | |
| 531 &accumulated_first_time_changes); | |
| 532 } | 541 } |
| 533 } | 542 } |
| 534 } | 543 } |
| 535 } | 544 } |
| 536 | 545 |
| 537 | 546 |
| 538 void HGlobalValueNumberingPhase::ProcessLoopBlock( | 547 void HGlobalValueNumberingPhase::ProcessLoopBlock( |
| 539 HBasicBlock* block, | 548 HBasicBlock* block, |
| 540 HBasicBlock* loop_header, | 549 HBasicBlock* loop_header, |
| 541 GVNFlagSet loop_kills, | 550 GVNFlagSet loop_kills) { |
| 542 GVNFlagSet* first_time_depends, | |
| 543 GVNFlagSet* first_time_changes) { | |
| 544 HBasicBlock* pre_header = loop_header->predecessors()->at(0); | 551 HBasicBlock* pre_header = loop_header->predecessors()->at(0); |
| 545 GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); | 552 GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); |
| 546 TRACE_GVN_2("Loop invariant motion for B%d %s\n", | 553 TRACE_GVN_2("Loop invariant motion for B%d %s\n", |
| 547 block->block_id(), | 554 block->block_id(), |
| 548 GetGVNFlagsString(depends_flags).get()); | 555 GetGVNFlagsString(depends_flags).get()); |
| 549 HInstruction* instr = block->first(); | 556 HInstruction* instr = block->first(); |
| 550 while (instr != NULL) { | 557 while (instr != NULL) { |
| 551 HInstruction* next = instr->next(); | 558 HInstruction* next = instr->next(); |
| 552 bool hoisted = false; | |
| 553 if (instr->CheckFlag(HValue::kUseGVN)) { | 559 if (instr->CheckFlag(HValue::kUseGVN)) { |
| 554 TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n", | 560 TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n", |
| 555 instr->id(), | 561 instr->id(), |
| 556 instr->Mnemonic(), | 562 instr->Mnemonic(), |
| 557 GetGVNFlagsString(instr->gvn_flags()).get(), | 563 GetGVNFlagsString(instr->gvn_flags()).get(), |
| 558 GetGVNFlagsString(loop_kills).get()); | 564 GetGVNFlagsString(loop_kills).get()); |
| 559 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); | 565 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); |
| 560 if (can_hoist && !graph()->use_optimistic_licm()) { | 566 if (can_hoist && !graph()->use_optimistic_licm()) { |
| 561 can_hoist = block->IsLoopSuccessorDominator(); | 567 can_hoist = block->IsLoopSuccessorDominator(); |
| 562 } | 568 } |
| 563 | 569 |
| 564 if (can_hoist) { | 570 if (can_hoist) { |
| 565 bool inputs_loop_invariant = true; | 571 bool inputs_loop_invariant = true; |
| 566 for (int i = 0; i < instr->OperandCount(); ++i) { | 572 for (int i = 0; i < instr->OperandCount(); ++i) { |
| 567 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) { | 573 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) { |
| 568 inputs_loop_invariant = false; | 574 inputs_loop_invariant = false; |
| 569 } | 575 } |
| 570 } | 576 } |
| 571 | 577 |
| 572 if (inputs_loop_invariant && ShouldMove(instr, loop_header)) { | 578 if (inputs_loop_invariant && ShouldMove(instr, loop_header)) { |
| 573 TRACE_GVN_2("Hoisting loop invariant instruction i%d to block B%d\n", | 579 TRACE_GVN_2("Hoisting loop invariant instruction i%d to block B%d\n", |
| 574 instr->id(), pre_header->block_id()); | 580 instr->id(), pre_header->block_id()); |
| 575 // Move the instruction out of the loop. | 581 // Move the instruction out of the loop. |
| 576 instr->Unlink(); | 582 instr->Unlink(); |
| 577 instr->InsertBefore(pre_header->end()); | 583 instr->InsertBefore(pre_header->end()); |
| 578 if (instr->HasSideEffects()) removed_side_effects_ = true; | 584 if (instr->HasSideEffects()) removed_side_effects_ = true; |
| 579 hoisted = true; | |
| 580 } | 585 } |
| 581 } | 586 } |
| 582 } | 587 } |
| 583 if (!hoisted) { | |
| 584 // If an instruction is not hoisted, we have to account for its side | |
| 585 // effects when hoisting later HTransitionElementsKind instructions. | |
| 586 GVNFlagSet previous_depends = *first_time_depends; | |
| 587 GVNFlagSet previous_changes = *first_time_changes; | |
| 588 first_time_depends->Add(instr->DependsOnFlags()); | |
| 589 first_time_changes->Add(instr->ChangesFlags()); | |
| 590 if (!(previous_depends == *first_time_depends)) { | |
| 591 TRACE_GVN_1("Updated first-time accumulated %s\n", | |
| 592 GetGVNFlagsString(*first_time_depends).get()); | |
| 593 } | |
| 594 if (!(previous_changes == *first_time_changes)) { | |
| 595 TRACE_GVN_1("Updated first-time accumulated %s\n", | |
| 596 GetGVNFlagsString(*first_time_changes).get()); | |
| 597 } | |
| 598 } | |
| 599 instr = next; | 588 instr = next; |
| 600 } | 589 } |
| 601 } | 590 } |
| 602 | 591 |
| 603 | 592 |
| 604 bool HGlobalValueNumberingPhase::AllowCodeMotion() { | 593 bool HGlobalValueNumberingPhase::AllowCodeMotion() { |
| 605 return info()->IsStub() || info()->opt_count() + 1 < FLAG_max_opt_count; | 594 return info()->IsStub() || info()->opt_count() + 1 < FLAG_max_opt_count; |
| 606 } | 595 } |
| 607 | 596 |
| 608 | 597 |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 784 GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); | 773 GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); |
| 785 GVNFlag depends_on_flag = HValue::DependsOnFlagFromInt(i); | 774 GVNFlag depends_on_flag = HValue::DependsOnFlagFromInt(i); |
| 786 if (instr->DependsOnFlags().Contains(depends_on_flag) && | 775 if (instr->DependsOnFlags().Contains(depends_on_flag) && |
| 787 (other != NULL)) { | 776 (other != NULL)) { |
| 788 TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n", | 777 TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n", |
| 789 i, | 778 i, |
| 790 instr->id(), | 779 instr->id(), |
| 791 instr->Mnemonic(), | 780 instr->Mnemonic(), |
| 792 other->id(), | 781 other->id(), |
| 793 other->Mnemonic()); | 782 other->Mnemonic()); |
| 794 instr->HandleSideEffectDominator(changes_flag, other); | 783 if (instr->HandleSideEffectDominator(changes_flag, other)) { |
| 784 removed_side_effects_ = true; |
| 785 } |
| 795 } | 786 } |
| 796 } | 787 } |
| 797 } | 788 } |
| 798 // Instruction was unlinked during graph traversal. | 789 // Instruction was unlinked during graph traversal. |
| 799 if (!instr->IsLinked()) continue; | 790 if (!instr->IsLinked()) continue; |
| 800 | 791 |
| 801 GVNFlagSet flags = instr->ChangesFlags(); | 792 GVNFlagSet flags = instr->ChangesFlags(); |
| 802 if (!flags.IsEmpty()) { | 793 if (!flags.IsEmpty()) { |
| 803 // Clear all instructions in the map that are affected by side effects. | 794 // Clear all instructions in the map that are affected by side effects. |
| 804 // Store instruction as the dominating one for tracked side effects. | 795 // Store instruction as the dominating one for tracked side effects. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 dominated); | 839 dominated); |
| 849 successor_map->Kill(side_effects_on_all_paths); | 840 successor_map->Kill(side_effects_on_all_paths); |
| 850 successor_dominators->Kill(side_effects_on_all_paths); | 841 successor_dominators->Kill(side_effects_on_all_paths); |
| 851 } | 842 } |
| 852 } | 843 } |
| 853 current = next; | 844 current = next; |
| 854 } | 845 } |
| 855 } | 846 } |
| 856 | 847 |
| 857 } } // namespace v8::internal | 848 } } // namespace v8::internal |
| OLD | NEW |