| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/crankshaft/hydrogen-instructions.h" | 5 #include "src/crankshaft/hydrogen-instructions.h" |
| 6 | 6 |
| 7 #include "src/base/bits.h" | 7 #include "src/base/bits.h" |
| 8 #include "src/base/safe_math.h" | 8 #include "src/base/safe_math.h" |
| 9 #include "src/crankshaft/hydrogen-infer-representation.h" | 9 #include "src/crankshaft/hydrogen-infer-representation.h" |
| 10 #include "src/double.h" | 10 #include "src/double.h" |
| (...skipping 757 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 768 | 768 |
| 769 bool HInstruction::CanDeoptimize() { | 769 bool HInstruction::CanDeoptimize() { |
| 770 switch (opcode()) { | 770 switch (opcode()) { |
| 771 case HValue::kAbnormalExit: | 771 case HValue::kAbnormalExit: |
| 772 case HValue::kAccessArgumentsAt: | 772 case HValue::kAccessArgumentsAt: |
| 773 case HValue::kAllocate: | 773 case HValue::kAllocate: |
| 774 case HValue::kArgumentsElements: | 774 case HValue::kArgumentsElements: |
| 775 case HValue::kArgumentsLength: | 775 case HValue::kArgumentsLength: |
| 776 case HValue::kArgumentsObject: | 776 case HValue::kArgumentsObject: |
| 777 case HValue::kBlockEntry: | 777 case HValue::kBlockEntry: |
| 778 case HValue::kBoundsCheckBaseIndexInformation: | |
| 779 case HValue::kCallNewArray: | 778 case HValue::kCallNewArray: |
| 780 case HValue::kCapturedObject: | 779 case HValue::kCapturedObject: |
| 781 case HValue::kClassOfTestAndBranch: | 780 case HValue::kClassOfTestAndBranch: |
| 782 case HValue::kCompareGeneric: | 781 case HValue::kCompareGeneric: |
| 783 case HValue::kCompareHoleAndBranch: | 782 case HValue::kCompareHoleAndBranch: |
| 784 case HValue::kCompareMap: | 783 case HValue::kCompareMap: |
| 785 case HValue::kCompareNumericAndBranch: | 784 case HValue::kCompareNumericAndBranch: |
| 786 case HValue::kCompareObjectEqAndBranch: | 785 case HValue::kCompareObjectEqAndBranch: |
| 787 case HValue::kConstant: | 786 case HValue::kConstant: |
| 788 case HValue::kConstructDouble: | 787 case HValue::kConstructDouble: |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 917 } | 916 } |
| 918 | 917 |
| 919 std::ostream& HInvokeFunction::PrintDataTo(std::ostream& os) const { // NOLINT | 918 std::ostream& HInvokeFunction::PrintDataTo(std::ostream& os) const { // NOLINT |
| 920 HBinaryCall::PrintDataTo(os); | 919 HBinaryCall::PrintDataTo(os); |
| 921 if (syntactic_tail_call_mode() == TailCallMode::kAllow) { | 920 if (syntactic_tail_call_mode() == TailCallMode::kAllow) { |
| 922 os << ", JSTailCall"; | 921 os << ", JSTailCall"; |
| 923 } | 922 } |
| 924 return os; | 923 return os; |
| 925 } | 924 } |
| 926 | 925 |
| 927 void HBoundsCheck::ApplyIndexChange() { | |
| 928 if (skip_check()) return; | |
| 929 | |
| 930 DecompositionResult decomposition; | |
| 931 bool index_is_decomposable = index()->TryDecompose(&decomposition); | |
| 932 if (index_is_decomposable) { | |
| 933 DCHECK(decomposition.base() == base()); | |
| 934 if (decomposition.offset() == offset() && | |
| 935 decomposition.scale() == scale()) return; | |
| 936 } else { | |
| 937 return; | |
| 938 } | |
| 939 | |
| 940 ReplaceAllUsesWith(index()); | |
| 941 | |
| 942 HValue* current_index = decomposition.base(); | |
| 943 int actual_offset = decomposition.offset() + offset(); | |
| 944 int actual_scale = decomposition.scale() + scale(); | |
| 945 | |
| 946 HGraph* graph = block()->graph(); | |
| 947 Isolate* isolate = graph->isolate(); | |
| 948 Zone* zone = graph->zone(); | |
| 949 HValue* context = graph->GetInvalidContext(); | |
| 950 if (actual_offset != 0) { | |
| 951 HConstant* add_offset = | |
| 952 HConstant::New(isolate, zone, context, actual_offset); | |
| 953 add_offset->InsertBefore(this); | |
| 954 HInstruction* add = | |
| 955 HAdd::New(isolate, zone, context, current_index, add_offset); | |
| 956 add->InsertBefore(this); | |
| 957 add->AssumeRepresentation(index()->representation()); | |
| 958 add->ClearFlag(kCanOverflow); | |
| 959 current_index = add; | |
| 960 } | |
| 961 | |
| 962 if (actual_scale != 0) { | |
| 963 HConstant* sar_scale = HConstant::New(isolate, zone, context, actual_scale); | |
| 964 sar_scale->InsertBefore(this); | |
| 965 HInstruction* sar = | |
| 966 HSar::New(isolate, zone, context, current_index, sar_scale); | |
| 967 sar->InsertBefore(this); | |
| 968 sar->AssumeRepresentation(index()->representation()); | |
| 969 current_index = sar; | |
| 970 } | |
| 971 | |
| 972 SetOperandAt(0, current_index); | |
| 973 | |
| 974 base_ = NULL; | |
| 975 offset_ = 0; | |
| 976 scale_ = 0; | |
| 977 } | |
| 978 | |
| 979 | |
| 980 std::ostream& HBoundsCheck::PrintDataTo(std::ostream& os) const { // NOLINT | 926 std::ostream& HBoundsCheck::PrintDataTo(std::ostream& os) const { // NOLINT |
| 981 os << NameOf(index()) << " " << NameOf(length()); | 927 os << NameOf(index()) << " " << NameOf(length()); |
| 982 if (base() != NULL && (offset() != 0 || scale() != 0)) { | 928 if (base() != NULL && (offset() != 0 || scale() != 0)) { |
| 983 os << " base: (("; | 929 os << " base: (("; |
| 984 if (base() != index()) { | 930 if (base() != index()) { |
| 985 os << NameOf(index()); | 931 os << NameOf(index()); |
| 986 } else { | 932 } else { |
| 987 os << "index"; | 933 os << "index"; |
| 988 } | 934 } |
| 989 os << " + " << offset() << ") >> " << scale() << ")"; | 935 os << " + " << offset() << ") >> " << scale() << ")"; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1025 } | 971 } |
| 1026 | 972 |
| 1027 // In case of Smi representation, clamp result to Smi::kMaxValue. | 973 // In case of Smi representation, clamp result to Smi::kMaxValue. |
| 1028 if (r.IsSmi()) result->ClampToSmi(); | 974 if (r.IsSmi()) result->ClampToSmi(); |
| 1029 return result; | 975 return result; |
| 1030 } | 976 } |
| 1031 return HValue::InferRange(zone); | 977 return HValue::InferRange(zone); |
| 1032 } | 978 } |
| 1033 | 979 |
| 1034 | 980 |
| 1035 std::ostream& HBoundsCheckBaseIndexInformation::PrintDataTo( | |
| 1036 std::ostream& os) const { // NOLINT | |
| 1037 // TODO(svenpanne) This 2nd base_index() looks wrong... | |
| 1038 return os << "base: " << NameOf(base_index()) | |
| 1039 << ", check: " << NameOf(base_index()); | |
| 1040 } | |
| 1041 | |
| 1042 | |
| 1043 std::ostream& HCallWithDescriptor::PrintDataTo( | 981 std::ostream& HCallWithDescriptor::PrintDataTo( |
| 1044 std::ostream& os) const { // NOLINT | 982 std::ostream& os) const { // NOLINT |
| 1045 for (int i = 0; i < OperandCount(); i++) { | 983 for (int i = 0; i < OperandCount(); i++) { |
| 1046 os << NameOf(OperandAt(i)) << " "; | 984 os << NameOf(OperandAt(i)) << " "; |
| 1047 } | 985 } |
| 1048 os << "#" << argument_count(); | 986 os << "#" << argument_count(); |
| 1049 if (syntactic_tail_call_mode() == TailCallMode::kAllow) { | 987 if (syntactic_tail_call_mode() == TailCallMode::kAllow) { |
| 1050 os << ", JSTailCall"; | 988 os << ", JSTailCall"; |
| 1051 } | 989 } |
| 1052 return os; | 990 return os; |
| (...skipping 903 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1956 if (!b->CanBeZero()) { | 1894 if (!b->CanBeZero()) { |
| 1957 ClearFlag(HValue::kCanBeDivByZero); | 1895 ClearFlag(HValue::kCanBeDivByZero); |
| 1958 } | 1896 } |
| 1959 return result; | 1897 return result; |
| 1960 } else { | 1898 } else { |
| 1961 return HValue::InferRange(zone); | 1899 return HValue::InferRange(zone); |
| 1962 } | 1900 } |
| 1963 } | 1901 } |
| 1964 | 1902 |
| 1965 | 1903 |
| 1966 InductionVariableData* InductionVariableData::ExaminePhi(HPhi* phi) { | |
| 1967 if (phi->block()->loop_information() == NULL) return NULL; | |
| 1968 if (phi->OperandCount() != 2) return NULL; | |
| 1969 int32_t candidate_increment; | |
| 1970 | |
| 1971 candidate_increment = ComputeIncrement(phi, phi->OperandAt(0)); | |
| 1972 if (candidate_increment != 0) { | |
| 1973 return new(phi->block()->graph()->zone()) | |
| 1974 InductionVariableData(phi, phi->OperandAt(1), candidate_increment); | |
| 1975 } | |
| 1976 | |
| 1977 candidate_increment = ComputeIncrement(phi, phi->OperandAt(1)); | |
| 1978 if (candidate_increment != 0) { | |
| 1979 return new(phi->block()->graph()->zone()) | |
| 1980 InductionVariableData(phi, phi->OperandAt(0), candidate_increment); | |
| 1981 } | |
| 1982 | |
| 1983 return NULL; | |
| 1984 } | |
| 1985 | |
| 1986 | |
| 1987 /* | |
| 1988 * This function tries to match the following patterns (and all the relevant | |
| 1989 * variants related to |, & and + being commutative): | |
| 1990 * base | constant_or_mask | |
| 1991 * base & constant_and_mask | |
| 1992 * (base + constant_offset) & constant_and_mask | |
| 1993 * (base - constant_offset) & constant_and_mask | |
| 1994 */ | |
| 1995 void InductionVariableData::DecomposeBitwise( | |
| 1996 HValue* value, | |
| 1997 BitwiseDecompositionResult* result) { | |
| 1998 HValue* base = IgnoreOsrValue(value); | |
| 1999 result->base = value; | |
| 2000 | |
| 2001 if (!base->representation().IsInteger32()) return; | |
| 2002 | |
| 2003 if (base->IsBitwise()) { | |
| 2004 bool allow_offset = false; | |
| 2005 int32_t mask = 0; | |
| 2006 | |
| 2007 HBitwise* bitwise = HBitwise::cast(base); | |
| 2008 if (bitwise->right()->IsInteger32Constant()) { | |
| 2009 mask = bitwise->right()->GetInteger32Constant(); | |
| 2010 base = bitwise->left(); | |
| 2011 } else if (bitwise->left()->IsInteger32Constant()) { | |
| 2012 mask = bitwise->left()->GetInteger32Constant(); | |
| 2013 base = bitwise->right(); | |
| 2014 } else { | |
| 2015 return; | |
| 2016 } | |
| 2017 if (bitwise->op() == Token::BIT_AND) { | |
| 2018 result->and_mask = mask; | |
| 2019 allow_offset = true; | |
| 2020 } else if (bitwise->op() == Token::BIT_OR) { | |
| 2021 result->or_mask = mask; | |
| 2022 } else { | |
| 2023 return; | |
| 2024 } | |
| 2025 | |
| 2026 result->context = bitwise->context(); | |
| 2027 | |
| 2028 if (allow_offset) { | |
| 2029 if (base->IsAdd()) { | |
| 2030 HAdd* add = HAdd::cast(base); | |
| 2031 if (add->right()->IsInteger32Constant()) { | |
| 2032 base = add->left(); | |
| 2033 } else if (add->left()->IsInteger32Constant()) { | |
| 2034 base = add->right(); | |
| 2035 } | |
| 2036 } else if (base->IsSub()) { | |
| 2037 HSub* sub = HSub::cast(base); | |
| 2038 if (sub->right()->IsInteger32Constant()) { | |
| 2039 base = sub->left(); | |
| 2040 } | |
| 2041 } | |
| 2042 } | |
| 2043 | |
| 2044 result->base = base; | |
| 2045 } | |
| 2046 } | |
| 2047 | |
| 2048 | |
| 2049 void InductionVariableData::AddCheck(HBoundsCheck* check, | |
| 2050 int32_t upper_limit) { | |
| 2051 DCHECK(limit_validity() != NULL); | |
| 2052 if (limit_validity() != check->block() && | |
| 2053 !limit_validity()->Dominates(check->block())) return; | |
| 2054 if (!phi()->block()->current_loop()->IsNestedInThisLoop( | |
| 2055 check->block()->current_loop())) return; | |
| 2056 | |
| 2057 ChecksRelatedToLength* length_checks = checks(); | |
| 2058 while (length_checks != NULL) { | |
| 2059 if (length_checks->length() == check->length()) break; | |
| 2060 length_checks = length_checks->next(); | |
| 2061 } | |
| 2062 if (length_checks == NULL) { | |
| 2063 length_checks = new(check->block()->zone()) | |
| 2064 ChecksRelatedToLength(check->length(), checks()); | |
| 2065 checks_ = length_checks; | |
| 2066 } | |
| 2067 | |
| 2068 length_checks->AddCheck(check, upper_limit); | |
| 2069 } | |
| 2070 | |
| 2071 | |
| 2072 void InductionVariableData::ChecksRelatedToLength::CloseCurrentBlock() { | |
| 2073 if (checks() != NULL) { | |
| 2074 InductionVariableCheck* c = checks(); | |
| 2075 HBasicBlock* current_block = c->check()->block(); | |
| 2076 while (c != NULL && c->check()->block() == current_block) { | |
| 2077 c->set_upper_limit(current_upper_limit_); | |
| 2078 c = c->next(); | |
| 2079 } | |
| 2080 } | |
| 2081 } | |
| 2082 | |
| 2083 | |
| 2084 void InductionVariableData::ChecksRelatedToLength::UseNewIndexInCurrentBlock( | |
| 2085 Token::Value token, | |
| 2086 int32_t mask, | |
| 2087 HValue* index_base, | |
| 2088 HValue* context) { | |
| 2089 DCHECK(first_check_in_block() != NULL); | |
| 2090 HValue* previous_index = first_check_in_block()->index(); | |
| 2091 DCHECK(context != NULL); | |
| 2092 | |
| 2093 Zone* zone = index_base->block()->graph()->zone(); | |
| 2094 Isolate* isolate = index_base->block()->graph()->isolate(); | |
| 2095 set_added_constant(HConstant::New(isolate, zone, context, mask)); | |
| 2096 if (added_index() != NULL) { | |
| 2097 added_constant()->InsertBefore(added_index()); | |
| 2098 } else { | |
| 2099 added_constant()->InsertBefore(first_check_in_block()); | |
| 2100 } | |
| 2101 | |
| 2102 if (added_index() == NULL) { | |
| 2103 first_check_in_block()->ReplaceAllUsesWith(first_check_in_block()->index()); | |
| 2104 HInstruction* new_index = HBitwise::New(isolate, zone, context, token, | |
| 2105 index_base, added_constant()); | |
| 2106 DCHECK(new_index->IsBitwise()); | |
| 2107 new_index->ClearAllSideEffects(); | |
| 2108 new_index->AssumeRepresentation(Representation::Integer32()); | |
| 2109 set_added_index(HBitwise::cast(new_index)); | |
| 2110 added_index()->InsertBefore(first_check_in_block()); | |
| 2111 } | |
| 2112 DCHECK(added_index()->op() == token); | |
| 2113 | |
| 2114 added_index()->SetOperandAt(1, index_base); | |
| 2115 added_index()->SetOperandAt(2, added_constant()); | |
| 2116 first_check_in_block()->SetOperandAt(0, added_index()); | |
| 2117 if (previous_index->HasNoUses()) { | |
| 2118 previous_index->DeleteAndReplaceWith(NULL); | |
| 2119 } | |
| 2120 } | |
| 2121 | |
| 2122 void InductionVariableData::ChecksRelatedToLength::AddCheck( | |
| 2123 HBoundsCheck* check, | |
| 2124 int32_t upper_limit) { | |
| 2125 BitwiseDecompositionResult decomposition; | |
| 2126 InductionVariableData::DecomposeBitwise(check->index(), &decomposition); | |
| 2127 | |
| 2128 if (first_check_in_block() == NULL || | |
| 2129 first_check_in_block()->block() != check->block()) { | |
| 2130 CloseCurrentBlock(); | |
| 2131 | |
| 2132 first_check_in_block_ = check; | |
| 2133 set_added_index(NULL); | |
| 2134 set_added_constant(NULL); | |
| 2135 current_and_mask_in_block_ = decomposition.and_mask; | |
| 2136 current_or_mask_in_block_ = decomposition.or_mask; | |
| 2137 current_upper_limit_ = upper_limit; | |
| 2138 | |
| 2139 InductionVariableCheck* new_check = new(check->block()->graph()->zone()) | |
| 2140 InductionVariableCheck(check, checks_, upper_limit); | |
| 2141 checks_ = new_check; | |
| 2142 return; | |
| 2143 } | |
| 2144 | |
| 2145 if (upper_limit > current_upper_limit()) { | |
| 2146 current_upper_limit_ = upper_limit; | |
| 2147 } | |
| 2148 | |
| 2149 if (decomposition.and_mask != 0 && | |
| 2150 current_or_mask_in_block() == 0) { | |
| 2151 if (current_and_mask_in_block() == 0 || | |
| 2152 decomposition.and_mask > current_and_mask_in_block()) { | |
| 2153 UseNewIndexInCurrentBlock(Token::BIT_AND, | |
| 2154 decomposition.and_mask, | |
| 2155 decomposition.base, | |
| 2156 decomposition.context); | |
| 2157 current_and_mask_in_block_ = decomposition.and_mask; | |
| 2158 } | |
| 2159 check->set_skip_check(); | |
| 2160 } | |
| 2161 if (current_and_mask_in_block() == 0) { | |
| 2162 if (decomposition.or_mask > current_or_mask_in_block()) { | |
| 2163 UseNewIndexInCurrentBlock(Token::BIT_OR, | |
| 2164 decomposition.or_mask, | |
| 2165 decomposition.base, | |
| 2166 decomposition.context); | |
| 2167 current_or_mask_in_block_ = decomposition.or_mask; | |
| 2168 } | |
| 2169 check->set_skip_check(); | |
| 2170 } | |
| 2171 | |
| 2172 if (!check->skip_check()) { | |
| 2173 InductionVariableCheck* new_check = new(check->block()->graph()->zone()) | |
| 2174 InductionVariableCheck(check, checks_, upper_limit); | |
| 2175 checks_ = new_check; | |
| 2176 } | |
| 2177 } | |
| 2178 | |
| 2179 | |
| 2180 /* | |
| 2181 * This method detects if phi is an induction variable, with phi_operand as | |
| 2182 * its "incremented" value (the other operand would be the "base" value). | |
| 2183 * | |
| 2184 * It cheks is phi_operand has the form "phi + constant". | |
| 2185 * If yes, the constant is the increment that the induction variable gets at | |
| 2186 * every loop iteration. | |
| 2187 * Otherwise it returns 0. | |
| 2188 */ | |
| 2189 int32_t InductionVariableData::ComputeIncrement(HPhi* phi, | |
| 2190 HValue* phi_operand) { | |
| 2191 if (!phi_operand->representation().IsSmiOrInteger32()) return 0; | |
| 2192 | |
| 2193 if (phi_operand->IsAdd()) { | |
| 2194 HAdd* operation = HAdd::cast(phi_operand); | |
| 2195 if (operation->left() == phi && | |
| 2196 operation->right()->IsInteger32Constant()) { | |
| 2197 return operation->right()->GetInteger32Constant(); | |
| 2198 } else if (operation->right() == phi && | |
| 2199 operation->left()->IsInteger32Constant()) { | |
| 2200 return operation->left()->GetInteger32Constant(); | |
| 2201 } | |
| 2202 } else if (phi_operand->IsSub()) { | |
| 2203 HSub* operation = HSub::cast(phi_operand); | |
| 2204 if (operation->left() == phi && | |
| 2205 operation->right()->IsInteger32Constant()) { | |
| 2206 int constant = operation->right()->GetInteger32Constant(); | |
| 2207 if (constant == kMinInt) return 0; | |
| 2208 return -constant; | |
| 2209 } | |
| 2210 } | |
| 2211 | |
| 2212 return 0; | |
| 2213 } | |
| 2214 | |
| 2215 | |
| 2216 /* | |
| 2217 * Swaps the information in "update" with the one contained in "this". | |
| 2218 * The swapping is important because this method is used while doing a | |
| 2219 * dominator tree traversal, and "update" will retain the old data that | |
| 2220 * will be restored while backtracking. | |
| 2221 */ | |
| 2222 void InductionVariableData::UpdateAdditionalLimit( | |
| 2223 InductionVariableLimitUpdate* update) { | |
| 2224 DCHECK(update->updated_variable == this); | |
| 2225 if (update->limit_is_upper) { | |
| 2226 swap(&additional_upper_limit_, &update->limit); | |
| 2227 swap(&additional_upper_limit_is_included_, &update->limit_is_included); | |
| 2228 } else { | |
| 2229 swap(&additional_lower_limit_, &update->limit); | |
| 2230 swap(&additional_lower_limit_is_included_, &update->limit_is_included); | |
| 2231 } | |
| 2232 } | |
| 2233 | |
| 2234 | |
| 2235 int32_t InductionVariableData::ComputeUpperLimit(int32_t and_mask, | |
| 2236 int32_t or_mask) { | |
| 2237 // Should be Smi::kMaxValue but it must fit 32 bits; lower is safe anyway. | |
| 2238 const int32_t MAX_LIMIT = 1 << 30; | |
| 2239 | |
| 2240 int32_t result = MAX_LIMIT; | |
| 2241 | |
| 2242 if (limit() != NULL && | |
| 2243 limit()->IsInteger32Constant()) { | |
| 2244 int32_t limit_value = limit()->GetInteger32Constant(); | |
| 2245 if (!limit_included()) { | |
| 2246 limit_value--; | |
| 2247 } | |
| 2248 if (limit_value < result) result = limit_value; | |
| 2249 } | |
| 2250 | |
| 2251 if (additional_upper_limit() != NULL && | |
| 2252 additional_upper_limit()->IsInteger32Constant()) { | |
| 2253 int32_t limit_value = additional_upper_limit()->GetInteger32Constant(); | |
| 2254 if (!additional_upper_limit_is_included()) { | |
| 2255 limit_value--; | |
| 2256 } | |
| 2257 if (limit_value < result) result = limit_value; | |
| 2258 } | |
| 2259 | |
| 2260 if (and_mask > 0 && and_mask < MAX_LIMIT) { | |
| 2261 if (and_mask < result) result = and_mask; | |
| 2262 return result; | |
| 2263 } | |
| 2264 | |
| 2265 // Add the effect of the or_mask. | |
| 2266 result |= or_mask; | |
| 2267 | |
| 2268 return result >= MAX_LIMIT ? kNoLimit : result; | |
| 2269 } | |
| 2270 | |
| 2271 | |
| 2272 HValue* InductionVariableData::IgnoreOsrValue(HValue* v) { | |
| 2273 if (!v->IsPhi()) return v; | |
| 2274 HPhi* phi = HPhi::cast(v); | |
| 2275 if (phi->OperandCount() != 2) return v; | |
| 2276 if (phi->OperandAt(0)->block()->is_osr_entry()) { | |
| 2277 return phi->OperandAt(1); | |
| 2278 } else if (phi->OperandAt(1)->block()->is_osr_entry()) { | |
| 2279 return phi->OperandAt(0); | |
| 2280 } else { | |
| 2281 return v; | |
| 2282 } | |
| 2283 } | |
| 2284 | |
| 2285 | |
| 2286 InductionVariableData* InductionVariableData::GetInductionVariableData( | |
| 2287 HValue* v) { | |
| 2288 v = IgnoreOsrValue(v); | |
| 2289 if (v->IsPhi()) { | |
| 2290 return HPhi::cast(v)->induction_variable_data(); | |
| 2291 } | |
| 2292 return NULL; | |
| 2293 } | |
| 2294 | |
| 2295 | |
| 2296 /* | |
| 2297 * Check if a conditional branch to "current_branch" with token "token" is | |
| 2298 * the branch that keeps the induction loop running (and, conversely, will | |
| 2299 * terminate it if the "other_branch" is taken). | |
| 2300 * | |
| 2301 * Three conditions must be met: | |
| 2302 * - "current_branch" must be in the induction loop. | |
| 2303 * - "other_branch" must be out of the induction loop. | |
| 2304 * - "token" and the induction increment must be "compatible": the token should | |
| 2305 * be a condition that keeps the execution inside the loop until the limit is | |
| 2306 * reached. | |
| 2307 */ | |
| 2308 bool InductionVariableData::CheckIfBranchIsLoopGuard( | |
| 2309 Token::Value token, | |
| 2310 HBasicBlock* current_branch, | |
| 2311 HBasicBlock* other_branch) { | |
| 2312 if (!phi()->block()->current_loop()->IsNestedInThisLoop( | |
| 2313 current_branch->current_loop())) { | |
| 2314 return false; | |
| 2315 } | |
| 2316 | |
| 2317 if (phi()->block()->current_loop()->IsNestedInThisLoop( | |
| 2318 other_branch->current_loop())) { | |
| 2319 return false; | |
| 2320 } | |
| 2321 | |
| 2322 if (increment() > 0 && (token == Token::LT || token == Token::LTE)) { | |
| 2323 return true; | |
| 2324 } | |
| 2325 if (increment() < 0 && (token == Token::GT || token == Token::GTE)) { | |
| 2326 return true; | |
| 2327 } | |
| 2328 if (Token::IsInequalityOp(token) && (increment() == 1 || increment() == -1)) { | |
| 2329 return true; | |
| 2330 } | |
| 2331 | |
| 2332 return false; | |
| 2333 } | |
| 2334 | |
| 2335 | |
| 2336 void InductionVariableData::ComputeLimitFromPredecessorBlock( | |
| 2337 HBasicBlock* block, | |
| 2338 LimitFromPredecessorBlock* result) { | |
| 2339 if (block->predecessors()->length() != 1) return; | |
| 2340 HBasicBlock* predecessor = block->predecessors()->at(0); | |
| 2341 HInstruction* end = predecessor->last(); | |
| 2342 | |
| 2343 if (!end->IsCompareNumericAndBranch()) return; | |
| 2344 HCompareNumericAndBranch* branch = HCompareNumericAndBranch::cast(end); | |
| 2345 | |
| 2346 Token::Value token = branch->token(); | |
| 2347 if (!Token::IsArithmeticCompareOp(token)) return; | |
| 2348 | |
| 2349 HBasicBlock* other_target; | |
| 2350 if (block == branch->SuccessorAt(0)) { | |
| 2351 other_target = branch->SuccessorAt(1); | |
| 2352 } else { | |
| 2353 other_target = branch->SuccessorAt(0); | |
| 2354 token = Token::NegateCompareOp(token); | |
| 2355 DCHECK(block == branch->SuccessorAt(1)); | |
| 2356 } | |
| 2357 | |
| 2358 InductionVariableData* data; | |
| 2359 | |
| 2360 data = GetInductionVariableData(branch->left()); | |
| 2361 HValue* limit = branch->right(); | |
| 2362 if (data == NULL) { | |
| 2363 data = GetInductionVariableData(branch->right()); | |
| 2364 token = Token::ReverseCompareOp(token); | |
| 2365 limit = branch->left(); | |
| 2366 } | |
| 2367 | |
| 2368 if (data != NULL) { | |
| 2369 result->variable = data; | |
| 2370 result->token = token; | |
| 2371 result->limit = limit; | |
| 2372 result->other_target = other_target; | |
| 2373 } | |
| 2374 } | |
| 2375 | |
| 2376 | |
| 2377 /* | |
| 2378 * Compute the limit that is imposed on an induction variable when entering | |
| 2379 * "block" (if any). | |
| 2380 * If the limit is the "proper" induction limit (the one that makes the loop | |
| 2381 * terminate when the induction variable reaches it) it is stored directly in | |
| 2382 * the induction variable data. | |
| 2383 * Otherwise the limit is written in "additional_limit" and the method | |
| 2384 * returns true. | |
| 2385 */ | |
| 2386 bool InductionVariableData::ComputeInductionVariableLimit( | |
| 2387 HBasicBlock* block, | |
| 2388 InductionVariableLimitUpdate* additional_limit) { | |
| 2389 LimitFromPredecessorBlock limit; | |
| 2390 ComputeLimitFromPredecessorBlock(block, &limit); | |
| 2391 if (!limit.LimitIsValid()) return false; | |
| 2392 | |
| 2393 if (limit.variable->CheckIfBranchIsLoopGuard(limit.token, | |
| 2394 block, | |
| 2395 limit.other_target)) { | |
| 2396 limit.variable->limit_ = limit.limit; | |
| 2397 limit.variable->limit_included_ = limit.LimitIsIncluded(); | |
| 2398 limit.variable->limit_validity_ = block; | |
| 2399 limit.variable->induction_exit_block_ = block->predecessors()->at(0); | |
| 2400 limit.variable->induction_exit_target_ = limit.other_target; | |
| 2401 return false; | |
| 2402 } else { | |
| 2403 additional_limit->updated_variable = limit.variable; | |
| 2404 additional_limit->limit = limit.limit; | |
| 2405 additional_limit->limit_is_upper = limit.LimitIsUpper(); | |
| 2406 additional_limit->limit_is_included = limit.LimitIsIncluded(); | |
| 2407 return true; | |
| 2408 } | |
| 2409 } | |
| 2410 | |
| 2411 | |
| 2412 Range* HMathMinMax::InferRange(Zone* zone) { | 1904 Range* HMathMinMax::InferRange(Zone* zone) { |
| 2413 if (representation().IsSmiOrInteger32()) { | 1905 if (representation().IsSmiOrInteger32()) { |
| 2414 Range* a = left()->range(); | 1906 Range* a = left()->range(); |
| 2415 Range* b = right()->range(); | 1907 Range* b = right()->range(); |
| 2416 Range* res = a->Copy(zone); | 1908 Range* res = a->Copy(zone); |
| 2417 if (operation_ == kMathMax) { | 1909 if (operation_ == kMathMax) { |
| 2418 res->CombinedMax(b); | 1910 res->CombinedMax(b); |
| 2419 } else { | 1911 } else { |
| 2420 DCHECK(operation_ == kMathMin); | 1912 DCHECK(operation_ == kMathMin); |
| 2421 res->CombinedMin(b); | 1913 res->CombinedMin(b); |
| (...skipping 2215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4637 case HObjectAccess::kExternalMemory: | 4129 case HObjectAccess::kExternalMemory: |
| 4638 os << "[external-memory]"; | 4130 os << "[external-memory]"; |
| 4639 break; | 4131 break; |
| 4640 } | 4132 } |
| 4641 | 4133 |
| 4642 return os << "@" << access.offset(); | 4134 return os << "@" << access.offset(); |
| 4643 } | 4135 } |
| 4644 | 4136 |
| 4645 } // namespace internal | 4137 } // namespace internal |
| 4646 } // namespace v8 | 4138 } // namespace v8 |
| OLD | NEW |