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 |