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 1015 matching lines...) Loading... | |
1026 if (context->upper_bound() == length() && | 1026 if (context->upper_bound() == length() && |
1027 context->lower_bound_guarantee() != NULL && | 1027 context->lower_bound_guarantee() != NULL && |
1028 context->lower_bound_guarantee() != this && | 1028 context->lower_bound_guarantee() != this && |
1029 context->lower_bound_guarantee()->block() != block() && | 1029 context->lower_bound_guarantee()->block() != block() && |
1030 offset() < context->offset() && | 1030 offset() < context->offset() && |
1031 index_can_increase() && | 1031 index_can_increase() && |
1032 context->upper_bound_guarantee() == NULL) { | 1032 context->upper_bound_guarantee() == NULL) { |
1033 offset_ = context->offset(); | 1033 offset_ = context->offset(); |
1034 SetResponsibilityForRange(DIRECTION_UPPER); | 1034 SetResponsibilityForRange(DIRECTION_UPPER); |
1035 context->set_upper_bound_guarantee(this); | 1035 context->set_upper_bound_guarantee(this); |
1036 isolate()->counters()->bounds_checks_covered()->Increment(); | |
1036 } else if (context->upper_bound_guarantee() != NULL && | 1037 } else if (context->upper_bound_guarantee() != NULL && |
1037 context->upper_bound_guarantee() != this && | 1038 context->upper_bound_guarantee() != this && |
1038 context->upper_bound_guarantee()->block() != block() && | 1039 context->upper_bound_guarantee()->block() != block() && |
1039 offset() > context->offset() && | 1040 offset() > context->offset() && |
1040 index_can_decrease() && | 1041 index_can_decrease() && |
1041 context->lower_bound_guarantee() == NULL) { | 1042 context->lower_bound_guarantee() == NULL) { |
1042 offset_ = context->offset(); | 1043 offset_ = context->offset(); |
1043 SetResponsibilityForRange(DIRECTION_LOWER); | 1044 SetResponsibilityForRange(DIRECTION_LOWER); |
1044 context->set_lower_bound_guarantee(this); | 1045 context->set_lower_bound_guarantee(this); |
1046 isolate()->counters()->bounds_checks_covered()->Increment(); | |
1045 } | 1047 } |
1046 } | 1048 } |
1047 | 1049 |
1048 | 1050 |
1049 void HBoundsCheck::ApplyIndexChange() { | 1051 void HBoundsCheck::ApplyIndexChange() { |
1050 if (skip_check()) return; | 1052 if (skip_check()) return; |
1051 | 1053 |
1052 DecompositionResult decomposition; | 1054 DecompositionResult decomposition; |
1053 bool index_is_decomposable = index()->TryDecompose(&decomposition); | 1055 bool index_is_decomposable = index()->TryDecompose(&decomposition); |
1054 if (index_is_decomposable) { | 1056 if (index_is_decomposable) { |
(...skipping 40 matching lines...) Loading... | |
1095 scale_ = 0; | 1097 scale_ = 0; |
1096 responsibility_direction_ = DIRECTION_NONE; | 1098 responsibility_direction_ = DIRECTION_NONE; |
1097 } | 1099 } |
1098 | 1100 |
1099 | 1101 |
1100 void HBoundsCheck::AddInformativeDefinitions() { | 1102 void HBoundsCheck::AddInformativeDefinitions() { |
1101 // TODO(mmassi): Executing this code during AddInformativeDefinitions | 1103 // TODO(mmassi): Executing this code during AddInformativeDefinitions |
1102 // is a hack. Move it to some other HPhase. | 1104 // is a hack. Move it to some other HPhase. |
1103 if (FLAG_array_bounds_checks_elimination) { | 1105 if (FLAG_array_bounds_checks_elimination) { |
1104 if (index()->TryGuaranteeRange(length())) { | 1106 if (index()->TryGuaranteeRange(length())) { |
1105 set_skip_check(true); | 1107 set_skip_check(); |
1106 } | 1108 } |
1107 if (DetectCompoundIndex()) { | 1109 if (DetectCompoundIndex()) { |
1108 HBoundsCheckBaseIndexInformation* base_index_info = | 1110 HBoundsCheckBaseIndexInformation* base_index_info = |
1109 new(block()->graph()->zone()) | 1111 new(block()->graph()->zone()) |
1110 HBoundsCheckBaseIndexInformation(this); | 1112 HBoundsCheckBaseIndexInformation(this); |
1111 base_index_info->InsertAfter(this); | 1113 base_index_info->InsertAfter(this); |
1112 } | 1114 } |
1113 } | 1115 } |
1114 } | 1116 } |
1115 | 1117 |
(...skipping 825 matching lines...) Loading... | |
1941 result = false; | 1943 result = false; |
1942 break; | 1944 break; |
1943 } | 1945 } |
1944 } | 1946 } |
1945 ClearFlag(kNumericConstraintEvaluationInProgress); | 1947 ClearFlag(kNumericConstraintEvaluationInProgress); |
1946 | 1948 |
1947 return result; | 1949 return result; |
1948 } | 1950 } |
1949 | 1951 |
1950 | 1952 |
1953 InductionVariableData* InductionVariableData::ExaminePhi(HPhi* phi) { | |
1954 if (phi->block()->loop_information() == NULL) return NULL; | |
1955 if (phi->OperandCount() != 2) return NULL; | |
1956 int32_t candidate_increment; | |
1957 | |
1958 candidate_increment = ComputeIncrement(phi, phi->OperandAt(0)); | |
1959 if (candidate_increment != 0) { | |
1960 return new(phi->block()->graph()->zone()) | |
1961 InductionVariableData(phi, phi->OperandAt(1), candidate_increment); | |
1962 } | |
1963 | |
1964 candidate_increment = ComputeIncrement(phi, phi->OperandAt(1)); | |
1965 if (candidate_increment != 0) { | |
1966 return new(phi->block()->graph()->zone()) | |
1967 InductionVariableData(phi, phi->OperandAt(0), candidate_increment); | |
1968 } | |
1969 | |
1970 return NULL; | |
1971 } | |
1972 | |
1973 /* | |
1974 * This function tries to match the following patterns (and all the relevant | |
1975 * variants related to |, & and + being commutative): | |
1976 * base | or_mask | |
1977 * base & and_mask | |
1978 * (base + constant_offset) & and_mask | |
1979 * (base - constant_offset) & and_mask | |
1980 */ | |
1981 void InductionVariableData::DecomposeBitwise( | |
1982 HValue* value, | |
1983 BitwiseDecompositionResult* result) { | |
1984 HValue* current = IgnoreOsrValue(value); | |
1985 bool has_offset = false; | |
1986 result->base = value; | |
titzer
2013/07/10 16:34:18
Thanks for the comment; now that I understand the
Massi
2013/07/11 11:15:22
Done.
| |
1987 | |
1988 if (!current->representation().IsInteger32()) return; | |
1989 | |
1990 while (true) { | |
1991 if (current->IsAdd()) { | |
1992 if (result->and_mask != 0 || result->or_mask != 0) return; | |
1993 HAdd* operation = HAdd::cast(current); | |
1994 if (operation->right()->IsInteger32Constant()) { | |
1995 has_offset = true; | |
1996 current = operation->left(); | |
1997 } else if (operation->left()->IsInteger32Constant()) { | |
1998 has_offset = true; | |
1999 current = operation->right(); | |
2000 } else { | |
2001 return; | |
2002 } | |
2003 continue; | |
2004 } else if (current->IsSub()) { | |
2005 if (result->and_mask != 0 || result->or_mask != 0) return; | |
2006 HSub* operation = HSub::cast(current); | |
2007 if (operation->right()->IsInteger32Constant()) { | |
2008 has_offset = true; | |
2009 current = operation->left(); | |
2010 } else { | |
2011 return; | |
2012 } | |
2013 continue; | |
2014 } else if (current->IsBitwise()) { | |
2015 HBitwise* operation = HBitwise::cast(current); | |
2016 int32_t* mask = NULL; | |
2017 if (operation->op() == Token::BIT_AND) { | |
2018 mask = &(result->and_mask); | |
2019 } else if (operation->op() == Token::BIT_OR) { | |
2020 if (has_offset) { | |
2021 return; | |
2022 } | |
2023 mask = &(result->or_mask); | |
2024 } else { | |
2025 return; | |
2026 } | |
2027 if (operation->right()->IsInteger32Constant()) { | |
2028 *mask = operation->right()->GetInteger32Constant(); | |
2029 current = operation->left(); | |
2030 } else if (operation->left()->IsInteger32Constant()) { | |
2031 *mask = operation->left()->GetInteger32Constant(); | |
2032 current = operation->right(); | |
2033 } | |
2034 result->context = operation->context(); | |
2035 result->base = current; | |
2036 return; | |
2037 } else { | |
2038 return; | |
2039 } | |
2040 } | |
2041 | |
2042 return; | |
2043 } | |
2044 | |
2045 | |
2046 void InductionVariableData::AddCheck(HBoundsCheck* check, | |
2047 int32_t upper_limit) { | |
2048 ASSERT(limit_validity() != NULL); | |
2049 if (limit_validity() != check->block() && | |
2050 !limit_validity()->Dominates(check->block())) return; | |
2051 if (!phi()->block()->current_loop()->IsNestedInThisLoop( | |
2052 check->block()->current_loop())) return; | |
2053 | |
2054 ChecksRelatedToLength* length_checks = checks(); | |
2055 while (length_checks != NULL) { | |
2056 if (length_checks->length() == check->length()) break; | |
2057 length_checks = length_checks->next(); | |
2058 } | |
2059 if (length_checks == NULL) { | |
2060 length_checks = new(check->block()->zone()) | |
2061 ChecksRelatedToLength(check->length(), checks()); | |
2062 checks_ = length_checks; | |
2063 } | |
2064 | |
2065 length_checks->AddCheck(check, upper_limit); | |
2066 } | |
2067 | |
2068 void InductionVariableData::ChecksRelatedToLength::CloseCurrentBlock() { | |
2069 if (checks() != NULL) { | |
2070 InductionVariableCheck* c = checks(); | |
2071 HBasicBlock* current_block = c->check()->block(); | |
2072 while (c != NULL && c->check()->block() == current_block) { | |
2073 c->set_upper_limit(current_upper_limit_); | |
2074 c = c->next(); | |
2075 } | |
2076 } | |
2077 } | |
2078 | |
2079 | |
2080 void InductionVariableData::ChecksRelatedToLength::UseNewIndexInCurrentBlock( | |
2081 Token::Value token, | |
2082 int32_t mask, | |
2083 HValue* index_base, | |
2084 HValue* context) { | |
2085 ASSERT(first_check_in_block() != NULL); | |
2086 HValue* previous_index = first_check_in_block()->index(); | |
2087 ASSERT(context != NULL); | |
2088 | |
2089 set_added_constant(new(index_base->block()->graph()->zone()) HConstant( | |
2090 mask, index_base->representation())); | |
2091 if (added_index() != NULL) { | |
2092 added_constant()->InsertBefore(added_index()); | |
2093 } else { | |
2094 added_constant()->InsertBefore(first_check_in_block()); | |
2095 } | |
2096 | |
2097 if (added_index() == NULL) { | |
2098 first_check_in_block()->ReplaceAllUsesWith(first_check_in_block()->index()); | |
2099 HInstruction* new_index = HBitwise::New( | |
2100 index_base->block()->graph()->zone(), | |
2101 token, context, index_base, added_constant()); | |
2102 ASSERT(new_index->IsBitwise()); | |
2103 new_index->ClearAllSideEffects(); | |
2104 new_index->AssumeRepresentation(Representation::Integer32()); | |
2105 set_added_index(HBitwise::cast(new_index)); | |
2106 added_index()->InsertBefore(first_check_in_block()); | |
2107 } | |
2108 ASSERT(added_index()->op() == token); | |
2109 | |
2110 added_index()->SetOperandAt(1, index_base); | |
2111 added_index()->SetOperandAt(2, added_constant()); | |
2112 first_check_in_block()->SetOperandAt(0, added_index()); | |
2113 if (previous_index->UseCount() == 0) { | |
2114 previous_index->DeleteAndReplaceWith(NULL); | |
2115 } | |
2116 } | |
2117 | |
2118 void InductionVariableData::ChecksRelatedToLength::AddCheck( | |
2119 HBoundsCheck* check, | |
2120 int32_t upper_limit) { | |
2121 BitwiseDecompositionResult decomposition; | |
2122 InductionVariableData::DecomposeBitwise(check->index(), &decomposition); | |
2123 | |
2124 if (first_check_in_block() == NULL || | |
2125 first_check_in_block()->block() != check->block()) { | |
2126 CloseCurrentBlock(); | |
2127 | |
2128 first_check_in_block_ = check; | |
2129 set_added_index(NULL); | |
2130 set_added_constant(NULL); | |
2131 current_and_mask_in_block_ = decomposition.and_mask; | |
2132 current_or_mask_in_block_ = decomposition.or_mask; | |
2133 current_upper_limit_ = upper_limit; | |
2134 | |
2135 InductionVariableCheck* new_check = new(check->block()->graph()->zone()) | |
2136 InductionVariableCheck(check, checks_, upper_limit); | |
2137 checks_ = new_check; | |
2138 return; | |
2139 } | |
2140 | |
2141 if (upper_limit > current_upper_limit()) { | |
2142 current_upper_limit_ = upper_limit; | |
2143 } | |
2144 | |
2145 if (decomposition.and_mask != 0 && | |
2146 current_or_mask_in_block() == 0) { | |
2147 if (current_and_mask_in_block() == 0 || | |
2148 decomposition.and_mask > current_and_mask_in_block()) { | |
2149 UseNewIndexInCurrentBlock(Token::BIT_AND, | |
2150 decomposition.and_mask, | |
2151 decomposition.base, | |
2152 decomposition.context); | |
2153 current_and_mask_in_block_ = decomposition.and_mask; | |
2154 } | |
2155 check->set_skip_check(); | |
2156 } | |
2157 if (current_and_mask_in_block() == 0) { | |
2158 if (decomposition.or_mask > current_or_mask_in_block()) { | |
2159 UseNewIndexInCurrentBlock(Token::BIT_OR, | |
2160 decomposition.or_mask, | |
2161 decomposition.base, | |
2162 decomposition.context); | |
2163 current_or_mask_in_block_ = decomposition.or_mask; | |
2164 } | |
2165 check->set_skip_check(); | |
2166 } | |
2167 | |
2168 if (!check->skip_check()) { | |
2169 InductionVariableCheck* new_check = new(check->block()->graph()->zone()) | |
2170 InductionVariableCheck(check, checks_, upper_limit); | |
2171 checks_ = new_check; | |
2172 } | |
2173 } | |
2174 | |
2175 | |
2176 /* | |
2177 * This method detects if phi is an induction variable, with phi_operand as | |
2178 * its "incremented" value (the other operand would be the "base" value). | |
2179 * | |
2180 * It cheks is phi_operand has the form "phi + constant". | |
2181 * If yes, the constant is the increment that the induction variable gets at | |
2182 * every loop iteration. | |
2183 * Otherwise it returns 0. | |
2184 */ | |
2185 int32_t InductionVariableData::ComputeIncrement(HPhi* phi, | |
2186 HValue* phi_operand) { | |
2187 if (!phi_operand->representation().IsInteger32()) return 0; | |
2188 | |
2189 if (phi_operand->IsAdd()) { | |
2190 HAdd* operation = HAdd::cast(phi_operand); | |
2191 if (operation->left() == phi && | |
2192 operation->right()->IsInteger32Constant()) { | |
2193 return operation->right()->GetInteger32Constant(); | |
2194 } else if (operation->right() == phi && | |
2195 operation->left()->IsInteger32Constant()) { | |
2196 return operation->left()->GetInteger32Constant(); | |
2197 } | |
2198 } else if (phi_operand->IsSub()) { | |
2199 HSub* operation = HSub::cast(phi_operand); | |
2200 if (operation->left() == phi && | |
2201 operation->right()->IsInteger32Constant()) { | |
2202 return -operation->right()->GetInteger32Constant(); | |
2203 } | |
2204 } | |
2205 | |
2206 return 0; | |
2207 } | |
2208 | |
2209 | |
2210 HValue* InductionVariableData::IgnoreOsrValue(HValue* v) { | |
2211 if (!v->IsPhi()) return v; | |
2212 HPhi* phi = HPhi::cast(v); | |
2213 if (phi->OperandCount() != 2) return v; | |
2214 if (phi->OperandAt(0)->block()->is_osr_entry()) { | |
2215 return phi->OperandAt(1); | |
2216 } else if (phi->OperandAt(1)->block()->is_osr_entry()) { | |
2217 return phi->OperandAt(0); | |
2218 } else { | |
2219 return v; | |
2220 } | |
2221 } | |
2222 | |
2223 | |
2224 InductionVariableData* InductionVariableData::GetInductionVariableData( | |
2225 HValue* v) { | |
2226 v = IgnoreOsrValue(v); | |
2227 if (v->IsPhi()) { | |
2228 return HPhi::cast(v)->induction_variable_data(); | |
2229 } | |
2230 return NULL; | |
2231 } | |
2232 | |
2233 | |
2234 /* | |
2235 * Check if a comparison token can represent a branch that keeps the control | |
2236 * flow inside a loop (in other words, the branch where the increment is still | |
2237 * applied to the induction variable). | |
2238 * If this is true, then the condition associated with the branch can be the | |
2239 * induction variable limit for the loop. | |
2240 */ | |
2241 bool InductionVariableData::TokenCanRepresentLoopGuard(Token::Value token) { | |
titzer
2013/07/10 16:34:18
With the name change I see now more clearly what y
Massi
2013/07/11 11:15:22
Inlined it into CheckIfBranchIsLoopGuard.
| |
2242 if (increment() > 0 && (token == Token::GT || token == Token::GTE)) { | |
2243 return false; | |
2244 } | |
2245 if (increment() < 0 && (token == Token::GT || token == Token::GTE)) { | |
2246 return false; | |
2247 } | |
2248 if (Token::IsInequalityOp(token) && increment() != 1 && increment() != -1) { | |
2249 return false; | |
2250 } | |
2251 return true; | |
2252 } | |
2253 | |
2254 | |
2255 bool InductionVariableData::CheckIfBranchIsLoopGuard(HBasicBlock* in_branch, | |
2256 HBasicBlock* out_branch) { | |
titzer
2013/07/10 16:34:18
This is kind of a strange name for this method. I
Massi
2013/07/11 11:15:22
After the off line discussion I ended up not inlin
| |
2257 return phi()->block()->current_loop()->IsNestedInThisLoop( | |
2258 in_branch->current_loop()) && | |
2259 !phi()->block()->current_loop()->IsNestedInThisLoop( | |
2260 out_branch->current_loop()); | |
2261 } | |
2262 | |
2263 | |
2264 bool InductionVariableData::ComputeInductionVariableLimit( | |
2265 HBasicBlock* block, | |
2266 InductionVariableLimitUpdate* additional_limit) { | |
2267 if (block->predecessors()->length() != 1) return false; | |
2268 HBasicBlock* predecessor = block->predecessors()->at(0); | |
2269 HInstruction* end = predecessor->last(); | |
titzer
2013/07/10 16:34:18
This method could benefit from being split up into
Massi
2013/07/11 11:15:22
Done.
| |
2270 | |
2271 if (!end->IsCompareIDAndBranch()) return false; | |
2272 HCompareIDAndBranch* branch = HCompareIDAndBranch::cast(end); | |
2273 | |
2274 Token::Value token = branch->token(); | |
2275 if (!Token::IsArithmeticCompareOp(token)) return false; | |
2276 | |
2277 bool is_else_branch; | |
2278 HBasicBlock* other_target; | |
2279 if (block == branch->SuccessorAt(0)) { | |
2280 is_else_branch = false; | |
2281 other_target = branch->SuccessorAt(1); | |
2282 } else { | |
2283 is_else_branch = true; | |
2284 other_target = branch->SuccessorAt(0); | |
2285 ASSERT(block == branch->SuccessorAt(1)); | |
2286 } | |
2287 | |
2288 if (is_else_branch) { | |
titzer
2013/07/10 16:34:18
Please just negate the token above, and don't use
Massi
2013/07/11 11:15:22
Done.
| |
2289 token = Token::NegateCompareOp(token); | |
2290 } | |
2291 bool limit_included = (Token::IsEqualityOp(token) || | |
2292 token == Token::GTE || token == Token::LTE); | |
2293 | |
2294 InductionVariableData* data; | |
2295 | |
2296 data = GetInductionVariableData(branch->left()); | |
2297 Token::Value actual_token = token; | |
2298 HValue* limit = branch->right(); | |
2299 if (data == NULL) { | |
2300 data = GetInductionVariableData(branch->right()); | |
2301 actual_token = Token::ReverseCompareOp(token); | |
2302 limit = branch->left(); | |
2303 } | |
2304 | |
2305 if (data != NULL) { | |
2306 if (data->TokenCanRepresentLoopGuard(actual_token) && | |
2307 data->CheckIfBranchIsLoopGuard(block, other_target)) { | |
2308 data->limit_ = limit; | |
2309 data->limit_included_ = limit_included; | |
2310 data->limit_validity_ = block; | |
2311 data->induction_exit_block_ = predecessor; | |
2312 data->induction_exit_target_ = other_target; | |
2313 return false; | |
2314 } else { | |
2315 additional_limit->updated_variable = data; | |
2316 additional_limit->limit = limit; | |
2317 additional_limit->limit_is_upper = (actual_token == Token::LTE || | |
2318 actual_token == Token::LT || | |
2319 actual_token == Token::NE); | |
2320 additional_limit->limit_is_included = limit_included; | |
2321 return true; | |
2322 } | |
2323 } | |
2324 | |
2325 return false; | |
2326 } | |
2327 | |
2328 | |
1951 Range* HMathMinMax::InferRange(Zone* zone) { | 2329 Range* HMathMinMax::InferRange(Zone* zone) { |
1952 if (representation().IsInteger32()) { | 2330 if (representation().IsInteger32()) { |
1953 Range* a = left()->range(); | 2331 Range* a = left()->range(); |
1954 Range* b = right()->range(); | 2332 Range* b = right()->range(); |
1955 Range* res = a->Copy(zone); | 2333 Range* res = a->Copy(zone); |
1956 if (operation_ == kMathMax) { | 2334 if (operation_ == kMathMax) { |
1957 res->CombinedMax(b); | 2335 res->CombinedMax(b); |
1958 } else { | 2336 } else { |
1959 ASSERT(operation_ == kMathMin); | 2337 ASSERT(operation_ == kMathMin); |
1960 res->CombinedMin(b); | 2338 res->CombinedMin(b); |
(...skipping 1905 matching lines...) Loading... | |
3866 case kBackingStore: | 4244 case kBackingStore: |
3867 if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString()); | 4245 if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString()); |
3868 stream->Add("[backing-store]"); | 4246 stream->Add("[backing-store]"); |
3869 break; | 4247 break; |
3870 } | 4248 } |
3871 | 4249 |
3872 stream->Add("@%d", offset()); | 4250 stream->Add("@%d", offset()); |
3873 } | 4251 } |
3874 | 4252 |
3875 } } // namespace v8::internal | 4253 } } // namespace v8::internal |
OLD | NEW |