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 727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
738 } | 738 } |
739 | 739 |
740 | 740 |
741 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 741 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
742 HValue* object, | 742 HValue* object, |
743 HValue* key, | 743 HValue* key, |
744 HValue* val, | 744 HValue* val, |
745 HCheckMaps* mapcheck, | 745 HCheckMaps* mapcheck, |
746 bool is_js_array, | 746 bool is_js_array, |
747 ElementsKind elements_kind, | 747 ElementsKind elements_kind, |
748 bool is_store) { | 748 bool is_store, |
| 749 Representation checked_index_representation) { |
749 Zone* zone = this->zone(); | 750 Zone* zone = this->zone(); |
750 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency | 751 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency |
751 // on a HElementsTransition instruction. The flag can also be removed if the | 752 // on a HElementsTransition instruction. The flag can also be removed if the |
752 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further | 753 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further |
753 // ElementsKind transitions. Finally, the dependency can be removed for stores | 754 // ElementsKind transitions. Finally, the dependency can be removed for stores |
754 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the | 755 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the |
755 // generated store code. | 756 // generated store code. |
756 if ((elements_kind == FAST_HOLEY_ELEMENTS) || | 757 if ((elements_kind == FAST_HOLEY_ELEMENTS) || |
757 (elements_kind == FAST_ELEMENTS && is_store)) { | 758 (elements_kind == FAST_ELEMENTS && is_store)) { |
758 if (mapcheck != NULL) { | 759 if (mapcheck != NULL) { |
759 mapcheck->ClearGVNFlag(kDependsOnElementsKind); | 760 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
760 } | 761 } |
761 } | 762 } |
762 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); | 763 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); |
763 bool fast_elements = IsFastObjectElementsKind(elements_kind); | 764 bool fast_elements = IsFastObjectElementsKind(elements_kind); |
764 HInstruction* elements = | 765 HInstruction* elements = |
765 AddInstruction(new(zone) HLoadElements(object, mapcheck)); | 766 AddInstruction(new(zone) HLoadElements(object, mapcheck)); |
766 if (is_store && (fast_elements || fast_smi_only_elements)) { | 767 if (is_store && (fast_elements || fast_smi_only_elements)) { |
767 HCheckMaps* check_cow_map = new(zone) HCheckMaps( | 768 HCheckMaps* check_cow_map = new(zone) HCheckMaps( |
768 elements, Isolate::Current()->factory()->fixed_array_map(), zone); | 769 elements, Isolate::Current()->factory()->fixed_array_map(), zone); |
769 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | 770 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
770 AddInstruction(check_cow_map); | 771 AddInstruction(check_cow_map); |
771 } | 772 } |
772 HInstruction* length = NULL; | 773 HInstruction* length = NULL; |
773 HInstruction* checked_key = NULL; | 774 HInstruction* checked_key = NULL; |
774 if (IsExternalArrayElementsKind(elements_kind)) { | 775 if (IsExternalArrayElementsKind(elements_kind)) { |
775 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); | 776 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); |
776 checked_key = AddInstruction(new(zone) HBoundsCheck(key, length, | 777 checked_key = AddInstruction(new(zone) HBoundsCheck( |
777 ALLOW_SMI_KEY)); | 778 key, length, ALLOW_SMI_KEY, checked_index_representation)); |
778 HLoadExternalArrayPointer* external_elements = | 779 HLoadExternalArrayPointer* external_elements = |
779 new(zone) HLoadExternalArrayPointer(elements); | 780 new(zone) HLoadExternalArrayPointer(elements); |
780 AddInstruction(external_elements); | 781 AddInstruction(external_elements); |
781 return BuildExternalArrayElementAccess( | 782 return BuildExternalArrayElementAccess( |
782 external_elements, checked_key, val, mapcheck, | 783 external_elements, checked_key, val, mapcheck, |
783 elements_kind, is_store); | 784 elements_kind, is_store); |
784 } | 785 } |
785 ASSERT(fast_smi_only_elements || | 786 ASSERT(fast_smi_only_elements || |
786 fast_elements || | 787 fast_elements || |
787 IsFastDoubleElementsKind(elements_kind)); | 788 IsFastDoubleElementsKind(elements_kind)); |
788 if (is_js_array) { | 789 if (is_js_array) { |
789 length = AddInstruction(new(zone) HJSArrayLength(object, mapcheck, | 790 length = AddInstruction(new(zone) HJSArrayLength(object, mapcheck, |
790 HType::Smi())); | 791 HType::Smi())); |
791 } else { | 792 } else { |
792 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); | 793 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); |
793 } | 794 } |
794 checked_key = AddInstruction(new(zone) HBoundsCheck(key, length, | 795 checked_key = AddInstruction(new(zone) HBoundsCheck( |
795 ALLOW_SMI_KEY)); | 796 key, length, ALLOW_SMI_KEY, checked_index_representation)); |
796 return BuildFastElementAccess(elements, checked_key, val, mapcheck, | 797 return BuildFastElementAccess(elements, checked_key, val, mapcheck, |
797 elements_kind, is_store); | 798 elements_kind, is_store); |
798 } | 799 } |
799 | 800 |
800 | 801 |
801 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, | 802 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, |
802 TypeFeedbackOracle* oracle) | 803 TypeFeedbackOracle* oracle) |
803 : HGraphBuilder(info), | 804 : HGraphBuilder(info), |
804 function_state_(NULL), | 805 function_state_(NULL), |
805 initial_function_state_(this, info, oracle, NORMAL_RETURN), | 806 initial_function_state_(this, info, oracle, NORMAL_RETURN), |
(...skipping 2773 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3579 if (FLAG_use_range) { | 3580 if (FLAG_use_range) { |
3580 HRangeAnalysis rangeAnalysis(this); | 3581 HRangeAnalysis rangeAnalysis(this); |
3581 rangeAnalysis.Analyze(); | 3582 rangeAnalysis.Analyze(); |
3582 } | 3583 } |
3583 ComputeMinusZeroChecks(); | 3584 ComputeMinusZeroChecks(); |
3584 | 3585 |
3585 // Eliminate redundant stack checks on backwards branches. | 3586 // Eliminate redundant stack checks on backwards branches. |
3586 HStackCheckEliminator sce(this); | 3587 HStackCheckEliminator sce(this); |
3587 sce.Process(); | 3588 sce.Process(); |
3588 | 3589 |
3589 EliminateRedundantBoundsChecks(); | 3590 if (FLAG_array_bounds_checks_elimination) EliminateRedundantBoundsChecks(); |
3590 DehoistSimpleArrayIndexComputations(); | 3591 if (FLAG_array_index_dehoisting) DehoistSimpleArrayIndexComputations(); |
3591 if (FLAG_dead_code_elimination) DeadCodeElimination(); | 3592 if (FLAG_dead_code_elimination) DeadCodeElimination(); |
3592 | 3593 |
| 3594 RestoreActualValues(); |
| 3595 |
3593 return true; | 3596 return true; |
3594 } | 3597 } |
3595 | 3598 |
3596 | 3599 |
3597 // We try to "factor up" HBoundsCheck instructions towards the root of the | 3600 // We try to "factor up" HBoundsCheck instructions towards the root of the |
3598 // dominator tree. | 3601 // dominator tree. |
3599 // For now we handle checks where the index is like "exp + int32value". | 3602 // For now we handle checks where the index is like "exp + int32value". |
3600 // If in the dominator tree we check "exp + v1" and later (dominated) | 3603 // If in the dominator tree we check "exp + v1" and later (dominated) |
3601 // "exp + v2", if v2 <= v1 we can safely remove the second check, and if | 3604 // "exp + v2", if v2 <= v1 we can safely remove the second check, and if |
3602 // v2 > v1 we can use v2 in the 1st check and again remove the second. | 3605 // v2 > v1 we can use v2 in the 1st check and again remove the second. |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3720 keep_new_check = true; | 3723 keep_new_check = true; |
3721 upper_check_ = new_check; | 3724 upper_check_ = new_check; |
3722 } else { | 3725 } else { |
3723 bool result = BuildOffsetAdd(upper_check_, | 3726 bool result = BuildOffsetAdd(upper_check_, |
3724 &added_upper_index_, | 3727 &added_upper_index_, |
3725 &added_upper_offset_, | 3728 &added_upper_offset_, |
3726 Key()->IndexBase(), | 3729 Key()->IndexBase(), |
3727 new_check->index()->representation(), | 3730 new_check->index()->representation(), |
3728 new_offset); | 3731 new_offset); |
3729 if (!result) return false; | 3732 if (!result) return false; |
| 3733 upper_check_->ReplaceAllUsesWith(upper_check_->index()); |
3730 upper_check_->SetOperandAt(0, added_upper_index_); | 3734 upper_check_->SetOperandAt(0, added_upper_index_); |
3731 } | 3735 } |
3732 } else if (new_offset < lower_offset_) { | 3736 } else if (new_offset < lower_offset_) { |
3733 lower_offset_ = new_offset; | 3737 lower_offset_ = new_offset; |
3734 if (HasSingleCheck()) { | 3738 if (HasSingleCheck()) { |
3735 keep_new_check = true; | 3739 keep_new_check = true; |
3736 lower_check_ = new_check; | 3740 lower_check_ = new_check; |
3737 } else { | 3741 } else { |
3738 bool result = BuildOffsetAdd(lower_check_, | 3742 bool result = BuildOffsetAdd(lower_check_, |
3739 &added_lower_index_, | 3743 &added_lower_index_, |
3740 &added_lower_offset_, | 3744 &added_lower_offset_, |
3741 Key()->IndexBase(), | 3745 Key()->IndexBase(), |
3742 new_check->index()->representation(), | 3746 new_check->index()->representation(), |
3743 new_offset); | 3747 new_offset); |
3744 if (!result) return false; | 3748 if (!result) return false; |
| 3749 lower_check_->ReplaceAllUsesWith(lower_check_->index()); |
3745 lower_check_->SetOperandAt(0, added_lower_index_); | 3750 lower_check_->SetOperandAt(0, added_lower_index_); |
3746 } | 3751 } |
3747 } else { | 3752 } else { |
3748 ASSERT(false); | 3753 ASSERT(false); |
3749 } | 3754 } |
3750 | 3755 |
3751 if (!keep_new_check) { | 3756 if (!keep_new_check) { |
3752 new_check->DeleteAndReplaceWith(NULL); | 3757 new_check->DeleteAndReplaceWith(new_check->ActualValue()); |
3753 } | 3758 } |
3754 | 3759 |
3755 return true; | 3760 return true; |
3756 } | 3761 } |
3757 | 3762 |
3758 void RemoveZeroOperations() { | 3763 void RemoveZeroOperations() { |
3759 RemoveZeroAdd(&added_lower_index_, &added_lower_offset_); | 3764 RemoveZeroAdd(&added_lower_index_, &added_lower_offset_); |
3760 RemoveZeroAdd(&added_upper_index_, &added_upper_offset_); | 3765 RemoveZeroAdd(&added_upper_index_, &added_upper_offset_); |
3761 } | 3766 } |
3762 | 3767 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3878 // this point. It enables better register allocation since the value produced | 3883 // this point. It enables better register allocation since the value produced |
3879 // by check instructions is really a copy of the original value. | 3884 // by check instructions is really a copy of the original value. |
3880 void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb, | 3885 void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb, |
3881 BoundsCheckTable* table) { | 3886 BoundsCheckTable* table) { |
3882 BoundsCheckBbData* bb_data_list = NULL; | 3887 BoundsCheckBbData* bb_data_list = NULL; |
3883 | 3888 |
3884 for (HInstruction* i = bb->first(); i != NULL; i = i->next()) { | 3889 for (HInstruction* i = bb->first(); i != NULL; i = i->next()) { |
3885 if (!i->IsBoundsCheck()) continue; | 3890 if (!i->IsBoundsCheck()) continue; |
3886 | 3891 |
3887 HBoundsCheck* check = HBoundsCheck::cast(i); | 3892 HBoundsCheck* check = HBoundsCheck::cast(i); |
3888 check->ReplaceAllUsesWith(check->index()); | |
3889 | |
3890 if (!FLAG_array_bounds_checks_elimination) continue; | |
3891 | |
3892 int32_t offset; | 3893 int32_t offset; |
3893 BoundsCheckKey* key = | 3894 BoundsCheckKey* key = |
3894 BoundsCheckKey::Create(zone(), check, &offset); | 3895 BoundsCheckKey::Create(zone(), check, &offset); |
3895 if (key == NULL) continue; | 3896 if (key == NULL) continue; |
3896 BoundsCheckBbData** data_p = table->LookupOrInsert(key, zone()); | 3897 BoundsCheckBbData** data_p = table->LookupOrInsert(key, zone()); |
3897 BoundsCheckBbData* data = *data_p; | 3898 BoundsCheckBbData* data = *data_p; |
3898 if (data == NULL) { | 3899 if (data == NULL) { |
3899 bb_data_list = new(zone()) BoundsCheckBbData(key, | 3900 bb_data_list = new(zone()) BoundsCheckBbData(key, |
3900 offset, | 3901 offset, |
3901 offset, | 3902 offset, |
3902 bb, | 3903 bb, |
3903 check, | 3904 check, |
3904 check, | 3905 check, |
3905 bb_data_list, | 3906 bb_data_list, |
3906 NULL); | 3907 NULL); |
3907 *data_p = bb_data_list; | 3908 *data_p = bb_data_list; |
3908 } else if (data->OffsetIsCovered(offset)) { | 3909 } else if (data->OffsetIsCovered(offset)) { |
3909 check->DeleteAndReplaceWith(NULL); | 3910 check->DeleteAndReplaceWith(check->ActualValue()); |
3910 } else if (data->BasicBlock() != bb || | 3911 } else if (data->BasicBlock() != bb || |
3911 !data->CoverCheck(check, offset)) { | 3912 !data->CoverCheck(check, offset)) { |
3912 // If the check is in the current BB we try to modify it by calling | 3913 // If the check is in the current BB we try to modify it by calling |
3913 // "CoverCheck", but if also that fails we record the current offsets | 3914 // "CoverCheck", but if also that fails we record the current offsets |
3914 // in a new data instance because from now on they are covered. | 3915 // in a new data instance because from now on they are covered. |
3915 int32_t new_lower_offset = offset < data->LowerOffset() | 3916 int32_t new_lower_offset = offset < data->LowerOffset() |
3916 ? offset | 3917 ? offset |
3917 : data->LowerOffset(); | 3918 : data->LowerOffset(); |
3918 int32_t new_upper_offset = offset > data->UpperOffset() | 3919 int32_t new_upper_offset = offset > data->UpperOffset() |
3919 ? offset | 3920 ? offset |
(...skipping 28 matching lines...) Expand all Loading... |
3948 | 3949 |
3949 | 3950 |
3950 void HGraph::EliminateRedundantBoundsChecks() { | 3951 void HGraph::EliminateRedundantBoundsChecks() { |
3951 HPhase phase("H_Eliminate bounds checks", this); | 3952 HPhase phase("H_Eliminate bounds checks", this); |
3952 BoundsCheckTable checks_table(zone()); | 3953 BoundsCheckTable checks_table(zone()); |
3953 EliminateRedundantBoundsChecks(entry_block(), &checks_table); | 3954 EliminateRedundantBoundsChecks(entry_block(), &checks_table); |
3954 } | 3955 } |
3955 | 3956 |
3956 | 3957 |
3957 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { | 3958 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { |
3958 HValue* index = array_operation->GetKey(); | 3959 HValue* index = array_operation->GetKey()->ActualValue(); |
3959 if (!index->representation().IsInteger32()) return; | 3960 if (!index->representation().IsInteger32()) return; |
3960 | 3961 |
3961 HConstant* constant; | 3962 HConstant* constant; |
3962 HValue* subexpression; | 3963 HValue* subexpression; |
3963 int32_t sign; | 3964 int32_t sign; |
3964 if (index->IsAdd()) { | 3965 if (index->IsAdd()) { |
3965 sign = 1; | 3966 sign = 1; |
3966 HAdd* add = HAdd::cast(index); | 3967 HAdd* add = HAdd::cast(index); |
3967 if (add->left()->IsConstant()) { | 3968 if (add->left()->IsConstant()) { |
3968 subexpression = add->right(); | 3969 subexpression = add->right(); |
(...skipping 27 matching lines...) Expand all Loading... |
3996 if (index->HasNoUses()) { | 3997 if (index->HasNoUses()) { |
3997 index->DeleteAndReplaceWith(NULL); | 3998 index->DeleteAndReplaceWith(NULL); |
3998 } | 3999 } |
3999 ASSERT(value >= 0); | 4000 ASSERT(value >= 0); |
4000 array_operation->SetIndexOffset(static_cast<uint32_t>(value)); | 4001 array_operation->SetIndexOffset(static_cast<uint32_t>(value)); |
4001 array_operation->SetDehoisted(true); | 4002 array_operation->SetDehoisted(true); |
4002 } | 4003 } |
4003 | 4004 |
4004 | 4005 |
4005 void HGraph::DehoistSimpleArrayIndexComputations() { | 4006 void HGraph::DehoistSimpleArrayIndexComputations() { |
4006 if (!FLAG_array_index_dehoisting) return; | |
4007 | |
4008 HPhase phase("H_Dehoist index computations", this); | 4007 HPhase phase("H_Dehoist index computations", this); |
4009 for (int i = 0; i < blocks()->length(); ++i) { | 4008 for (int i = 0; i < blocks()->length(); ++i) { |
4010 for (HInstruction* instr = blocks()->at(i)->first(); | 4009 for (HInstruction* instr = blocks()->at(i)->first(); |
4011 instr != NULL; | 4010 instr != NULL; |
4012 instr = instr->next()) { | 4011 instr = instr->next()) { |
4013 ArrayInstructionInterface* array_instruction = NULL; | 4012 ArrayInstructionInterface* array_instruction = NULL; |
4014 if (instr->IsLoadKeyed()) { | 4013 if (instr->IsLoadKeyed()) { |
4015 HLoadKeyed* op = HLoadKeyed::cast(instr); | 4014 HLoadKeyed* op = HLoadKeyed::cast(instr); |
4016 array_instruction = static_cast<ArrayInstructionInterface*>(op); | 4015 array_instruction = static_cast<ArrayInstructionInterface*>(op); |
4017 } else if (instr->IsStoreKeyed()) { | 4016 } else if (instr->IsStoreKeyed()) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4049 } | 4048 } |
4050 instr->DeleteAndReplaceWith(NULL); | 4049 instr->DeleteAndReplaceWith(NULL); |
4051 for (int i = 0; i < instr->OperandCount(); ++i) { | 4050 for (int i = 0; i < instr->OperandCount(); ++i) { |
4052 HValue* operand = instr->OperandAt(i); | 4051 HValue* operand = instr->OperandAt(i); |
4053 if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone()); | 4052 if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone()); |
4054 } | 4053 } |
4055 } | 4054 } |
4056 } | 4055 } |
4057 | 4056 |
4058 | 4057 |
| 4058 void HGraph::RestoreActualValues() { |
| 4059 HPhase phase("H_Restore actual values", this); |
| 4060 |
| 4061 for (int block_index = 0; block_index < blocks()->length(); block_index++) { |
| 4062 HBasicBlock* block = blocks()->at(block_index); |
| 4063 |
| 4064 #ifdef DEBUG |
| 4065 for (int i = 0; i < block->phis()->length(); i++) { |
| 4066 HPhi* phi = block->phis()->at(i); |
| 4067 ASSERT(phi->ActualValue() == phi); |
| 4068 } |
| 4069 #endif |
| 4070 |
| 4071 for (HInstruction* instruction = block->first(); |
| 4072 instruction != NULL; |
| 4073 instruction = instruction->next()) { |
| 4074 if (instruction->ActualValue() != instruction) { |
| 4075 instruction->ReplaceAllUsesWith(instruction->ActualValue()); |
| 4076 } |
| 4077 } |
| 4078 } |
| 4079 } |
| 4080 |
| 4081 |
4059 void HOptimizedGraphBuilder::AddPhi(HPhi* instr) { | 4082 void HOptimizedGraphBuilder::AddPhi(HPhi* instr) { |
4060 ASSERT(current_block() != NULL); | 4083 ASSERT(current_block() != NULL); |
4061 current_block()->AddPhi(instr); | 4084 current_block()->AddPhi(instr); |
4062 } | 4085 } |
4063 | 4086 |
4064 | 4087 |
4065 void HOptimizedGraphBuilder::PushAndAdd(HInstruction* instr) { | 4088 void HOptimizedGraphBuilder::PushAndAdd(HInstruction* instr) { |
4066 Push(instr); | 4089 Push(instr); |
4067 AddInstruction(instr); | 4090 AddInstruction(instr); |
4068 } | 4091 } |
(...skipping 6256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10325 } | 10348 } |
10326 } | 10349 } |
10327 | 10350 |
10328 #ifdef DEBUG | 10351 #ifdef DEBUG |
10329 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 10352 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
10330 if (allocator_ != NULL) allocator_->Verify(); | 10353 if (allocator_ != NULL) allocator_->Verify(); |
10331 #endif | 10354 #endif |
10332 } | 10355 } |
10333 | 10356 |
10334 } } // namespace v8::internal | 10357 } } // namespace v8::internal |
OLD | NEW |