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 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 void HValue::AddDependantsToWorklist(HInferRepresentation* h_infer) { | 160 void HValue::AddDependantsToWorklist(HInferRepresentation* h_infer) { |
161 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { | 161 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { |
162 h_infer->AddToWorklist(it.value()); | 162 h_infer->AddToWorklist(it.value()); |
163 } | 163 } |
164 for (int i = 0; i < OperandCount(); ++i) { | 164 for (int i = 0; i < OperandCount(); ++i) { |
165 h_infer->AddToWorklist(OperandAt(i)); | 165 h_infer->AddToWorklist(OperandAt(i)); |
166 } | 166 } |
167 } | 167 } |
168 | 168 |
169 | 169 |
| 170 // This method is recursive but it is guaranteed to terminate because |
| 171 // RedefinedOperand() always dominates "this". |
| 172 bool HValue::IsRelationTrue(NumericRelation relation, |
| 173 HValue* other, |
| 174 int offset, |
| 175 int scale) { |
| 176 if (this == other) { |
| 177 return NumericRelation::Eq().Implies(relation); |
| 178 } |
| 179 |
| 180 // Test the direct relation. |
| 181 if (IsRelationTrueInternal(relation, other, offset, scale)) return true; |
| 182 |
| 183 // If scale is 0 try the reversed relation. |
| 184 if (scale == 0 && |
| 185 // TODO(mmassi): do we need the full, recursive IsRelationTrue? |
| 186 other->IsRelationTrueInternal(relation.Reversed(), this, -offset)) { |
| 187 return true; |
| 188 } |
| 189 |
| 190 // Try decomposition (but do not accept scaled compounds). |
| 191 DecompositionResult decomposition; |
| 192 if (TryDecompose(&decomposition) && |
| 193 decomposition.scale() == 0 && |
| 194 decomposition.base()->IsRelationTrue(relation, other, |
| 195 offset + decomposition.offset(), |
| 196 scale)) { |
| 197 return true; |
| 198 } |
| 199 |
| 200 // Pass the request to the redefined value. |
| 201 HValue* redefined = RedefinedOperand(); |
| 202 return redefined != NULL && redefined->IsRelationTrue(relation, other, |
| 203 offset, scale); |
| 204 } |
| 205 |
| 206 |
| 207 bool HValue::TryGuaranteeRange(HValue* upper_bound) { |
| 208 RangeEvaluationContext context = RangeEvaluationContext(this, upper_bound); |
| 209 TryGuaranteeRangeRecursive(&context); |
| 210 bool result = context.is_range_satisfied(); |
| 211 if (result) { |
| 212 context.lower_bound_guarantee()->SetResponsibilityForRange(DIRECTION_LOWER); |
| 213 context.upper_bound_guarantee()->SetResponsibilityForRange(DIRECTION_UPPER); |
| 214 } |
| 215 return result; |
| 216 } |
| 217 |
| 218 |
| 219 void HValue::TryGuaranteeRangeRecursive(RangeEvaluationContext* context) { |
| 220 // Check if we already know that this value satisfies the lower bound. |
| 221 if (context->lower_bound_guarantee() == NULL) { |
| 222 if (IsRelationTrueInternal(NumericRelation::Ge(), context->lower_bound(), |
| 223 context->offset(), context->scale())) { |
| 224 context->set_lower_bound_guarantee(this); |
| 225 } |
| 226 } |
| 227 |
| 228 // Check if we already know that this value satisfies the upper bound. |
| 229 if (context->upper_bound_guarantee() == NULL) { |
| 230 if (IsRelationTrueInternal(NumericRelation::Lt(), context->upper_bound(), |
| 231 context->offset(), context->scale()) || |
| 232 (context->scale() == 0 && |
| 233 context->upper_bound()->IsRelationTrue(NumericRelation::Gt(), |
| 234 this, -context->offset()))) { |
| 235 context->set_upper_bound_guarantee(this); |
| 236 } |
| 237 } |
| 238 |
| 239 if (context->is_range_satisfied()) return; |
| 240 |
| 241 // See if our RedefinedOperand() satisfies the constraints. |
| 242 if (RedefinedOperand() != NULL) { |
| 243 RedefinedOperand()->TryGuaranteeRangeRecursive(context); |
| 244 } |
| 245 if (context->is_range_satisfied()) return; |
| 246 |
| 247 // See if the constraints can be satisfied by decomposition. |
| 248 DecompositionResult decomposition; |
| 249 if (TryDecompose(&decomposition)) { |
| 250 context->swap_candidate(&decomposition); |
| 251 context->candidate()->TryGuaranteeRangeRecursive(context); |
| 252 context->swap_candidate(&decomposition); |
| 253 } |
| 254 if (context->is_range_satisfied()) return; |
| 255 |
| 256 // Try to modify this to satisfy the constraint. |
| 257 |
| 258 TryGuaranteeRangeChanging(context); |
| 259 } |
| 260 |
| 261 |
| 262 RangeEvaluationContext::RangeEvaluationContext(HValue* value, HValue* upper) |
| 263 : lower_bound_(upper->block()->graph()->GetConstant0()), |
| 264 lower_bound_guarantee_(NULL), |
| 265 candidate_(value), |
| 266 upper_bound_(upper), |
| 267 upper_bound_guarantee_(NULL), |
| 268 offset_(0), |
| 269 scale_(0) { |
| 270 } |
| 271 |
| 272 |
| 273 HValue* RangeEvaluationContext::ConvertGuarantee(HValue* guarantee) { |
| 274 return guarantee->IsBoundsCheckBaseIndexInformation() |
| 275 ? HBoundsCheckBaseIndexInformation::cast(guarantee)->bounds_check() |
| 276 : guarantee; |
| 277 } |
| 278 |
| 279 |
170 static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) { | 280 static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) { |
171 if (result > kMaxInt) { | 281 if (result > kMaxInt) { |
172 *overflow = true; | 282 *overflow = true; |
173 return kMaxInt; | 283 return kMaxInt; |
174 } | 284 } |
175 if (result < kMinInt) { | 285 if (result < kMinInt) { |
176 *overflow = true; | 286 *overflow = true; |
177 return kMinInt; | 287 return kMinInt; |
178 } | 288 } |
179 return static_cast<int32_t>(result); | 289 return static_cast<int32_t>(result); |
(...skipping 701 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
881 | 991 |
882 void HBinaryCall::PrintDataTo(StringStream* stream) { | 992 void HBinaryCall::PrintDataTo(StringStream* stream) { |
883 first()->PrintNameTo(stream); | 993 first()->PrintNameTo(stream); |
884 stream->Add(" "); | 994 stream->Add(" "); |
885 second()->PrintNameTo(stream); | 995 second()->PrintNameTo(stream); |
886 stream->Add(" "); | 996 stream->Add(" "); |
887 stream->Add("#%d", argument_count()); | 997 stream->Add("#%d", argument_count()); |
888 } | 998 } |
889 | 999 |
890 | 1000 |
| 1001 void HBoundsCheck::TryGuaranteeRangeChanging(RangeEvaluationContext* context) { |
| 1002 if (context->candidate()->ActualValue() != base()->ActualValue() || |
| 1003 context->scale() < scale()) { |
| 1004 return; |
| 1005 } |
| 1006 |
| 1007 // TODO(mmassi) |
| 1008 // Instead of checking for "same basic block" we should check for |
| 1009 // "dominates and postdominates". |
| 1010 if (context->upper_bound() == length() && |
| 1011 context->lower_bound_guarantee() != NULL && |
| 1012 context->lower_bound_guarantee() != this && |
| 1013 context->lower_bound_guarantee()->block() != block() && |
| 1014 offset() < context->offset() && |
| 1015 index_can_increase() && |
| 1016 context->upper_bound_guarantee() == NULL) { |
| 1017 offset_ = context->offset(); |
| 1018 SetResponsibilityForRange(DIRECTION_UPPER); |
| 1019 context->set_upper_bound_guarantee(this); |
| 1020 } else if (context->upper_bound_guarantee() != NULL && |
| 1021 context->upper_bound_guarantee() != this && |
| 1022 context->upper_bound_guarantee()->block() != block() && |
| 1023 offset() > context->offset() && |
| 1024 index_can_decrease() && |
| 1025 context->lower_bound_guarantee() == NULL) { |
| 1026 offset_ = context->offset(); |
| 1027 SetResponsibilityForRange(DIRECTION_LOWER); |
| 1028 context->set_lower_bound_guarantee(this); |
| 1029 } |
| 1030 } |
| 1031 |
| 1032 |
| 1033 void HBoundsCheck::ApplyIndexChange() { |
| 1034 if (skip_check()) return; |
| 1035 |
| 1036 DecompositionResult decomposition; |
| 1037 bool index_is_decomposable = index()->TryDecompose(&decomposition); |
| 1038 if (index_is_decomposable) { |
| 1039 ASSERT(decomposition.base() == base()); |
| 1040 if (decomposition.offset() == offset() && |
| 1041 decomposition.scale() == scale()) return; |
| 1042 } else { |
| 1043 return; |
| 1044 } |
| 1045 |
| 1046 ReplaceAllUsesWith(index()); |
| 1047 |
| 1048 HValue* current_index = decomposition.base(); |
| 1049 int actual_offset = decomposition.offset() + offset(); |
| 1050 int actual_scale = decomposition.scale() + scale(); |
| 1051 |
| 1052 if (actual_offset != 0) { |
| 1053 HConstant* add_offset = new(block()->graph()->zone()) HConstant( |
| 1054 actual_offset, index()->representation()); |
| 1055 add_offset->InsertBefore(this); |
| 1056 HInstruction* add = HAdd::New(block()->graph()->zone(), |
| 1057 block()->graph()->GetInvalidContext(), current_index, add_offset); |
| 1058 add->InsertBefore(this); |
| 1059 add->AssumeRepresentation(index()->representation()); |
| 1060 current_index = add; |
| 1061 } |
| 1062 |
| 1063 if (actual_scale != 0) { |
| 1064 HConstant* sar_scale = new(block()->graph()->zone()) HConstant( |
| 1065 actual_scale, index()->representation()); |
| 1066 sar_scale->InsertBefore(this); |
| 1067 HInstruction* sar = HSar::New(block()->graph()->zone(), |
| 1068 block()->graph()->GetInvalidContext(), current_index, sar_scale); |
| 1069 sar->InsertBefore(this); |
| 1070 sar->AssumeRepresentation(index()->representation()); |
| 1071 current_index = sar; |
| 1072 } |
| 1073 |
| 1074 SetOperandAt(0, current_index); |
| 1075 |
| 1076 base_ = NULL; |
| 1077 offset_ = 0; |
| 1078 scale_ = 0; |
| 1079 responsibility_direction_ = DIRECTION_NONE; |
| 1080 } |
| 1081 |
| 1082 |
891 void HBoundsCheck::AddInformativeDefinitions() { | 1083 void HBoundsCheck::AddInformativeDefinitions() { |
892 // TODO(mmassi): Executing this code during AddInformativeDefinitions | 1084 // TODO(mmassi): Executing this code during AddInformativeDefinitions |
893 // is a hack. Move it to some other HPhase. | 1085 // is a hack. Move it to some other HPhase. |
894 if (index()->IsRelationTrue(NumericRelation::Ge(), | 1086 if (FLAG_array_bounds_checks_elimination) { |
895 block()->graph()->GetConstant0()) && | 1087 if (index()->TryGuaranteeRange(length())) { |
896 index()->IsRelationTrue(NumericRelation::Lt(), length())) { | 1088 set_skip_check(true); |
897 set_skip_check(true); | 1089 } |
| 1090 if (DetectCompoundIndex()) { |
| 1091 HBoundsCheckBaseIndexInformation* base_index_info = |
| 1092 new(block()->graph()->zone()) |
| 1093 HBoundsCheckBaseIndexInformation(this); |
| 1094 base_index_info->InsertAfter(this); |
| 1095 } |
898 } | 1096 } |
899 } | 1097 } |
900 | 1098 |
901 | 1099 |
902 bool HBoundsCheck::IsRelationTrueInternal(NumericRelation relation, | 1100 bool HBoundsCheck::IsRelationTrueInternal(NumericRelation relation, |
903 HValue* related_value) { | 1101 HValue* related_value, |
| 1102 int offset, |
| 1103 int scale) { |
904 if (related_value == length()) { | 1104 if (related_value == length()) { |
905 // A HBoundsCheck is smaller than the length it compared against. | 1105 // A HBoundsCheck is smaller than the length it compared against. |
906 return NumericRelation::Lt().Implies(relation); | 1106 return NumericRelation::Lt().CompoundImplies(relation, 0, 0, offset, scale); |
907 } else if (related_value == block()->graph()->GetConstant0()) { | 1107 } else if (related_value == block()->graph()->GetConstant0()) { |
908 // A HBoundsCheck is greater than or equal to zero. | 1108 // A HBoundsCheck is greater than or equal to zero. |
909 return NumericRelation::Ge().Implies(relation); | 1109 return NumericRelation::Ge().CompoundImplies(relation, 0, 0, offset, scale); |
910 } else { | 1110 } else { |
911 return false; | 1111 return false; |
912 } | 1112 } |
913 } | 1113 } |
914 | 1114 |
915 | 1115 |
916 void HBoundsCheck::PrintDataTo(StringStream* stream) { | 1116 void HBoundsCheck::PrintDataTo(StringStream* stream) { |
917 index()->PrintNameTo(stream); | 1117 index()->PrintNameTo(stream); |
918 stream->Add(" "); | 1118 stream->Add(" "); |
919 length()->PrintNameTo(stream); | 1119 length()->PrintNameTo(stream); |
| 1120 if (base() != NULL && (offset() != 0 || scale() != 0)) { |
| 1121 stream->Add(" base: (("); |
| 1122 if (base() != index()) { |
| 1123 index()->PrintNameTo(stream); |
| 1124 } else { |
| 1125 stream->Add("index"); |
| 1126 } |
| 1127 stream->Add(" + %d) >> %d)", offset(), scale()); |
| 1128 } |
920 if (skip_check()) { | 1129 if (skip_check()) { |
921 stream->Add(" [DISABLED]"); | 1130 stream->Add(" [DISABLED]"); |
922 } | 1131 } |
923 } | 1132 } |
924 | 1133 |
925 | 1134 |
926 void HBoundsCheck::InferRepresentation(HInferRepresentation* h_infer) { | 1135 void HBoundsCheck::InferRepresentation(HInferRepresentation* h_infer) { |
927 ASSERT(CheckFlag(kFlexibleRepresentation)); | 1136 ASSERT(CheckFlag(kFlexibleRepresentation)); |
928 Representation r; | 1137 Representation r; |
929 HValue* actual_length = length()->ActualValue(); | 1138 HValue* actual_length = length()->ActualValue(); |
930 HValue* actual_index = index()->ActualValue(); | 1139 HValue* actual_index = index()->ActualValue(); |
931 if (key_mode_ == DONT_ALLOW_SMI_KEY || | 1140 if (key_mode_ == DONT_ALLOW_SMI_KEY || |
932 !actual_length->representation().IsTagged()) { | 1141 !actual_length->representation().IsTagged()) { |
933 r = Representation::Integer32(); | 1142 r = Representation::Integer32(); |
934 } else if (actual_index->representation().IsTagged() || | 1143 } else if (actual_index->representation().IsTagged() || |
935 (actual_index->IsConstant() && | 1144 (actual_index->IsConstant() && |
936 HConstant::cast(actual_index)->HasSmiValue())) { | 1145 HConstant::cast(actual_index)->HasSmiValue())) { |
937 // If the index is tagged, or a constant that holds a Smi, allow the length | 1146 // If the index is tagged, or a constant that holds a Smi, allow the length |
938 // to be tagged, since it is usually already tagged from loading it out of | 1147 // to be tagged, since it is usually already tagged from loading it out of |
939 // the length field of a JSArray. This allows for direct comparison without | 1148 // the length field of a JSArray. This allows for direct comparison without |
940 // untagging. | 1149 // untagging. |
941 r = Representation::Tagged(); | 1150 r = Representation::Tagged(); |
942 } else { | 1151 } else { |
943 r = Representation::Integer32(); | 1152 r = Representation::Integer32(); |
944 } | 1153 } |
945 UpdateRepresentation(r, h_infer, "boundscheck"); | 1154 UpdateRepresentation(r, h_infer, "boundscheck"); |
946 } | 1155 } |
947 | 1156 |
948 | 1157 |
| 1158 bool HBoundsCheckBaseIndexInformation::IsRelationTrueInternal( |
| 1159 NumericRelation relation, |
| 1160 HValue* related_value, |
| 1161 int offset, |
| 1162 int scale) { |
| 1163 if (related_value == bounds_check()->length()) { |
| 1164 return NumericRelation::Lt().CompoundImplies( |
| 1165 relation, |
| 1166 bounds_check()->offset(), bounds_check()->scale(), offset, scale); |
| 1167 } else if (related_value == block()->graph()->GetConstant0()) { |
| 1168 return NumericRelation::Ge().CompoundImplies( |
| 1169 relation, |
| 1170 bounds_check()->offset(), bounds_check()->scale(), offset, scale); |
| 1171 } else { |
| 1172 return false; |
| 1173 } |
| 1174 } |
| 1175 |
| 1176 |
| 1177 void HBoundsCheckBaseIndexInformation::PrintDataTo(StringStream* stream) { |
| 1178 stream->Add("base: "); |
| 1179 base_index()->PrintNameTo(stream); |
| 1180 stream->Add(", check: "); |
| 1181 base_index()->PrintNameTo(stream); |
| 1182 } |
| 1183 |
| 1184 |
949 void HCallConstantFunction::PrintDataTo(StringStream* stream) { | 1185 void HCallConstantFunction::PrintDataTo(StringStream* stream) { |
950 if (IsApplyFunction()) { | 1186 if (IsApplyFunction()) { |
951 stream->Add("optimized apply "); | 1187 stream->Add("optimized apply "); |
952 } else { | 1188 } else { |
953 stream->Add("%o ", function()->shared()->DebugName()); | 1189 stream->Add("%o ", function()->shared()->DebugName()); |
954 } | 1190 } |
955 stream->Add("#%d", argument_count()); | 1191 stream->Add("#%d", argument_count()); |
956 } | 1192 } |
957 | 1193 |
958 | 1194 |
(...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1604 HInductionVariableAnnotation::AddToGraph(this, | 1840 HInductionVariableAnnotation::AddToGraph(this, |
1605 relations[relation_index], | 1841 relations[relation_index], |
1606 other_operand_index); | 1842 other_operand_index); |
1607 } | 1843 } |
1608 } | 1844 } |
1609 } | 1845 } |
1610 } | 1846 } |
1611 } | 1847 } |
1612 | 1848 |
1613 | 1849 |
1614 bool HPhi::IsRelationTrueInternal(NumericRelation relation, HValue* other) { | 1850 bool HPhi::IsRelationTrueInternal(NumericRelation relation, |
| 1851 HValue* other, |
| 1852 int offset, |
| 1853 int scale) { |
1615 if (CheckFlag(kNumericConstraintEvaluationInProgress)) return false; | 1854 if (CheckFlag(kNumericConstraintEvaluationInProgress)) return false; |
1616 | 1855 |
1617 SetFlag(kNumericConstraintEvaluationInProgress); | 1856 SetFlag(kNumericConstraintEvaluationInProgress); |
1618 bool result = true; | 1857 bool result = true; |
1619 for (int i = 0; i < OperandCount(); i++) { | 1858 for (int i = 0; i < OperandCount(); i++) { |
1620 // Skip OSR entry blocks | 1859 // Skip OSR entry blocks |
1621 if (OperandAt(i)->block()->is_osr_entry()) continue; | 1860 if (OperandAt(i)->block()->is_osr_entry()) continue; |
1622 | 1861 |
1623 if (!OperandAt(i)->IsRelationTrue(relation, other)) { | 1862 if (!OperandAt(i)->IsRelationTrue(relation, other, offset, scale)) { |
1624 result = false; | 1863 result = false; |
1625 break; | 1864 break; |
1626 } | 1865 } |
1627 } | 1866 } |
1628 ClearFlag(kNumericConstraintEvaluationInProgress); | 1867 ClearFlag(kNumericConstraintEvaluationInProgress); |
1629 | 1868 |
1630 return result; | 1869 return result; |
1631 } | 1870 } |
1632 | 1871 |
1633 | 1872 |
(...skipping 1645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3279 | 3518 |
3280 | 3519 |
3281 void HCheckFunction::Verify() { | 3520 void HCheckFunction::Verify() { |
3282 HInstruction::Verify(); | 3521 HInstruction::Verify(); |
3283 ASSERT(HasNoUses()); | 3522 ASSERT(HasNoUses()); |
3284 } | 3523 } |
3285 | 3524 |
3286 #endif | 3525 #endif |
3287 | 3526 |
3288 } } // namespace v8::internal | 3527 } } // namespace v8::internal |
OLD | NEW |