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 725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
736 } | 736 } |
737 | 737 |
738 | 738 |
739 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 739 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
740 HValue* object, | 740 HValue* object, |
741 HValue* key, | 741 HValue* key, |
742 HValue* val, | 742 HValue* val, |
743 HCheckMaps* mapcheck, | 743 HCheckMaps* mapcheck, |
744 bool is_js_array, | 744 bool is_js_array, |
745 ElementsKind elements_kind, | 745 ElementsKind elements_kind, |
746 bool is_store) { | 746 bool is_store, |
747 Representation checked_index_representation) { | |
747 Zone* zone = this->zone(); | 748 Zone* zone = this->zone(); |
748 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency | 749 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency |
749 // on a HElementsTransition instruction. The flag can also be removed if the | 750 // on a HElementsTransition instruction. The flag can also be removed if the |
750 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further | 751 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further |
751 // ElementsKind transitions. Finally, the dependency can be removed for stores | 752 // ElementsKind transitions. Finally, the dependency can be removed for stores |
752 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the | 753 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the |
753 // generated store code. | 754 // generated store code. |
754 if ((elements_kind == FAST_HOLEY_ELEMENTS) || | 755 if ((elements_kind == FAST_HOLEY_ELEMENTS) || |
755 (elements_kind == FAST_ELEMENTS && is_store)) { | 756 (elements_kind == FAST_ELEMENTS && is_store)) { |
756 if (mapcheck != NULL) { | 757 if (mapcheck != NULL) { |
757 mapcheck->ClearGVNFlag(kDependsOnElementsKind); | 758 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
758 } | 759 } |
759 } | 760 } |
760 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); | 761 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); |
761 bool fast_elements = IsFastObjectElementsKind(elements_kind); | 762 bool fast_elements = IsFastObjectElementsKind(elements_kind); |
762 HInstruction* elements = | 763 HInstruction* elements = |
763 AddInstruction(new(zone) HLoadElements(object, mapcheck)); | 764 AddInstruction(new(zone) HLoadElements(object, mapcheck)); |
764 if (is_store && (fast_elements || fast_smi_only_elements)) { | 765 if (is_store && (fast_elements || fast_smi_only_elements)) { |
765 HCheckMaps* check_cow_map = new(zone) HCheckMaps( | 766 HCheckMaps* check_cow_map = new(zone) HCheckMaps( |
766 elements, Isolate::Current()->factory()->fixed_array_map(), zone); | 767 elements, Isolate::Current()->factory()->fixed_array_map(), zone); |
767 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | 768 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
768 AddInstruction(check_cow_map); | 769 AddInstruction(check_cow_map); |
769 } | 770 } |
770 HInstruction* length = NULL; | 771 HInstruction* length = NULL; |
771 HInstruction* checked_key = NULL; | 772 HInstruction* checked_key = NULL; |
772 if (IsExternalArrayElementsKind(elements_kind)) { | 773 if (IsExternalArrayElementsKind(elements_kind)) { |
773 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); | 774 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); |
774 checked_key = AddInstruction(new(zone) HBoundsCheck(key, length, | 775 checked_key = AddInstruction(new(zone) HBoundsCheck( |
775 ALLOW_SMI_KEY)); | 776 key, length, ALLOW_SMI_KEY, checked_index_representation)); |
776 HLoadExternalArrayPointer* external_elements = | 777 HLoadExternalArrayPointer* external_elements = |
777 new(zone) HLoadExternalArrayPointer(elements); | 778 new(zone) HLoadExternalArrayPointer(elements); |
778 AddInstruction(external_elements); | 779 AddInstruction(external_elements); |
779 return BuildExternalArrayElementAccess( | 780 return BuildExternalArrayElementAccess( |
780 external_elements, checked_key, val, mapcheck, | 781 external_elements, checked_key, val, mapcheck, |
781 elements_kind, is_store); | 782 elements_kind, is_store); |
782 } | 783 } |
783 ASSERT(fast_smi_only_elements || | 784 ASSERT(fast_smi_only_elements || |
784 fast_elements || | 785 fast_elements || |
785 IsFastDoubleElementsKind(elements_kind)); | 786 IsFastDoubleElementsKind(elements_kind)); |
786 if (is_js_array) { | 787 if (is_js_array) { |
787 length = AddInstruction(new(zone) HJSArrayLength(object, mapcheck, | 788 length = AddInstruction(new(zone) HJSArrayLength(object, mapcheck, |
788 HType::Smi())); | 789 HType::Smi())); |
789 } else { | 790 } else { |
790 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); | 791 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); |
791 } | 792 } |
792 checked_key = AddInstruction(new(zone) HBoundsCheck(key, length, | 793 checked_key = AddInstruction(new(zone) HBoundsCheck( |
793 ALLOW_SMI_KEY)); | 794 key, length, ALLOW_SMI_KEY, checked_index_representation)); |
794 return BuildFastElementAccess(elements, checked_key, val, mapcheck, | 795 return BuildFastElementAccess(elements, checked_key, val, mapcheck, |
795 elements_kind, is_store); | 796 elements_kind, is_store); |
796 } | 797 } |
797 | 798 |
798 | 799 |
799 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, | 800 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, |
800 TypeFeedbackOracle* oracle) | 801 TypeFeedbackOracle* oracle) |
801 : HGraphBuilder(info), | 802 : HGraphBuilder(info), |
802 function_state_(NULL), | 803 function_state_(NULL), |
803 initial_function_state_(this, info, oracle, NORMAL_RETURN), | 804 initial_function_state_(this, info, oracle, NORMAL_RETURN), |
(...skipping 2692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3496 if (FLAG_use_range) { | 3497 if (FLAG_use_range) { |
3497 HRangeAnalysis rangeAnalysis(this); | 3498 HRangeAnalysis rangeAnalysis(this); |
3498 rangeAnalysis.Analyze(); | 3499 rangeAnalysis.Analyze(); |
3499 } | 3500 } |
3500 ComputeMinusZeroChecks(); | 3501 ComputeMinusZeroChecks(); |
3501 | 3502 |
3502 // Eliminate redundant stack checks on backwards branches. | 3503 // Eliminate redundant stack checks on backwards branches. |
3503 HStackCheckEliminator sce(this); | 3504 HStackCheckEliminator sce(this); |
3504 sce.Process(); | 3505 sce.Process(); |
3505 | 3506 |
3506 EliminateRedundantBoundsChecks(); | 3507 if (FLAG_array_bounds_checks_elimination) EliminateRedundantBoundsChecks(); |
3507 DehoistSimpleArrayIndexComputations(); | 3508 if (FLAG_array_index_dehoisting) DehoistSimpleArrayIndexComputations(); |
3508 if (FLAG_dead_code_elimination) DeadCodeElimination(); | 3509 if (FLAG_dead_code_elimination) DeadCodeElimination(); |
3509 | 3510 |
3511 ApplyActualValues(); | |
3512 | |
3510 return true; | 3513 return true; |
3511 } | 3514 } |
3512 | 3515 |
3513 | 3516 |
3514 // We try to "factor up" HBoundsCheck instructions towards the root of the | 3517 // We try to "factor up" HBoundsCheck instructions towards the root of the |
3515 // dominator tree. | 3518 // dominator tree. |
3516 // For now we handle checks where the index is like "exp + int32value". | 3519 // For now we handle checks where the index is like "exp + int32value". |
3517 // If in the dominator tree we check "exp + v1" and later (dominated) | 3520 // If in the dominator tree we check "exp + v1" and later (dominated) |
3518 // "exp + v2", if v2 <= v1 we can safely remove the second check, and if | 3521 // "exp + v2", if v2 <= v1 we can safely remove the second check, and if |
3519 // v2 > v1 we can use v2 in the 1st check and again remove the second. | 3522 // v2 > v1 we can use v2 in the 1st check and again remove the second. |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3659 new_check->index()->representation(), | 3662 new_check->index()->representation(), |
3660 new_offset); | 3663 new_offset); |
3661 if (!result) return false; | 3664 if (!result) return false; |
3662 lower_check_->SetOperandAt(0, added_lower_index_); | 3665 lower_check_->SetOperandAt(0, added_lower_index_); |
3663 } | 3666 } |
3664 } else { | 3667 } else { |
3665 ASSERT(false); | 3668 ASSERT(false); |
3666 } | 3669 } |
3667 | 3670 |
3668 if (!keep_new_check) { | 3671 if (!keep_new_check) { |
3669 new_check->DeleteAndReplaceWith(NULL); | 3672 new_check->DeleteAndReplaceWith(new_check->ActualValue()); |
3670 } | 3673 } |
3671 | 3674 |
3672 return true; | 3675 return true; |
3673 } | 3676 } |
3674 | 3677 |
3675 void RemoveZeroOperations() { | 3678 void RemoveZeroOperations() { |
3676 RemoveZeroAdd(&added_lower_index_, &added_lower_offset_); | 3679 RemoveZeroAdd(&added_lower_index_, &added_lower_offset_); |
3677 RemoveZeroAdd(&added_upper_index_, &added_upper_offset_); | 3680 RemoveZeroAdd(&added_upper_index_, &added_upper_offset_); |
3678 } | 3681 } |
3679 | 3682 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3795 // this point. It enables better register allocation since the value produced | 3798 // this point. It enables better register allocation since the value produced |
3796 // by check instructions is really a copy of the original value. | 3799 // by check instructions is really a copy of the original value. |
3797 void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb, | 3800 void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb, |
3798 BoundsCheckTable* table) { | 3801 BoundsCheckTable* table) { |
3799 BoundsCheckBbData* bb_data_list = NULL; | 3802 BoundsCheckBbData* bb_data_list = NULL; |
3800 | 3803 |
3801 for (HInstruction* i = bb->first(); i != NULL; i = i->next()) { | 3804 for (HInstruction* i = bb->first(); i != NULL; i = i->next()) { |
3802 if (!i->IsBoundsCheck()) continue; | 3805 if (!i->IsBoundsCheck()) continue; |
3803 | 3806 |
3804 HBoundsCheck* check = HBoundsCheck::cast(i); | 3807 HBoundsCheck* check = HBoundsCheck::cast(i); |
3805 check->ReplaceAllUsesWith(check->index()); | |
3806 | |
3807 if (!FLAG_array_bounds_checks_elimination) continue; | |
3808 | |
3809 int32_t offset; | 3808 int32_t offset; |
3810 BoundsCheckKey* key = | 3809 BoundsCheckKey* key = |
3811 BoundsCheckKey::Create(zone(), check, &offset); | 3810 BoundsCheckKey::Create(zone(), check, &offset); |
3812 if (key == NULL) continue; | 3811 if (key == NULL) continue; |
3813 BoundsCheckBbData** data_p = table->LookupOrInsert(key, zone()); | 3812 BoundsCheckBbData** data_p = table->LookupOrInsert(key, zone()); |
3814 BoundsCheckBbData* data = *data_p; | 3813 BoundsCheckBbData* data = *data_p; |
3815 if (data == NULL) { | 3814 if (data == NULL) { |
3816 bb_data_list = new(zone()) BoundsCheckBbData(key, | 3815 bb_data_list = new(zone()) BoundsCheckBbData(key, |
3817 offset, | 3816 offset, |
3818 offset, | 3817 offset, |
3819 bb, | 3818 bb, |
3820 check, | 3819 check, |
3821 check, | 3820 check, |
3822 bb_data_list, | 3821 bb_data_list, |
3823 NULL); | 3822 NULL); |
3824 *data_p = bb_data_list; | 3823 *data_p = bb_data_list; |
3825 } else if (data->OffsetIsCovered(offset)) { | 3824 } else if (data->OffsetIsCovered(offset)) { |
3826 check->DeleteAndReplaceWith(NULL); | 3825 check->DeleteAndReplaceWith(check->ActualValue()); |
3827 } else if (data->BasicBlock() != bb || | 3826 } else if (data->BasicBlock() != bb || |
3828 !data->CoverCheck(check, offset)) { | 3827 !data->CoverCheck(check, offset)) { |
3829 // If the check is in the current BB we try to modify it by calling | 3828 // If the check is in the current BB we try to modify it by calling |
3830 // "CoverCheck", but if also that fails we record the current offsets | 3829 // "CoverCheck", but if also that fails we record the current offsets |
3831 // in a new data instance because from now on they are covered. | 3830 // in a new data instance because from now on they are covered. |
3832 int32_t new_lower_offset = offset < data->LowerOffset() | 3831 int32_t new_lower_offset = offset < data->LowerOffset() |
3833 ? offset | 3832 ? offset |
3834 : data->LowerOffset(); | 3833 : data->LowerOffset(); |
3835 int32_t new_upper_offset = offset > data->UpperOffset() | 3834 int32_t new_upper_offset = offset > data->UpperOffset() |
3836 ? offset | 3835 ? offset |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3913 if (index->HasNoUses()) { | 3912 if (index->HasNoUses()) { |
3914 index->DeleteAndReplaceWith(NULL); | 3913 index->DeleteAndReplaceWith(NULL); |
3915 } | 3914 } |
3916 ASSERT(value >= 0); | 3915 ASSERT(value >= 0); |
3917 array_operation->SetIndexOffset(static_cast<uint32_t>(value)); | 3916 array_operation->SetIndexOffset(static_cast<uint32_t>(value)); |
3918 array_operation->SetDehoisted(true); | 3917 array_operation->SetDehoisted(true); |
3919 } | 3918 } |
3920 | 3919 |
3921 | 3920 |
3922 void HGraph::DehoistSimpleArrayIndexComputations() { | 3921 void HGraph::DehoistSimpleArrayIndexComputations() { |
3923 if (!FLAG_array_index_dehoisting) return; | |
3924 | |
3925 HPhase phase("H_Dehoist index computations", this); | 3922 HPhase phase("H_Dehoist index computations", this); |
3926 for (int i = 0; i < blocks()->length(); ++i) { | 3923 for (int i = 0; i < blocks()->length(); ++i) { |
3927 for (HInstruction* instr = blocks()->at(i)->first(); | 3924 for (HInstruction* instr = blocks()->at(i)->first(); |
3928 instr != NULL; | 3925 instr != NULL; |
3929 instr = instr->next()) { | 3926 instr = instr->next()) { |
3930 ArrayInstructionInterface* array_instruction = NULL; | 3927 ArrayInstructionInterface* array_instruction = NULL; |
3931 if (instr->IsLoadKeyed()) { | 3928 if (instr->IsLoadKeyed()) { |
3932 HLoadKeyed* op = HLoadKeyed::cast(instr); | 3929 HLoadKeyed* op = HLoadKeyed::cast(instr); |
3933 array_instruction = static_cast<ArrayInstructionInterface*>(op); | 3930 array_instruction = static_cast<ArrayInstructionInterface*>(op); |
3934 } else if (instr->IsStoreKeyed()) { | 3931 } else if (instr->IsStoreKeyed()) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3966 } | 3963 } |
3967 instr->DeleteAndReplaceWith(NULL); | 3964 instr->DeleteAndReplaceWith(NULL); |
3968 for (int i = 0; i < instr->OperandCount(); ++i) { | 3965 for (int i = 0; i < instr->OperandCount(); ++i) { |
3969 HValue* operand = instr->OperandAt(i); | 3966 HValue* operand = instr->OperandAt(i); |
3970 if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone()); | 3967 if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone()); |
3971 } | 3968 } |
3972 } | 3969 } |
3973 } | 3970 } |
3974 | 3971 |
3975 | 3972 |
3973 void HGraph::ApplyActualValues() { | |
3974 HPhase phase("H_Apply actual values", this); | |
Jakob Kummerow
2013/01/10 16:06:47
It would be nice to be able to skip this completel
| |
3975 | |
3976 for (int block_index = 0; block_index < blocks()->length(); block_index++) { | |
3977 HBasicBlock* block = blocks()->at(block_index); | |
3978 | |
3979 for (int i = 0; i < block->phis()->length(); i++) { | |
3980 HPhi* phi = block->phis()->at(i); | |
3981 if (phi->ActualValue() != phi) { | |
Jakob Kummerow
2013/01/10 16:06:47
This can never be true, right? Let's not do the wo
| |
3982 phi->ReplaceAllUsesWith(phi->ActualValue()); | |
3983 } | |
3984 } | |
3985 | |
3986 for (HInstruction* instruction = block->first(); | |
3987 instruction != NULL; | |
3988 instruction = instruction->next()) { | |
3989 if (instruction->ActualValue() != instruction) { | |
3990 instruction->ReplaceAllUsesWith(instruction->ActualValue()); | |
3991 } | |
3992 } | |
3993 } | |
3994 } | |
3995 | |
3996 | |
3976 void HOptimizedGraphBuilder::AddPhi(HPhi* instr) { | 3997 void HOptimizedGraphBuilder::AddPhi(HPhi* instr) { |
3977 ASSERT(current_block() != NULL); | 3998 ASSERT(current_block() != NULL); |
3978 current_block()->AddPhi(instr); | 3999 current_block()->AddPhi(instr); |
3979 } | 4000 } |
3980 | 4001 |
3981 | 4002 |
3982 void HOptimizedGraphBuilder::PushAndAdd(HInstruction* instr) { | 4003 void HOptimizedGraphBuilder::PushAndAdd(HInstruction* instr) { |
3983 Push(instr); | 4004 Push(instr); |
3984 AddInstruction(instr); | 4005 AddInstruction(instr); |
3985 } | 4006 } |
(...skipping 6212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
10198 } | 10219 } |
10199 } | 10220 } |
10200 | 10221 |
10201 #ifdef DEBUG | 10222 #ifdef DEBUG |
10202 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 10223 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
10203 if (allocator_ != NULL) allocator_->Verify(); | 10224 if (allocator_ != NULL) allocator_->Verify(); |
10204 #endif | 10225 #endif |
10205 } | 10226 } |
10206 | 10227 |
10207 } } // namespace v8::internal | 10228 } } // namespace v8::internal |
OLD | NEW |