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