Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: src/hydrogen-instructions.cc

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
Patch Set: Actually removed a method, and applied a small fix. Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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/11 16:39:10 Why do we not also want to match "base + constant_
Massi 2013/07/12 08:20:24 Because collapsing those patterns is the job of th
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 int32_t mask = 0;
1988
1989 if (!base->representation().IsInteger32()) return;
1990
1991 if (base->IsBitwise()) {
1992 bool allow_offset = false;
1993
1994 HBitwise* bitwise = HBitwise::cast(base);
1995 if (bitwise->op() == Token::BIT_AND) {
1996 mask_location = &(result->and_mask);
1997 allow_offset = true;
1998 } else if (bitwise->op() == Token::BIT_OR) {
1999 mask_location = &(result->or_mask);
2000 } else {
2001 return;
2002 }
2003 if (bitwise->right()->IsInteger32Constant()) {
titzer 2013/07/11 16:39:10 If you get the mask first, before matching AND or
Massi 2013/07/12 08:20:24 True about mask, but we still want to allow those
2004 mask = bitwise->right()->GetInteger32Constant();
2005 base = bitwise->left();
2006 } else if (bitwise->left()->IsInteger32Constant()) {
2007 mask = bitwise->left()->GetInteger32Constant();
2008 base = bitwise->right();
2009 } else {
2010 return;
2011 }
2012
2013 *mask_location = mask;
2014 result->context = bitwise->context();
2015
2016 if (allow_offset) {
2017 if (base->IsAdd()) {
2018 HAdd* add = HAdd::cast(base);
2019 if (add->right()->IsInteger32Constant()) {
2020 base = add->left();
2021 } else if (add->left()->IsInteger32Constant()) {
2022 base = add->right();
2023 }
2024 } else if (base->IsSub()) {
2025 HSub* sub = HSub::cast(base);
2026 if (sub->right()->IsInteger32Constant()) {
2027 base = sub->left();
2028 }
2029 }
2030 }
2031
2032 result->base = base;
2033 }
2034 }
2035
2036
2037 void InductionVariableData::AddCheck(HBoundsCheck* check,
2038 int32_t upper_limit) {
2039 ASSERT(limit_validity() != NULL);
2040 if (limit_validity() != check->block() &&
2041 !limit_validity()->Dominates(check->block())) return;
2042 if (!phi()->block()->current_loop()->IsNestedInThisLoop(
2043 check->block()->current_loop())) return;
2044
2045 ChecksRelatedToLength* length_checks = checks();
2046 while (length_checks != NULL) {
2047 if (length_checks->length() == check->length()) break;
2048 length_checks = length_checks->next();
2049 }
2050 if (length_checks == NULL) {
2051 length_checks = new(check->block()->zone())
2052 ChecksRelatedToLength(check->length(), checks());
2053 checks_ = length_checks;
2054 }
2055
2056 length_checks->AddCheck(check, upper_limit);
2057 }
2058
2059 void InductionVariableData::ChecksRelatedToLength::CloseCurrentBlock() {
2060 if (checks() != NULL) {
2061 InductionVariableCheck* c = checks();
2062 HBasicBlock* current_block = c->check()->block();
2063 while (c != NULL && c->check()->block() == current_block) {
2064 c->set_upper_limit(current_upper_limit_);
2065 c = c->next();
2066 }
2067 }
2068 }
2069
2070
2071 void InductionVariableData::ChecksRelatedToLength::UseNewIndexInCurrentBlock(
2072 Token::Value token,
2073 int32_t mask,
2074 HValue* index_base,
2075 HValue* context) {
2076 ASSERT(first_check_in_block() != NULL);
2077 HValue* previous_index = first_check_in_block()->index();
2078 ASSERT(context != NULL);
2079
2080 set_added_constant(new(index_base->block()->graph()->zone()) HConstant(
2081 mask, index_base->representation()));
2082 if (added_index() != NULL) {
2083 added_constant()->InsertBefore(added_index());
2084 } else {
2085 added_constant()->InsertBefore(first_check_in_block());
2086 }
2087
2088 if (added_index() == NULL) {
2089 first_check_in_block()->ReplaceAllUsesWith(first_check_in_block()->index());
2090 HInstruction* new_index = HBitwise::New(
2091 index_base->block()->graph()->zone(),
2092 token, context, index_base, added_constant());
2093 ASSERT(new_index->IsBitwise());
2094 new_index->ClearAllSideEffects();
2095 new_index->AssumeRepresentation(Representation::Integer32());
2096 set_added_index(HBitwise::cast(new_index));
2097 added_index()->InsertBefore(first_check_in_block());
2098 }
2099 ASSERT(added_index()->op() == token);
2100
2101 added_index()->SetOperandAt(1, index_base);
2102 added_index()->SetOperandAt(2, added_constant());
2103 first_check_in_block()->SetOperandAt(0, added_index());
2104 if (previous_index->UseCount() == 0) {
2105 previous_index->DeleteAndReplaceWith(NULL);
2106 }
2107 }
2108
2109 void InductionVariableData::ChecksRelatedToLength::AddCheck(
2110 HBoundsCheck* check,
2111 int32_t upper_limit) {
2112 BitwiseDecompositionResult decomposition;
2113 InductionVariableData::DecomposeBitwise(check->index(), &decomposition);
2114
2115 if (first_check_in_block() == NULL ||
2116 first_check_in_block()->block() != check->block()) {
2117 CloseCurrentBlock();
2118
2119 first_check_in_block_ = check;
2120 set_added_index(NULL);
2121 set_added_constant(NULL);
2122 current_and_mask_in_block_ = decomposition.and_mask;
2123 current_or_mask_in_block_ = decomposition.or_mask;
2124 current_upper_limit_ = upper_limit;
2125
2126 InductionVariableCheck* new_check = new(check->block()->graph()->zone())
2127 InductionVariableCheck(check, checks_, upper_limit);
2128 checks_ = new_check;
2129 return;
2130 }
2131
2132 if (upper_limit > current_upper_limit()) {
2133 current_upper_limit_ = upper_limit;
2134 }
2135
2136 if (decomposition.and_mask != 0 &&
2137 current_or_mask_in_block() == 0) {
2138 if (current_and_mask_in_block() == 0 ||
2139 decomposition.and_mask > current_and_mask_in_block()) {
2140 UseNewIndexInCurrentBlock(Token::BIT_AND,
2141 decomposition.and_mask,
2142 decomposition.base,
2143 decomposition.context);
2144 current_and_mask_in_block_ = decomposition.and_mask;
2145 }
2146 check->set_skip_check();
2147 }
2148 if (current_and_mask_in_block() == 0) {
2149 if (decomposition.or_mask > current_or_mask_in_block()) {
2150 UseNewIndexInCurrentBlock(Token::BIT_OR,
2151 decomposition.or_mask,
2152 decomposition.base,
2153 decomposition.context);
2154 current_or_mask_in_block_ = decomposition.or_mask;
2155 }
2156 check->set_skip_check();
2157 }
2158
2159 if (!check->skip_check()) {
2160 InductionVariableCheck* new_check = new(check->block()->graph()->zone())
2161 InductionVariableCheck(check, checks_, upper_limit);
2162 checks_ = new_check;
2163 }
2164 }
2165
2166
2167 /*
2168 * This method detects if phi is an induction variable, with phi_operand as
2169 * its "incremented" value (the other operand would be the "base" value).
2170 *
2171 * It cheks is phi_operand has the form "phi + constant".
2172 * If yes, the constant is the increment that the induction variable gets at
2173 * every loop iteration.
2174 * Otherwise it returns 0.
2175 */
2176 int32_t InductionVariableData::ComputeIncrement(HPhi* phi,
2177 HValue* phi_operand) {
2178 if (!phi_operand->representation().IsInteger32()) return 0;
2179
2180 if (phi_operand->IsAdd()) {
2181 HAdd* operation = HAdd::cast(phi_operand);
2182 if (operation->left() == phi &&
2183 operation->right()->IsInteger32Constant()) {
2184 return operation->right()->GetInteger32Constant();
2185 } else if (operation->right() == phi &&
2186 operation->left()->IsInteger32Constant()) {
2187 return operation->left()->GetInteger32Constant();
2188 }
2189 } else if (phi_operand->IsSub()) {
2190 HSub* operation = HSub::cast(phi_operand);
2191 if (operation->left() == phi &&
2192 operation->right()->IsInteger32Constant()) {
2193 return -operation->right()->GetInteger32Constant();
2194 }
2195 }
2196
2197 return 0;
2198 }
2199
2200
2201 HValue* InductionVariableData::IgnoreOsrValue(HValue* v) {
2202 if (!v->IsPhi()) return v;
2203 HPhi* phi = HPhi::cast(v);
2204 if (phi->OperandCount() != 2) return v;
2205 if (phi->OperandAt(0)->block()->is_osr_entry()) {
2206 return phi->OperandAt(1);
2207 } else if (phi->OperandAt(1)->block()->is_osr_entry()) {
2208 return phi->OperandAt(0);
2209 } else {
2210 return v;
2211 }
2212 }
2213
2214
2215 InductionVariableData* InductionVariableData::GetInductionVariableData(
2216 HValue* v) {
2217 v = IgnoreOsrValue(v);
2218 if (v->IsPhi()) {
2219 return HPhi::cast(v)->induction_variable_data();
2220 }
2221 return NULL;
2222 }
2223
2224
2225 /*
2226 * Check if a conditional branch to "current_branch" with token "token" is
2227 * the branch that keeps the induction loop running (and, conversely, will
2228 * terminate it if the "other_branch" is taken).
2229 *
2230 * Three conditions must be met:
2231 * - "current_branch" must be in the induction loop.
2232 * - "other_branch" must be out of the induction loop.
2233 * - "token" and the induction increment must be "compatible": the token should
2234 * be a condition that keeps the execution inside the loop until the limit is
2235 * reached.
2236 */
2237 bool InductionVariableData::CheckIfBranchIsLoopGuard(
2238 Token::Value token,
2239 HBasicBlock* current_branch,
titzer 2013/07/11 16:39:10 If I understand this code correctly now, this is t
2240 HBasicBlock* other_branch) {
2241 if (!phi()->block()->current_loop()->IsNestedInThisLoop(
2242 current_branch->current_loop())) {
2243 return false;
2244 }
2245
2246 if (phi()->block()->current_loop()->IsNestedInThisLoop(
2247 other_branch->current_loop())) {
2248 return false;
2249 }
2250
2251 if (increment() > 0 && (token == Token::LT || token == Token::LTE)) {
2252 return true;
2253 }
2254 if (increment() < 0 && (token == Token::GT || token == Token::GTE)) {
2255 return true;
2256 }
2257 if (Token::IsInequalityOp(token) && (increment() == 1 || increment() == -1)) {
2258 return true;
2259 }
2260
2261 return false;
2262 }
2263
2264
2265 void InductionVariableData::ComputeLimitFromPredecessorBlock(
2266 HBasicBlock* block,
2267 LimitFromPredecessorBlock* result) {
2268 if (block->predecessors()->length() != 1) return;
2269 HBasicBlock* predecessor = block->predecessors()->at(0);
2270 HInstruction* end = predecessor->last();
2271
2272 if (!end->IsCompareIDAndBranch()) return;
2273 HCompareIDAndBranch* branch = HCompareIDAndBranch::cast(end);
2274
2275 Token::Value token = branch->token();
2276 if (!Token::IsArithmeticCompareOp(token)) return;
2277
2278 HBasicBlock* other_target;
2279 if (block == branch->SuccessorAt(0)) {
2280 other_target = branch->SuccessorAt(1);
2281 } else {
2282 other_target = branch->SuccessorAt(0);
2283 token = Token::NegateCompareOp(token);
2284 ASSERT(block == branch->SuccessorAt(1));
2285 }
2286
2287 InductionVariableData* data;
2288
2289 data = GetInductionVariableData(branch->left());
2290 HValue* limit = branch->right();
2291 if (data == NULL) {
2292 data = GetInductionVariableData(branch->right());
2293 token = Token::ReverseCompareOp(token);
2294 limit = branch->left();
2295 }
2296
2297 if (data != NULL) {
2298 result->variable = data;
2299 result->token = token;
2300 result->limit = limit;
2301 result->other_target = other_target;
2302 }
2303 }
2304
2305 /*
2306 * Compute the limit that is imposed on an induction variable when entering
2307 * "block" (if any).
2308 * If the limit is the "proper" induction limit (the one that makes the loop
2309 * terminate when the induction variable reaches it) it is stored directly in
2310 * the induction variable data.
2311 * Otherwise the limit is written in "additional_limit" and the method
2312 * returns true.
2313 */
2314 bool InductionVariableData::ComputeInductionVariableLimit(
2315 HBasicBlock* block,
2316 InductionVariableLimitUpdate* additional_limit) {
2317 LimitFromPredecessorBlock limit;
2318 ComputeLimitFromPredecessorBlock(block, &limit);
2319 if (!limit.LimitIsValid()) return false;
2320
2321 if (limit.variable->CheckIfBranchIsLoopGuard(limit.token,
2322 block,
2323 limit.other_target)) {
2324 limit.variable->limit_ = limit.limit;
2325 limit.variable->limit_included_ = limit.LimitIsIncluded();
2326 limit.variable->limit_validity_ = block;
2327 limit.variable->induction_exit_block_ = block->predecessors()->at(0);
2328 limit.variable->induction_exit_target_ = limit.other_target;
2329 return false;
2330 } else {
2331 additional_limit->updated_variable = limit.variable;
2332 additional_limit->limit = limit.limit;
2333 additional_limit->limit_is_upper = limit.LimitIsUpper();
2334 additional_limit->limit_is_included = limit.LimitIsIncluded();
2335 return true;
2336 }
2337 }
2338
2339
1951 Range* HMathMinMax::InferRange(Zone* zone) { 2340 Range* HMathMinMax::InferRange(Zone* zone) {
1952 if (representation().IsInteger32()) { 2341 if (representation().IsInteger32()) {
1953 Range* a = left()->range(); 2342 Range* a = left()->range();
1954 Range* b = right()->range(); 2343 Range* b = right()->range();
1955 Range* res = a->Copy(zone); 2344 Range* res = a->Copy(zone);
1956 if (operation_ == kMathMax) { 2345 if (operation_ == kMathMax) {
1957 res->CombinedMax(b); 2346 res->CombinedMax(b);
1958 } else { 2347 } else {
1959 ASSERT(operation_ == kMathMin); 2348 ASSERT(operation_ == kMathMin);
1960 res->CombinedMin(b); 2349 res->CombinedMin(b);
(...skipping 1905 matching lines...) Expand 10 before | Expand all | Expand 10 after
3866 case kBackingStore: 4255 case kBackingStore:
3867 if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString()); 4256 if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString());
3868 stream->Add("[backing-store]"); 4257 stream->Add("[backing-store]");
3869 break; 4258 break;
3870 } 4259 }
3871 4260
3872 stream->Add("@%d", offset()); 4261 stream->Add("@%d", offset());
3873 } 4262 }
3874 4263
3875 } } // namespace v8::internal 4264 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698