Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 2543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2554 if (FLAG_use_range) { | 2554 if (FLAG_use_range) { |
| 2555 HRangeAnalysis rangeAnalysis(graph()); | 2555 HRangeAnalysis rangeAnalysis(graph()); |
| 2556 rangeAnalysis.Analyze(); | 2556 rangeAnalysis.Analyze(); |
| 2557 } | 2557 } |
| 2558 graph()->ComputeMinusZeroChecks(); | 2558 graph()->ComputeMinusZeroChecks(); |
| 2559 | 2559 |
| 2560 // Eliminate redundant stack checks on backwards branches. | 2560 // Eliminate redundant stack checks on backwards branches. |
| 2561 HStackCheckEliminator sce(graph()); | 2561 HStackCheckEliminator sce(graph()); |
| 2562 sce.Process(); | 2562 sce.Process(); |
| 2563 | 2563 |
| 2564 graph()->EliminateRedundantChecks(); | |
| 2565 | |
| 2564 // Replace the results of check instructions with the original value, if the | 2566 // Replace the results of check instructions with the original value, if the |
| 2565 // result is used. This is safe now, since we don't do code motion after this | 2567 // result is used. This is safe now, since we don't do code motion after this |
| 2566 // point. It enables better register allocation since the value produced by | 2568 // point. It enables better register allocation since the value produced by |
| 2567 // check instructions is really a copy of the original value. | 2569 // check instructions is really a copy of the original value. |
| 2568 graph()->ReplaceCheckedValues(); | 2570 graph()->ReplaceCheckedValues(); |
| 2569 | 2571 |
| 2570 return graph(); | 2572 return graph(); |
| 2571 } | 2573 } |
| 2572 | 2574 |
| 2575 // We try to "factor up" HBoundsCheck instructions towards the root of the | |
| 2576 // dominator tree. | |
| 2577 // For now we handle checks where the index is like "exp + int32value". | |
| 2578 // If in the DT we check "exp + v1" and later (dominated) "exp + v2", if | |
| 2579 // v2 <= v1 we can safely remove the second check, and if v2 > v1 we can | |
| 2580 // use v2 in the 1st check and again remove the second. | |
| 2581 // To do so we keep a dictionary of all checks where the key if the pair | |
| 2582 // "exp, length". | |
| 2583 // The class BoundsCheckKey represents this key. | |
| 2584 class BoundsCheckKey : public ZoneObject { | |
| 2585 public: | |
| 2586 HValue* IndexBase() const {return index_base_;} | |
| 2587 HValue* Length() const {return length_;} | |
| 2588 | |
| 2589 intptr_t Hash() { | |
| 2590 return index_base_->Hashcode() ^ length_->Hashcode(); | |
| 2591 } | |
| 2592 | |
| 2593 static BoundsCheckKey* CreateBoundsCheckKey(Zone* zone, | |
|
Sven Panne
2012/04/12 09:45:42
To quote memegen: Just drop the "BoundsCheckKey" p
Massi
2012/04/13 10:55:16
Done.
| |
| 2594 HBoundsCheck* check, | |
| 2595 int32_t* offset) { | |
| 2596 HValue* index_base; | |
| 2597 if (check->index()->IsAdd()) { | |
|
Sven Panne
2012/04/12 09:45:42
It might be worthwhile to reduce the redundancy an
Massi
2012/04/13 10:55:16
Done.
| |
| 2598 HAdd* index = HAdd::cast(check->index()); | |
| 2599 if (index->left()->IsConstant()) { | |
| 2600 HConstant* constant = HConstant::cast(index->left()); | |
| 2601 if (constant->HasInteger32Value()) { | |
| 2602 *offset = constant->Integer32Value(); | |
| 2603 index_base = index->right(); | |
| 2604 } else { | |
| 2605 *offset = 0; | |
| 2606 index_base = index; | |
| 2607 } | |
| 2608 } else if (index->right()->IsConstant()) { | |
| 2609 HConstant* constant = HConstant::cast(index->right()); | |
| 2610 if (constant->HasInteger32Value()) { | |
| 2611 *offset = constant->Integer32Value(); | |
| 2612 index_base = index->left(); | |
| 2613 } else { | |
| 2614 *offset = 0; | |
| 2615 index_base = index; | |
| 2616 } | |
| 2617 } else { | |
| 2618 *offset = 0; | |
| 2619 index_base = check->index(); | |
| 2620 } | |
| 2621 } else { | |
| 2622 *offset = 0; | |
| 2623 index_base = check->index(); | |
| 2624 } | |
| 2625 return new(zone) BoundsCheckKey(index_base, check->length()); | |
| 2626 } | |
| 2627 | |
| 2628 private: | |
| 2629 BoundsCheckKey(HValue* index_base, HValue* length) { | |
| 2630 index_base_ = index_base; | |
| 2631 length_ = length; | |
| 2632 } | |
| 2633 | |
| 2634 HValue* index_base_; | |
| 2635 HValue* length_; | |
| 2636 }; | |
| 2637 | |
| 2638 // Data for each BB about HBoundsCheck that can be eliminated or moved. | |
| 2639 class BoundsCheckBbData: public ZoneObject { | |
| 2640 // class BoundsCheckBbData { | |
| 2641 public: | |
| 2642 BoundsCheckKey* Key() {return key_;} | |
| 2643 int32_t Offset() {return offset_;} | |
| 2644 HBasicBlock* BasicBlock() {return bb_;} | |
| 2645 HBoundsCheck* Check() {return check_;} | |
| 2646 BoundsCheckBbData* NextInBb() {return next_in_bb_;} | |
| 2647 BoundsCheckBbData* FatherInDt() {return father_in_dt_;} | |
| 2648 | |
| 2649 static void RemoveCheck(HBoundsCheck* check) { | |
| 2650 HValue* index = check->index(); | |
| 2651 check->DeleteAndReplaceWith(NULL); | |
| 2652 if (index->UseCount() == 0) { | |
| 2653 index->DeleteAndReplaceWith(NULL); | |
| 2654 } | |
| 2655 } | |
| 2656 | |
| 2657 void ReplaceCheck(HBoundsCheck* new_check, int32_t new_offset) { | |
| 2658 // FIXME: can it be something else? | |
| 2659 if (new_check->index()->IsInstruction()) { | |
| 2660 HInstruction* new_index = HInstruction::cast(new_check->index()); | |
| 2661 new_index->Unlink(); | |
| 2662 new_check->Unlink(); | |
| 2663 new_index->InsertAfter(check_); | |
| 2664 new_check->InsertAfter(new_index); | |
| 2665 | |
| 2666 RemoveCheck(check_); | |
| 2667 | |
| 2668 check_ = new_check; | |
| 2669 offset_ = new_offset; | |
| 2670 } | |
| 2671 } | |
| 2672 | |
| 2673 BoundsCheckBbData(BoundsCheckKey* key, int32_t offset, HBasicBlock* bb, | |
| 2674 HBoundsCheck* check, BoundsCheckBbData* next_in_bb, | |
| 2675 BoundsCheckBbData* father_in_dt) { | |
| 2676 key_ = key; | |
| 2677 offset_ = offset; | |
| 2678 bb_ = bb; | |
| 2679 check_ = check; | |
| 2680 next_in_bb_ = next_in_bb; | |
| 2681 father_in_dt_ = father_in_dt; | |
| 2682 } | |
| 2683 | |
| 2684 private: | |
| 2685 BoundsCheckKey* key_; | |
| 2686 int32_t offset_; | |
| 2687 HBasicBlock* bb_; | |
| 2688 HBoundsCheck* check_; | |
| 2689 BoundsCheckBbData* next_in_bb_; | |
| 2690 BoundsCheckBbData* father_in_dt_; | |
|
Sven Panne
2012/04/12 09:45:42
I think using "bb" and "dt" is a little bit crypti
Massi
2012/04/13 10:55:16
Done.
| |
| 2691 }; | |
| 2692 | |
| 2693 bool BoundsCheckKeyMatch(void* key1, void* key2) { | |
|
Sven Panne
2012/04/12 09:45:42
This should probably be "static".
Massi
2012/04/13 10:55:16
Done.
| |
| 2694 BoundsCheckKey* k1 = static_cast<BoundsCheckKey*>(key1); | |
| 2695 BoundsCheckKey* k2 = static_cast<BoundsCheckKey*>(key2); | |
| 2696 return k1->IndexBase() == k2->IndexBase() && k1->Length() == k2->Length(); | |
| 2697 } | |
| 2698 | |
| 2699 class BoundsCheckTable BASE_EMBEDDED { | |
| 2700 public: | |
| 2701 void EliminateRedundantChecks(HBasicBlock* bb) { | |
|
Sven Panne
2012/04/12 09:45:42
I don't think this function really belongs into th
Massi
2012/04/13 10:55:16
Done.
| |
| 2702 BoundsCheckBbData* bb_data_list = NULL; | |
| 2703 | |
| 2704 for (HInstruction* i = bb->first(); i != NULL; i = i->next()) { | |
|
Sven Panne
2012/04/12 09:45:42
Perhaps the first loop can be extracted into a sep
Massi
2012/04/13 10:55:16
Done.
| |
| 2705 if (i->IsBoundsCheck()) { | |
| 2706 HBoundsCheck* check = HBoundsCheck::cast(i); | |
| 2707 int32_t offset; | |
| 2708 // TODO(mmassi): allocate key only when we create a new table entry... | |
| 2709 BoundsCheckKey* key = | |
| 2710 BoundsCheckKey::CreateBoundsCheckKey(bb->zone(), check, &offset); | |
| 2711 | |
| 2712 BoundsCheckBbData** data_p = LookupOrInsert(key); | |
| 2713 BoundsCheckBbData* data = *data_p; | |
| 2714 if (data == NULL) { | |
| 2715 bb_data_list = new(bb->zone()) BoundsCheckBbData(key, | |
| 2716 offset, | |
| 2717 bb, | |
| 2718 check, | |
| 2719 bb_data_list, | |
| 2720 NULL); | |
| 2721 } else if (offset <= data->Offset()) { | |
| 2722 BoundsCheckBbData::RemoveCheck(check); | |
| 2723 } else if (data->BasicBlock() == bb) { | |
| 2724 data->ReplaceCheck(check, offset); | |
| 2725 } else { | |
| 2726 bb_data_list = new(bb->zone()) BoundsCheckBbData(key, | |
| 2727 offset, | |
| 2728 bb, | |
| 2729 check, | |
| 2730 bb_data_list, | |
| 2731 data); | |
| 2732 } | |
| 2733 } | |
| 2734 } | |
| 2735 | |
| 2736 for (int i = 0; i < bb->dominated_blocks()->length(); ++i) { | |
| 2737 EliminateRedundantChecks(bb->dominated_blocks()->at(i)); | |
| 2738 } | |
| 2739 | |
| 2740 for (BoundsCheckBbData* data = bb_data_list; | |
| 2741 data != NULL; | |
| 2742 data = data->NextInBb()) { | |
| 2743 if (data->FatherInDt()) { | |
| 2744 Insert(data->Key(), data->FatherInDt()); | |
| 2745 } else { | |
| 2746 Remove(data->Key()); | |
| 2747 } | |
| 2748 } | |
| 2749 } | |
| 2750 | |
| 2751 BoundsCheckBbData* Lookup(BoundsCheckKey* key) { | |
| 2752 intptr_t hash = key->Hash(); | |
| 2753 ZoneHashMap::Entry* entry = map->Lookup(key, hash, false); | |
| 2754 return entry ? static_cast<BoundsCheckBbData*>(entry->value) : NULL; | |
| 2755 } | |
| 2756 | |
| 2757 BoundsCheckBbData** LookupOrInsert(BoundsCheckKey* key) { | |
| 2758 intptr_t hash = key->Hash(); | |
| 2759 ZoneHashMap::Entry* entry = map->Lookup(key, hash, true); | |
| 2760 return reinterpret_cast<BoundsCheckBbData**>(&(entry->value)); | |
| 2761 } | |
| 2762 | |
| 2763 void Insert(BoundsCheckKey* key, BoundsCheckBbData* data) { | |
| 2764 intptr_t hash = key->Hash(); | |
| 2765 ZoneHashMap::Entry* entry = map->Lookup(key, hash, true); | |
| 2766 entry->value = data; | |
| 2767 } | |
| 2768 | |
| 2769 void Remove(BoundsCheckKey* key) { | |
| 2770 intptr_t hash = key->Hash(); | |
| 2771 map->Remove(key, hash); | |
| 2772 } | |
| 2773 | |
| 2774 BoundsCheckTable() { | |
| 2775 map = new ZoneHashMap(BoundsCheckKeyMatch); | |
|
Sven Panne
2012/04/12 09:45:42
Using an initializer is a nicer and more standard
Massi
2012/04/13 10:55:16
Done.
| |
| 2776 } | |
| 2777 | |
| 2778 private: | |
| 2779 ZoneHashMap *map; | |
| 2780 }; | |
| 2781 | |
| 2782 void HGraph::EliminateRedundantChecks() { | |
| 2783 HPhase phase("H_Eliminate redundant checks", this); | |
| 2784 | |
| 2785 AssertNoAllocation no_gc; | |
| 2786 BoundsCheckTable checks_table; | |
| 2787 checks_table.EliminateRedundantChecks(entry_block()); | |
| 2788 } | |
| 2573 | 2789 |
| 2574 void HGraph::ReplaceCheckedValues() { | 2790 void HGraph::ReplaceCheckedValues() { |
| 2575 HPhase phase("H_Replace checked values", this); | 2791 HPhase phase("H_Replace checked values", this); |
| 2576 for (int i = 0; i < blocks()->length(); ++i) { | 2792 for (int i = 0; i < blocks()->length(); ++i) { |
| 2577 HInstruction* instr = blocks()->at(i)->first(); | 2793 HInstruction* instr = blocks()->at(i)->first(); |
| 2578 while (instr != NULL) { | 2794 while (instr != NULL) { |
| 2579 if (instr->IsBoundsCheck()) { | 2795 if (instr->IsBoundsCheck()) { |
| 2580 // Replace all uses of the checked value with the original input. | 2796 // Replace all uses of the checked value with the original input. |
| 2581 ASSERT(instr->UseCount() > 0); | 2797 ASSERT(instr->UseCount() > 0); |
| 2582 instr->ReplaceAllUsesWith(HBoundsCheck::cast(instr)->index()); | 2798 instr->ReplaceAllUsesWith(HBoundsCheck::cast(instr)->index()); |
| (...skipping 5648 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8231 } | 8447 } |
| 8232 } | 8448 } |
| 8233 | 8449 |
| 8234 #ifdef DEBUG | 8450 #ifdef DEBUG |
| 8235 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 8451 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 8236 if (allocator_ != NULL) allocator_->Verify(); | 8452 if (allocator_ != NULL) allocator_->Verify(); |
| 8237 #endif | 8453 #endif |
| 8238 } | 8454 } |
| 8239 | 8455 |
| 8240 } } // namespace v8::internal | 8456 } } // namespace v8::internal |
| OLD | NEW |