 Chromium Code Reviews
 Chromium Code Reviews Issue 17568015:
  New array bounds check elimination pass (focused on induction variables and bitwise operations).  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 17568015:
  New array bounds check elimination pass (focused on induction variables and bitwise operations).  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand 10 before | Expand all | Expand 10 after 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 | constant_or_mask | |
| 1977 * base & constant_and_mask | |
| 1978 * (base + constant_offset) & constant_and_mask | |
| 1979 * (base - constant_offset) & constant_and_mask | |
| 
titzer
2013/07/18 12:22:58
I don't understand why we don't match (base + cons
 
Massi
2013/07/23 07:57:50
Because the old bounds check elimination phase alr
 | |
| 1980 */ | |
| 1981 void InductionVariableData::DecomposeBitwise( | |
| 1982 HValue* value, | |
| 1983 BitwiseDecompositionResult* result) { | |
| 1984 HValue* base = IgnoreOsrValue(value); | |
| 1985 result->base = value; | |
| 1986 int32_t* mask_location = NULL; | |
| 1987 | |
| 1988 if (!base->representation().IsInteger32()) return; | |
| 1989 | |
| 1990 if (base->IsBitwise()) { | |
| 1991 bool allow_offset = false; | |
| 1992 | |
| 1993 HBitwise* bitwise = HBitwise::cast(base); | |
| 1994 if (bitwise->op() == Token::BIT_AND) { | |
| 1995 mask_location = &(result->and_mask); | |
| 1996 allow_offset = true; | |
| 1997 } else if (bitwise->op() == Token::BIT_OR) { | |
| 1998 mask_location = &(result->or_mask); | |
| 1999 } else { | |
| 2000 return; | |
| 2001 } | |
| 2002 if (bitwise->right()->IsInteger32Constant()) { | |
| 
titzer
2013/07/18 12:22:58
As per previous comments, please don't use a point
 
Massi
2013/07/23 07:57:50
Done.
 | |
| 2003 *mask_location = bitwise->right()->GetInteger32Constant(); | |
| 2004 base = bitwise->left(); | |
| 2005 } else if (bitwise->left()->IsInteger32Constant()) { | |
| 2006 *mask_location = bitwise->left()->GetInteger32Constant(); | |
| 2007 base = bitwise->right(); | |
| 2008 } else { | |
| 2009 return; | |
| 2010 } | |
| 2011 | |
| 2012 result->context = bitwise->context(); | |
| 2013 | |
| 2014 if (allow_offset) { | |
| 2015 if (base->IsAdd()) { | |
| 2016 HAdd* add = HAdd::cast(base); | |
| 2017 if (add->right()->IsInteger32Constant()) { | |
| 2018 base = add->left(); | |
| 2019 } else if (add->left()->IsInteger32Constant()) { | |
| 2020 base = add->right(); | |
| 2021 } | |
| 2022 } else if (base->IsSub()) { | |
| 2023 HSub* sub = HSub::cast(base); | |
| 2024 if (sub->right()->IsInteger32Constant()) { | |
| 2025 base = sub->left(); | |
| 2026 } | |
| 2027 } | |
| 2028 } | |
| 2029 | |
| 2030 result->base = base; | |
| 2031 } | |
| 2032 } | |
| 2033 | |
| 2034 | |
| 2035 void InductionVariableData::AddCheck(HBoundsCheck* check, | |
| 2036 int32_t upper_limit) { | |
| 2037 ASSERT(limit_validity() != NULL); | |
| 2038 if (limit_validity() != check->block() && | |
| 2039 !limit_validity()->Dominates(check->block())) return; | |
| 2040 if (!phi()->block()->current_loop()->IsNestedInThisLoop( | |
| 2041 check->block()->current_loop())) return; | |
| 2042 | |
| 2043 ChecksRelatedToLength* length_checks = checks(); | |
| 2044 while (length_checks != NULL) { | |
| 2045 if (length_checks->length() == check->length()) break; | |
| 2046 length_checks = length_checks->next(); | |
| 2047 } | |
| 2048 if (length_checks == NULL) { | |
| 2049 length_checks = new(check->block()->zone()) | |
| 2050 ChecksRelatedToLength(check->length(), checks()); | |
| 2051 checks_ = length_checks; | |
| 2052 } | |
| 2053 | |
| 2054 length_checks->AddCheck(check, upper_limit); | |
| 2055 } | |
| 2056 | |
| 2057 void InductionVariableData::ChecksRelatedToLength::CloseCurrentBlock() { | |
| 2058 if (checks() != NULL) { | |
| 2059 InductionVariableCheck* c = checks(); | |
| 2060 HBasicBlock* current_block = c->check()->block(); | |
| 2061 while (c != NULL && c->check()->block() == current_block) { | |
| 2062 c->set_upper_limit(current_upper_limit_); | |
| 2063 c = c->next(); | |
| 2064 } | |
| 2065 } | |
| 2066 } | |
| 2067 | |
| 2068 | |
| 2069 void InductionVariableData::ChecksRelatedToLength::UseNewIndexInCurrentBlock( | |
| 2070 Token::Value token, | |
| 2071 int32_t mask, | |
| 2072 HValue* index_base, | |
| 2073 HValue* context) { | |
| 2074 ASSERT(first_check_in_block() != NULL); | |
| 2075 HValue* previous_index = first_check_in_block()->index(); | |
| 2076 ASSERT(context != NULL); | |
| 2077 | |
| 2078 set_added_constant(new(index_base->block()->graph()->zone()) HConstant( | |
| 2079 mask, index_base->representation())); | |
| 2080 if (added_index() != NULL) { | |
| 2081 added_constant()->InsertBefore(added_index()); | |
| 2082 } else { | |
| 2083 added_constant()->InsertBefore(first_check_in_block()); | |
| 2084 } | |
| 2085 | |
| 2086 if (added_index() == NULL) { | |
| 2087 first_check_in_block()->ReplaceAllUsesWith(first_check_in_block()->index()); | |
| 2088 HInstruction* new_index = HBitwise::New( | |
| 2089 index_base->block()->graph()->zone(), | |
| 2090 token, context, index_base, added_constant()); | |
| 2091 ASSERT(new_index->IsBitwise()); | |
| 2092 new_index->ClearAllSideEffects(); | |
| 2093 new_index->AssumeRepresentation(Representation::Integer32()); | |
| 2094 set_added_index(HBitwise::cast(new_index)); | |
| 2095 added_index()->InsertBefore(first_check_in_block()); | |
| 2096 } | |
| 2097 ASSERT(added_index()->op() == token); | |
| 2098 | |
| 2099 added_index()->SetOperandAt(1, index_base); | |
| 2100 added_index()->SetOperandAt(2, added_constant()); | |
| 2101 first_check_in_block()->SetOperandAt(0, added_index()); | |
| 2102 if (previous_index->UseCount() == 0) { | |
| 2103 previous_index->DeleteAndReplaceWith(NULL); | |
| 2104 } | |
| 2105 } | |
| 2106 | |
| 2107 void InductionVariableData::ChecksRelatedToLength::AddCheck( | |
| 2108 HBoundsCheck* check, | |
| 2109 int32_t upper_limit) { | |
| 2110 BitwiseDecompositionResult decomposition; | |
| 2111 InductionVariableData::DecomposeBitwise(check->index(), &decomposition); | |
| 2112 | |
| 2113 if (first_check_in_block() == NULL || | |
| 2114 first_check_in_block()->block() != check->block()) { | |
| 2115 CloseCurrentBlock(); | |
| 2116 | |
| 2117 first_check_in_block_ = check; | |
| 2118 set_added_index(NULL); | |
| 2119 set_added_constant(NULL); | |
| 2120 current_and_mask_in_block_ = decomposition.and_mask; | |
| 2121 current_or_mask_in_block_ = decomposition.or_mask; | |
| 2122 current_upper_limit_ = upper_limit; | |
| 2123 | |
| 2124 InductionVariableCheck* new_check = new(check->block()->graph()->zone()) | |
| 2125 InductionVariableCheck(check, checks_, upper_limit); | |
| 2126 checks_ = new_check; | |
| 2127 return; | |
| 2128 } | |
| 2129 | |
| 2130 if (upper_limit > current_upper_limit()) { | |
| 2131 current_upper_limit_ = upper_limit; | |
| 2132 } | |
| 2133 | |
| 2134 if (decomposition.and_mask != 0 && | |
| 2135 current_or_mask_in_block() == 0) { | |
| 2136 if (current_and_mask_in_block() == 0 || | |
| 2137 decomposition.and_mask > current_and_mask_in_block()) { | |
| 2138 UseNewIndexInCurrentBlock(Token::BIT_AND, | |
| 2139 decomposition.and_mask, | |
| 2140 decomposition.base, | |
| 2141 decomposition.context); | |
| 2142 current_and_mask_in_block_ = decomposition.and_mask; | |
| 2143 } | |
| 2144 check->set_skip_check(); | |
| 2145 } | |
| 2146 if (current_and_mask_in_block() == 0) { | |
| 2147 if (decomposition.or_mask > current_or_mask_in_block()) { | |
| 2148 UseNewIndexInCurrentBlock(Token::BIT_OR, | |
| 2149 decomposition.or_mask, | |
| 2150 decomposition.base, | |
| 2151 decomposition.context); | |
| 2152 current_or_mask_in_block_ = decomposition.or_mask; | |
| 2153 } | |
| 2154 check->set_skip_check(); | |
| 2155 } | |
| 2156 | |
| 2157 if (!check->skip_check()) { | |
| 2158 InductionVariableCheck* new_check = new(check->block()->graph()->zone()) | |
| 2159 InductionVariableCheck(check, checks_, upper_limit); | |
| 2160 checks_ = new_check; | |
| 2161 } | |
| 2162 } | |
| 2163 | |
| 2164 | |
| 2165 /* | |
| 2166 * This method detects if phi is an induction variable, with phi_operand as | |
| 2167 * its "incremented" value (the other operand would be the "base" value). | |
| 2168 * | |
| 2169 * It cheks is phi_operand has the form "phi + constant". | |
| 2170 * If yes, the constant is the increment that the induction variable gets at | |
| 2171 * every loop iteration. | |
| 2172 * Otherwise it returns 0. | |
| 2173 */ | |
| 2174 int32_t InductionVariableData::ComputeIncrement(HPhi* phi, | |
| 2175 HValue* phi_operand) { | |
| 2176 if (!phi_operand->representation().IsInteger32()) return 0; | |
| 2177 | |
| 2178 if (phi_operand->IsAdd()) { | |
| 2179 HAdd* operation = HAdd::cast(phi_operand); | |
| 2180 if (operation->left() == phi && | |
| 2181 operation->right()->IsInteger32Constant()) { | |
| 2182 return operation->right()->GetInteger32Constant(); | |
| 2183 } else if (operation->right() == phi && | |
| 2184 operation->left()->IsInteger32Constant()) { | |
| 2185 return operation->left()->GetInteger32Constant(); | |
| 2186 } | |
| 2187 } else if (phi_operand->IsSub()) { | |
| 2188 HSub* operation = HSub::cast(phi_operand); | |
| 2189 if (operation->left() == phi && | |
| 2190 operation->right()->IsInteger32Constant()) { | |
| 2191 return -operation->right()->GetInteger32Constant(); | |
| 2192 } | |
| 2193 } | |
| 2194 | |
| 2195 return 0; | |
| 2196 } | |
| 2197 | |
| 2198 | |
| 2199 /* | |
| 2200 * Swaps the information in "update" with the one contained in "this". | |
| 2201 * The swapping is important because this method is used while doing a | |
| 2202 * dominator tree traversal, and "update" will retain the old data that | |
| 2203 * will be restored while backtracking. | |
| 2204 */ | |
| 2205 void InductionVariableData::UpdateAdditionalLimit( | |
| 2206 InductionVariableLimitUpdate* update) { | |
| 2207 ASSERT(update->updated_variable == this); | |
| 2208 if (update->limit_is_upper) { | |
| 2209 swap(&additional_upper_limit_, &update->limit); | |
| 2210 swap(&additional_upper_limit_is_included_, &update->limit_is_included); | |
| 2211 } else { | |
| 2212 swap(&additional_lower_limit_, &update->limit); | |
| 2213 swap(&additional_lower_limit_is_included_, &update->limit_is_included); | |
| 2214 } | |
| 2215 } | |
| 2216 | |
| 2217 | |
| 2218 int32_t InductionVariableData::ComputeUpperLimit(int32_t and_mask, | |
| 2219 int32_t or_mask) { | |
| 2220 // Should be Smi::kMaxValue but it must fit 32 bits; lower is safe anyway. | |
| 2221 const int32_t MAX_LIMIT = 1 << 30; | |
| 2222 | |
| 2223 int32_t result = MAX_LIMIT; | |
| 2224 | |
| 2225 if (limit() != NULL && | |
| 2226 limit()->IsInteger32Constant()) { | |
| 2227 int32_t limit_value = limit()->GetInteger32Constant(); | |
| 2228 if (!limit_included()) { | |
| 2229 limit_value--; | |
| 2230 } | |
| 2231 if (limit_value < result) result = limit_value; | |
| 2232 } | |
| 2233 | |
| 2234 if (additional_upper_limit() != NULL && | |
| 2235 additional_upper_limit()->IsInteger32Constant()) { | |
| 2236 int32_t limit_value = additional_upper_limit()->GetInteger32Constant(); | |
| 2237 if (!additional_upper_limit_is_included()) { | |
| 2238 limit_value--; | |
| 2239 } | |
| 2240 if (limit_value < result) result = limit_value; | |
| 2241 } | |
| 2242 | |
| 2243 if (and_mask > 0 && and_mask < MAX_LIMIT) { | |
| 2244 if (and_mask < result) result = and_mask; | |
| 2245 return result; | |
| 2246 } | |
| 2247 | |
| 2248 // Add the effect of the or_mask. | |
| 2249 result |= or_mask; | |
| 2250 | |
| 2251 if (result >= MAX_LIMIT) { | |
| 
titzer
2013/07/18 12:22:58
Can use a ternary here.
 
Massi
2013/07/23 07:57:50
Done.
 | |
| 2252 result = kNoLimit; | |
| 2253 } | |
| 2254 return result; | |
| 2255 } | |
| 2256 | |
| 2257 | |
| 2258 HValue* InductionVariableData::IgnoreOsrValue(HValue* v) { | |
| 2259 if (!v->IsPhi()) return v; | |
| 2260 HPhi* phi = HPhi::cast(v); | |
| 2261 if (phi->OperandCount() != 2) return v; | |
| 2262 if (phi->OperandAt(0)->block()->is_osr_entry()) { | |
| 2263 return phi->OperandAt(1); | |
| 2264 } else if (phi->OperandAt(1)->block()->is_osr_entry()) { | |
| 2265 return phi->OperandAt(0); | |
| 2266 } else { | |
| 2267 return v; | |
| 2268 } | |
| 2269 } | |
| 2270 | |
| 2271 | |
| 2272 InductionVariableData* InductionVariableData::GetInductionVariableData( | |
| 2273 HValue* v) { | |
| 2274 v = IgnoreOsrValue(v); | |
| 2275 if (v->IsPhi()) { | |
| 2276 return HPhi::cast(v)->induction_variable_data(); | |
| 2277 } | |
| 2278 return NULL; | |
| 2279 } | |
| 2280 | |
| 2281 | |
| 2282 /* | |
| 2283 * Check if a conditional branch to "current_branch" with token "token" is | |
| 2284 * the branch that keeps the induction loop running (and, conversely, will | |
| 2285 * terminate it if the "other_branch" is taken). | |
| 2286 * | |
| 2287 * Three conditions must be met: | |
| 2288 * - "current_branch" must be in the induction loop. | |
| 2289 * - "other_branch" must be out of the induction loop. | |
| 2290 * - "token" and the induction increment must be "compatible": the token should | |
| 2291 * be a condition that keeps the execution inside the loop until the limit is | |
| 2292 * reached. | |
| 2293 */ | |
| 2294 bool InductionVariableData::CheckIfBranchIsLoopGuard( | |
| 2295 Token::Value token, | |
| 2296 HBasicBlock* current_branch, | |
| 2297 HBasicBlock* other_branch) { | |
| 2298 if (!phi()->block()->current_loop()->IsNestedInThisLoop( | |
| 2299 current_branch->current_loop())) { | |
| 2300 return false; | |
| 2301 } | |
| 2302 | |
| 2303 if (phi()->block()->current_loop()->IsNestedInThisLoop( | |
| 2304 other_branch->current_loop())) { | |
| 2305 return false; | |
| 2306 } | |
| 2307 | |
| 2308 if (increment() > 0 && (token == Token::LT || token == Token::LTE)) { | |
| 2309 return true; | |
| 2310 } | |
| 2311 if (increment() < 0 && (token == Token::GT || token == Token::GTE)) { | |
| 2312 return true; | |
| 2313 } | |
| 2314 if (Token::IsInequalityOp(token) && (increment() == 1 || increment() == -1)) { | |
| 2315 return true; | |
| 2316 } | |
| 2317 | |
| 2318 return false; | |
| 2319 } | |
| 2320 | |
| 2321 | |
| 2322 void InductionVariableData::ComputeLimitFromPredecessorBlock( | |
| 2323 HBasicBlock* block, | |
| 2324 LimitFromPredecessorBlock* result) { | |
| 2325 if (block->predecessors()->length() != 1) return; | |
| 2326 HBasicBlock* predecessor = block->predecessors()->at(0); | |
| 2327 HInstruction* end = predecessor->last(); | |
| 2328 | |
| 2329 if (!end->IsCompareIDAndBranch()) return; | |
| 2330 HCompareIDAndBranch* branch = HCompareIDAndBranch::cast(end); | |
| 2331 | |
| 2332 Token::Value token = branch->token(); | |
| 2333 if (!Token::IsArithmeticCompareOp(token)) return; | |
| 2334 | |
| 2335 HBasicBlock* other_target; | |
| 2336 if (block == branch->SuccessorAt(0)) { | |
| 2337 other_target = branch->SuccessorAt(1); | |
| 2338 } else { | |
| 2339 other_target = branch->SuccessorAt(0); | |
| 2340 token = Token::NegateCompareOp(token); | |
| 2341 ASSERT(block == branch->SuccessorAt(1)); | |
| 2342 } | |
| 2343 | |
| 2344 InductionVariableData* data; | |
| 2345 | |
| 2346 data = GetInductionVariableData(branch->left()); | |
| 2347 HValue* limit = branch->right(); | |
| 2348 if (data == NULL) { | |
| 2349 data = GetInductionVariableData(branch->right()); | |
| 2350 token = Token::ReverseCompareOp(token); | |
| 2351 limit = branch->left(); | |
| 2352 } | |
| 2353 | |
| 2354 if (data != NULL) { | |
| 2355 result->variable = data; | |
| 2356 result->token = token; | |
| 2357 result->limit = limit; | |
| 2358 result->other_target = other_target; | |
| 2359 } | |
| 2360 } | |
| 2361 | |
| 2362 /* | |
| 2363 * Compute the limit that is imposed on an induction variable when entering | |
| 2364 * "block" (if any). | |
| 2365 * If the limit is the "proper" induction limit (the one that makes the loop | |
| 2366 * terminate when the induction variable reaches it) it is stored directly in | |
| 2367 * the induction variable data. | |
| 2368 * Otherwise the limit is written in "additional_limit" and the method | |
| 2369 * returns true. | |
| 2370 */ | |
| 2371 bool InductionVariableData::ComputeInductionVariableLimit( | |
| 2372 HBasicBlock* block, | |
| 2373 InductionVariableLimitUpdate* additional_limit) { | |
| 2374 LimitFromPredecessorBlock limit; | |
| 2375 ComputeLimitFromPredecessorBlock(block, &limit); | |
| 2376 if (!limit.LimitIsValid()) return false; | |
| 2377 | |
| 2378 if (limit.variable->CheckIfBranchIsLoopGuard(limit.token, | |
| 2379 block, | |
| 2380 limit.other_target)) { | |
| 2381 limit.variable->limit_ = limit.limit; | |
| 2382 limit.variable->limit_included_ = limit.LimitIsIncluded(); | |
| 2383 limit.variable->limit_validity_ = block; | |
| 2384 limit.variable->induction_exit_block_ = block->predecessors()->at(0); | |
| 2385 limit.variable->induction_exit_target_ = limit.other_target; | |
| 2386 return false; | |
| 2387 } else { | |
| 2388 additional_limit->updated_variable = limit.variable; | |
| 2389 additional_limit->limit = limit.limit; | |
| 2390 additional_limit->limit_is_upper = limit.LimitIsUpper(); | |
| 2391 additional_limit->limit_is_included = limit.LimitIsIncluded(); | |
| 2392 return true; | |
| 2393 } | |
| 2394 } | |
| 2395 | |
| 2396 | |
| 1951 Range* HMathMinMax::InferRange(Zone* zone) { | 2397 Range* HMathMinMax::InferRange(Zone* zone) { | 
| 1952 if (representation().IsInteger32()) { | 2398 if (representation().IsInteger32()) { | 
| 1953 Range* a = left()->range(); | 2399 Range* a = left()->range(); | 
| 1954 Range* b = right()->range(); | 2400 Range* b = right()->range(); | 
| 1955 Range* res = a->Copy(zone); | 2401 Range* res = a->Copy(zone); | 
| 1956 if (operation_ == kMathMax) { | 2402 if (operation_ == kMathMax) { | 
| 1957 res->CombinedMax(b); | 2403 res->CombinedMax(b); | 
| 1958 } else { | 2404 } else { | 
| 1959 ASSERT(operation_ == kMathMin); | 2405 ASSERT(operation_ == kMathMin); | 
| 1960 res->CombinedMin(b); | 2406 res->CombinedMin(b); | 
| (...skipping 1905 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3866 case kBackingStore: | 4312 case kBackingStore: | 
| 3867 if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString()); | 4313 if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString()); | 
| 3868 stream->Add("[backing-store]"); | 4314 stream->Add("[backing-store]"); | 
| 3869 break; | 4315 break; | 
| 3870 } | 4316 } | 
| 3871 | 4317 | 
| 3872 stream->Add("@%d", offset()); | 4318 stream->Add("@%d", offset()); | 
| 3873 } | 4319 } | 
| 3874 | 4320 | 
| 3875 } } // namespace v8::internal | 4321 } } // namespace v8::internal | 
| OLD | NEW |