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

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: Addressed review comments. 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 void InductionVariableData::DecomposeBitwise(
1975 HValue* value,
1976 BitwiseDecompositionResult* result) {
1977 HValue* current = IgnoreOsrValue(value);
1978 bool has_offset = false;
1979 result->base = value;
1980 result->and_mask = 0;
1981 result->or_mask = 0;
1982 result->context = NULL;
1983
1984 if (!current->representation().IsInteger32()) return;
1985
1986 while (true) {
titzer 2013/07/02 13:45:06 I do not understand why this pattern matching is a
Massi 2013/07/08 11:55:07 Added a comment. I still think that having the loo
1987 if (current->IsAdd()) {
1988 if (result->and_mask != 0 || result->or_mask != 0) return;
1989 HAdd* operation = HAdd::cast(current);
1990 if (operation->right()->IsInteger32Constant()) {
1991 has_offset = true;
1992 current = operation->left();
1993 } else if (operation->left()->IsInteger32Constant()) {
1994 has_offset = true;
1995 current = operation->right();
1996 } else {
1997 return;
1998 }
1999 continue;
2000 } else if (current->IsSub()) {
2001 if (result->and_mask != 0 || result->or_mask != 0) return;
2002 HSub* operation = HSub::cast(current);
2003 if (operation->right()->IsInteger32Constant()) {
2004 has_offset = true;
2005 current = operation->left();
2006 } else {
2007 return;
2008 }
2009 continue;
2010 } else if (current->IsBitwise()) {
2011 HBitwise* operation = HBitwise::cast(current);
2012 int32_t* mask = NULL;
2013 if (operation->op() == Token::BIT_AND) {
2014 mask = &(result->and_mask);
2015 } else if (operation->op() == Token::BIT_OR) {
2016 if (has_offset) {
2017 return;
2018 }
2019 mask = &(result->or_mask);
2020 } else {
2021 return;
2022 }
2023 if (operation->right()->IsInteger32Constant()) {
2024 *mask = operation->right()->GetInteger32Constant();
2025 current = operation->left();
2026 } else if (operation->left()->IsInteger32Constant()) {
2027 *mask = operation->left()->GetInteger32Constant();
2028 current = operation->right();
2029 }
2030 result->context = operation->context();
2031 result->base = current;
2032 return;
2033 } else {
2034 return;
2035 }
2036 }
2037
2038 return;
2039 }
2040
2041
2042 void InductionVariableData::AddCheck(HBoundsCheck* check,
2043 int32_t upper_limit) {
2044 ASSERT(limit_validity() != NULL);
2045 if (limit_validity() != check->block() &&
2046 !limit_validity()->Dominates(check->block())) return;
2047 if (!phi()->block()->current_loop()->IsNestedInThisLoop(
2048 check->block()->current_loop())) return;
2049
2050 ChecksRelatedToLength* length_checks = checks();
2051 while (length_checks != NULL) {
2052 if (length_checks->length() == check->length()) break;
2053 length_checks = length_checks->next();
2054 }
2055 if (length_checks == NULL) {
2056 length_checks = new(check->block()->zone())
2057 ChecksRelatedToLength(check->length(), checks());
2058 checks_ = length_checks;
2059 }
2060
2061 length_checks->AddCheck(check, upper_limit);
2062 }
2063
2064 void InductionVariableData::ChecksRelatedToLength::CloseCurrentBlock() {
2065 if (checks() != NULL) {
2066 InductionVariableCheck* c = checks();
2067 HBasicBlock* current_block = c->check()->block();
2068 while (c != NULL && c->check()->block() == current_block) {
2069 c->set_upper_limit(current_upper_limit_);
2070 c = c->next();
2071 }
2072 }
2073 }
2074
2075
2076 void InductionVariableData::ChecksRelatedToLength::UseNewIndexInCurrentBlock(
2077 Token::Value token,
2078 int32_t mask,
2079 HValue* index_base,
2080 HValue* context) {
2081 ASSERT(first_check_in_block() != NULL);
2082 HValue* previous_index = first_check_in_block()->index();
2083 ASSERT(context != NULL);
2084
2085 added_constant_ = new(index_base->block()->graph()->zone()) HConstant(
2086 mask, index_base->representation());
2087 HInstruction* constant_insertion_point;
2088 if (added_index() != NULL) {
2089 constant_insertion_point = added_index();
2090 } else {
2091 constant_insertion_point = first_check_in_block();
2092 }
2093 added_constant()->InsertBefore(constant_insertion_point);
titzer 2013/07/02 13:45:06 Just move this code up into the if and save two li
Massi 2013/07/08 11:55:07 I tried that, with the ternary ?:, but added_index
2094
2095 if (added_index() == NULL) {
2096 first_check_in_block()->ReplaceAllUsesWith(first_check_in_block()->index());
2097 HInstruction* new_index = HBitwise::New(
2098 index_base->block()->graph()->zone(),
2099 token, context, index_base, added_constant());
2100 ASSERT(new_index->IsBitwise());
2101 new_index->ClearAllSideEffects();
titzer 2013/07/02 13:45:06 What side effects might the new index have that yo
Massi 2013/07/08 11:55:07 IIRC calling "toNumber()", which in our case is gu
2102 new_index->AssumeRepresentation(Representation::Integer32());
2103 added_index_ = HBitwise::cast(new_index);
titzer 2013/07/02 13:45:06 There are several assignments of private variables
Massi 2013/07/08 11:55:07 The logic was to use the private variable for writ
2104 added_index()->InsertBefore(first_check_in_block());
2105 }
2106 ASSERT(added_index()->op() == token);
2107
2108 added_index()->SetOperandAt(1, index_base);
2109 added_index()->SetOperandAt(2, added_constant());
2110 first_check_in_block()->SetOperandAt(0, added_index());
2111 if (previous_index->UseCount() == 0) {
2112 previous_index->DeleteAndReplaceWith(NULL);
2113 }
2114 }
2115
2116 void InductionVariableData::ChecksRelatedToLength::AddCheck(
2117 HBoundsCheck* check,
2118 int32_t upper_limit) {
2119 BitwiseDecompositionResult decomposition;
titzer 2013/07/02 13:45:06 Probably better to initialize this struct at the d
Massi 2013/07/08 11:55:07 Added parameterless constructor, even if I still t
2120 InductionVariableData::DecomposeBitwise(check->index(), &decomposition);
2121
2122 if (first_check_in_block() == NULL ||
2123 first_check_in_block()->block() != check->block()) {
2124 CloseCurrentBlock();
2125
2126 first_check_in_block_ = check;
2127 added_index_ = NULL;
2128 added_constant_ = NULL;
2129 current_and_mask_in_block_ = decomposition.and_mask;
2130 current_or_mask_in_block_ = decomposition.or_mask;
2131 current_upper_limit_ = upper_limit;
2132
2133 InductionVariableCheck* new_check = new(check->block()->graph()->zone())
2134 InductionVariableCheck(check, checks_, upper_limit);
2135 checks_ = new_check;
2136 return;
2137 }
2138
2139 if (upper_limit > current_upper_limit()) {
2140 current_upper_limit_ = upper_limit;
2141 }
2142
2143 if (decomposition.and_mask != 0 &&
2144 current_or_mask_in_block() == 0) {
2145 if (current_and_mask_in_block() == 0 ||
2146 decomposition.and_mask > current_and_mask_in_block()) {
2147 UseNewIndexInCurrentBlock(Token::BIT_AND,
2148 decomposition.and_mask,
2149 decomposition.base,
2150 decomposition.context);
2151 current_and_mask_in_block_ = decomposition.and_mask;
2152 }
2153 check->set_skip_check();
2154 }
2155 if (current_and_mask_in_block() == 0) {
2156 if (decomposition.or_mask > current_or_mask_in_block()) {
2157 UseNewIndexInCurrentBlock(Token::BIT_OR,
2158 decomposition.or_mask,
2159 decomposition.base,
2160 decomposition.context);
2161 current_or_mask_in_block_ = decomposition.or_mask;
2162 }
2163 check->set_skip_check();
2164 }
2165
2166 if (!check->skip_check()) {
2167 InductionVariableCheck* new_check = new(check->block()->graph()->zone())
2168 InductionVariableCheck(check, checks_, upper_limit);
2169 checks_ = new_check;
2170 }
2171 }
2172
2173
2174 int32_t InductionVariableData::ComputeIncrement(HPhi* phi,
titzer 2013/07/02 13:45:06 Comments documenting this method.
Massi 2013/07/08 11:55:07 Done.
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) {
titzer 2013/07/02 13:45:06 You can further shorten these branches with &&.
Massi 2013/07/08 11:55:07 Done.
2181 if (operation->right()->IsInteger32Constant()) {
2182 return operation->right()->GetInteger32Constant();
2183 }
2184 } else if (operation->right() == phi) {
2185 if (operation->left()->IsInteger32Constant()) {
2186 return operation->left()->GetInteger32Constant();
2187 }
2188 }
2189 } else if (phi_operand->IsSub()) {
2190 HSub* operation = HSub::cast(phi_operand);
2191 if (operation->left() == phi) {
2192 if (operation->right()->IsInteger32Constant()) {
2193 return -operation->right()->GetInteger32Constant();
2194 }
2195 }
2196 }
2197
2198 return 0;
2199 }
2200
2201
2202 HValue* InductionVariableData::IgnoreOsrValue(HValue* v) {
2203 if (!v->IsPhi()) return v;
2204 HPhi* phi = HPhi::cast(v);
2205 if (phi->OperandCount() != 2) return v;
2206 if (phi->OperandAt(0)->block()->is_osr_entry()) {
2207 return phi->OperandAt(1);
2208 } else if (phi->OperandAt(1)->block()->is_osr_entry()) {
2209 return phi->OperandAt(0);
2210 } else {
2211 return v;
2212 }
2213 }
2214
2215
2216 InductionVariableData* InductionVariableData::GetInductionVariableData(
2217 HValue* v) {
2218 v = IgnoreOsrValue(v);
2219 if (v->IsPhi()) {
2220 return HPhi::cast(v)->induction_variable_data();
2221 }
2222 return NULL;
2223 }
2224
2225
2226 /*
2227 * Check if a comparison token can represent a branch that keeps the control
2228 * flow inside a loop (in other words, the branch where the increment is still
2229 * applied to the induction variable).
2230 * If this is true, then the condition associated with the branch can be the
2231 * induction variable limit for the loop.
2232 */
2233 bool InductionVariableData::TokenCanRepresentLoopGuard(Token::Value token) {
2234 if (increment() > 0 && (token == Token::GT || token == Token::GTE)) {
2235 return false;
2236 }
2237 if (increment() < 0 && (token == Token::GT || token == Token::GTE)) {
2238 return false;
2239 }
2240 if (Token::IsInequalityOp(token) && increment() != 1 && increment() != -1) {
2241 return false;
2242 }
2243 return true;
2244 }
2245
2246
2247 bool InductionVariableData::CheckIfBranchIsLoopGuard(HBasicBlock* in_branch,
2248 HBasicBlock* out_branch) {
2249 return phi()->block()->current_loop()->IsNestedInThisLoop(
2250 in_branch->current_loop()) &&
2251 !phi()->block()->current_loop()->IsNestedInThisLoop(
2252 out_branch->current_loop());
2253 }
2254
2255
2256 bool InductionVariableData::ComputeInductionVariableLimit(
2257 HBasicBlock* block,
2258 InductionVariableLimitUpdate* additional_limit) {
2259 if (block->predecessors()->length() != 1) return false;
2260 HBasicBlock* predecessor = block->predecessors()->at(0);
2261 HInstruction* end = predecessor->last();
2262
2263 if (!end->IsCompareIDAndBranch()) return false;
2264 HCompareIDAndBranch* branch = HCompareIDAndBranch::cast(end);
2265
2266 Token::Value token = branch->token();
2267 if (!Token::IsArithmeticCompareOp(token)) return false;
2268
2269 bool is_else_branch;
2270 HBasicBlock* other_target;
2271 if (block == branch->SuccessorAt(0)) {
2272 is_else_branch = false;
2273 other_target = branch->SuccessorAt(1);
2274 } else {
2275 is_else_branch = true;
2276 other_target = branch->SuccessorAt(0);
2277 ASSERT(block == branch->SuccessorAt(1));
2278 }
2279
2280 if (is_else_branch) {
2281 token = Token::NegateCompareOp(token);
2282 }
2283 bool limit_included = (Token::IsEqualityOp(token) ||
2284 token == Token::GTE || token == Token::LTE);
2285
2286 InductionVariableData* data;
2287
2288 data = GetInductionVariableData(branch->left());
2289 Token::Value actual_token = token;
2290 HValue* limit = branch->right();
2291 if (data == NULL) {
2292 data = GetInductionVariableData(branch->right());
2293 actual_token = Token::ReverseCompareOp(token);
2294 limit = branch->left();
2295 }
2296
2297 if (data != NULL) {
2298 if (data->TokenCanRepresentLoopGuard(actual_token) &&
2299 data->CheckIfBranchIsLoopGuard(block, other_target)) {
2300 data->limit_ = limit;
2301 data->limit_included_ = limit_included;
2302 data->limit_validity_ = block;
2303 data->induction_exit_block_ = predecessor;
2304 data->induction_exit_target_ = other_target;
2305 return false;
2306 } else {
2307 additional_limit->updated_variable = data;
2308 additional_limit->limit = limit;
2309 additional_limit->limit_is_upper = (actual_token == Token::LTE ||
2310 actual_token == Token::LT ||
2311 actual_token == Token::NE);
2312 additional_limit->limit_is_included = limit_included;
2313 return true;
2314 }
2315 }
2316
2317 return false;
2318 }
2319
2320
1951 Range* HMathMinMax::InferRange(Zone* zone) { 2321 Range* HMathMinMax::InferRange(Zone* zone) {
1952 if (representation().IsInteger32()) { 2322 if (representation().IsInteger32()) {
1953 Range* a = left()->range(); 2323 Range* a = left()->range();
1954 Range* b = right()->range(); 2324 Range* b = right()->range();
1955 Range* res = a->Copy(zone); 2325 Range* res = a->Copy(zone);
1956 if (operation_ == kMathMax) { 2326 if (operation_ == kMathMax) {
1957 res->CombinedMax(b); 2327 res->CombinedMax(b);
1958 } else { 2328 } else {
1959 ASSERT(operation_ == kMathMin); 2329 ASSERT(operation_ == kMathMin);
1960 res->CombinedMin(b); 2330 res->CombinedMin(b);
(...skipping 1905 matching lines...) Expand 10 before | Expand all | Expand 10 after
3866 case kBackingStore: 4236 case kBackingStore:
3867 if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString()); 4237 if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString());
3868 stream->Add("[backing-store]"); 4238 stream->Add("[backing-store]");
3869 break; 4239 break;
3870 } 4240 }
3871 4241
3872 stream->Add("@%d", offset()); 4242 stream->Add("@%d", offset());
3873 } 4243 }
3874 4244
3875 } } // namespace v8::internal 4245 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698