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

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: Created 7 years, 6 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::New(HPhi* phi) {
titzer 2013/06/24 14:03:30 This method really isn't a "new" or constructor me
Massi 2013/07/01 13:10:49 Done (renamed as "ExaminePhi").
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 HValue* InductionVariableData::DecomposeBitwise(HValue* value,
1975 int32_t* and_mask,
1976 int32_t* or_mask,
1977 HValue** context) {
titzer 2013/06/24 14:03:30 Returning potentially four different values via po
Massi 2013/07/01 13:10:49 Done.
1978 HValue* current = DiscardOsrValue(value);
1979 bool has_offset = false;
1980 *and_mask = 0;
1981 *or_mask = 0;
1982 *context = NULL;
1983
1984 if (!current->representation().IsInteger32()) return value;
1985
1986 while (true) {
1987 if (current->IsAdd()) {
1988 if (and_mask != 0 || or_mask != 0) return value;
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 value;
1998 }
1999 continue;
2000 } else if (current->IsSub()) {
2001 if (and_mask != 0 || or_mask != 0) return value;
2002 HSub* operation = HSub::cast(current);
2003 if (operation->right()->IsInteger32Constant()) {
2004 has_offset = true;
2005 current = operation->left();
2006 } else {
2007 return value;
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 = and_mask;
2015 } else if (operation->op() == Token::BIT_OR) {
2016 if (has_offset) {
2017 return value;
2018 }
2019 mask = or_mask;
2020 } else {
2021 return value;
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 *context = operation->context();
2031 return current;
2032 } else {
2033 return value;
2034 }
2035 }
2036
2037 return value;
2038 }
2039
2040
2041 void InductionVariableData::AddCheck(HBoundsCheck* check,
2042 int32_t upper_limit) {
2043 ASSERT(limit_validity() != NULL);
2044 if (limit_validity() != check->block() &&
2045 !limit_validity()->Dominates(check->block())) return;
2046 if (!phi()->block()->current_loop()->IsNestedInThisLoop(
2047 check->block())) return;
2048
2049 ChecksRelatedToLength* length_checks = checks();
2050 while (length_checks != NULL) {
2051 if (length_checks->length() == check->length()) break;
2052 length_checks = length_checks->next();
2053 }
2054 if (length_checks == NULL) {
2055 length_checks = new(check->block()->zone())
2056 ChecksRelatedToLength(check->length(), checks());
2057 checks_ = length_checks;
2058 }
2059
2060 length_checks->AddCheck(check, upper_limit);
2061 }
2062
2063 void InductionVariableData::ChecksRelatedToLength::CloseCurrentBlock() {
2064 if (checks() != NULL) {
2065 InductionVariableCheck* c = checks();
2066 HBasicBlock* current_block = c->check()->block();
2067 while (c != NULL && c->check()->block() == current_block) {
2068 c->set_upper_limit(current_upper_limit_);
2069 c = c->next();
2070 }
2071 }
2072 }
2073
2074
2075 void InductionVariableData::ChecksRelatedToLength::UseNewIndexInCurrentBlock(
2076 Token::Value token,
2077 int32_t mask,
2078 HValue* index_base,
2079 HValue* context) {
2080 ASSERT(first_check_in_block() != NULL);
2081 HValue* previous_index = first_check_in_block()->index();
2082 ASSERT(context != NULL);
2083
2084 added_constant_ = new(index_base->block()->graph()->zone()) HConstant(
2085 mask, index_base->representation());
2086 HInstruction* constant_insertion_point;
2087 if (added_index() != NULL) {
2088 constant_insertion_point = added_index();
2089 } else {
2090 constant_insertion_point = first_check_in_block();
2091 }
2092 added_constant()->InsertBefore(constant_insertion_point);
2093
2094 if (added_index() == NULL) {
2095 first_check_in_block()->ReplaceAllUsesWith(first_check_in_block()->index());
2096 HInstruction* new_index = HBitwise::New(
2097 index_base->block()->graph()->zone(),
2098 token, context, index_base, added_constant());
2099 ASSERT(new_index->IsBitwise());
2100 new_index->ClearAllSideEffects();
2101 new_index->AssumeRepresentation(Representation::Integer32());
2102 added_index_ = HBitwise::cast(new_index);
2103 added_index()->InsertBefore(first_check_in_block());
2104 }
2105 ASSERT(added_index()->op() == token);
2106
2107 added_index()->SetOperandAt(1, index_base);
2108 added_index()->SetOperandAt(2, added_constant());
2109 first_check_in_block()->SetOperandAt(0, added_index());
2110 if (previous_index->UseCount() == 0) {
2111 previous_index->DeleteAndReplaceWith(NULL);
2112 }
2113 }
2114
2115 void InductionVariableData::ChecksRelatedToLength::AddCheck(
2116 HBoundsCheck* check,
2117 int32_t upper_limit) {
2118 int32_t and_mask;
2119 int32_t or_mask;
2120 HValue* context;
2121 HValue* index_base = InductionVariableData::DecomposeBitwise(
2122 check->index(), &and_mask, &or_mask, &context);
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 added_index_ = NULL;
2130 added_constant_ = NULL;
2131 current_and_mask_in_block_ = and_mask;
2132 current_or_mask_in_block_ = 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 (and_mask != 0 &&
2146 current_or_mask_in_block() == 0) {
2147 if (current_and_mask_in_block() == 0 ||
2148 and_mask > current_and_mask_in_block()) {
2149 UseNewIndexInCurrentBlock(Token::BIT_AND, and_mask, index_base, context);
2150 current_and_mask_in_block_ = and_mask;
2151 }
2152 check->set_skip_check();
2153 }
2154 if (current_and_mask_in_block() == 0) {
2155 if (or_mask > current_or_mask_in_block()) {
2156 UseNewIndexInCurrentBlock(Token::BIT_OR, or_mask, index_base, context);
2157 current_or_mask_in_block_ = or_mask;
2158 }
2159 check->set_skip_check();
2160 }
2161
2162 if (!check->skip_check()) {
2163 InductionVariableCheck* new_check = new(check->block()->graph()->zone())
2164 InductionVariableCheck(check, checks_, upper_limit);
2165 checks_ = new_check;
2166 }
2167 }
2168
2169
2170 int32_t InductionVariableData::ComputeIncrement(HPhi* phi,
2171 HValue* phi_operand) {
titzer 2013/06/24 14:03:30 I think this code would be cleaner if all the matc
Massi 2013/07/01 13:10:49 Done.
2172 if (!phi_operand->representation().IsInteger32()) return 0;
2173
2174 if (phi_operand->IsAdd()) {
2175 HAdd* operation = HAdd::cast(phi_operand);
2176 if (operation->left() == phi) {
2177 if (operation->right()->IsInteger32Constant()) {
2178 return operation->right()->GetInteger32Constant();
2179 } else {
2180 return 0;
2181 }
2182 } else if (operation->right() == phi) {
2183 if (operation->left()->IsInteger32Constant()) {
2184 return operation->left()->GetInteger32Constant();
2185 } else {
2186 return 0;
2187 }
2188 } else {
2189 return 0;
2190 }
2191 } else if (phi_operand->IsSub()) {
2192 HSub* operation = HSub::cast(phi_operand);
2193 if (operation->left() == phi) {
2194 if (operation->right()->IsInteger32Constant()) {
2195 return -operation->right()->GetInteger32Constant();
2196 } else {
2197 return 0;
2198 }
2199 } else {
2200 return 0;
2201 }
2202 } else {
2203 return 0;
2204 }
2205 }
2206
2207
2208 HValue* InductionVariableData::DiscardOsrValue(HValue* v) {
titzer 2013/06/24 14:03:30 "DiscardOsrValue" implies something is being delet
Massi 2013/07/01 13:10:49 Done.
2209 if (!v->IsPhi()) return v;
2210 HPhi* phi = HPhi::cast(v);
2211 if (phi->OperandCount() != 2) return v;
2212 if (phi->OperandAt(0)->block()->is_osr_entry()) {
2213 return phi->OperandAt(1);
2214 } else if (phi->OperandAt(1)->block()->is_osr_entry()) {
2215 return phi->OperandAt(0);
2216 } else {
2217 return v;
2218 }
2219 }
2220
2221
2222 InductionVariableData* InductionVariableData::GetInductionVariableData(
2223 HValue* v) {
2224 v = DiscardOsrValue(v);
2225 if (v->IsPhi()) {
2226 return HPhi::cast(v)->induction_variable_data();
2227 }
2228 return NULL;
2229 }
2230
2231
2232 bool InductionVariableData::ValidateToken(Token::Value token) {
titzer 2013/06/24 14:03:30 Validate the token how? This is not clear.
Massi 2013/07/01 13:10:49 Renamed, and added comment.
2233 if (increment() > 0 && (token == Token::GT || token == Token::GTE)) {
2234 return false;
2235 }
2236 if (increment() < 0 && (token == Token::GT || token == Token::GTE)) {
2237 return false;
2238 }
2239 if (Token::IsInequalityOp(token) && increment() != 1 && increment() != -1) {
2240 return false;
2241 }
2242 return true;
2243 }
2244
2245
2246 bool InductionVariableData::CheckIfBranchIsLoopGuard(HBasicBlock* in_branch,
2247 HBasicBlock* out_branch) {
2248 return phi()->block()->current_loop()->IsNestedInThisLoop(in_branch) &&
2249 !phi()->block()->current_loop()->IsNestedInThisLoop(out_branch);
2250 }
2251
2252
2253 bool InductionVariableData::ComputeInductionVariableLimit(
2254 HBasicBlock* block,
2255 InductionVariableLimitUpdate* additional_limit) {
2256 if (block->predecessors()->length() != 1) return false;
2257 HBasicBlock* predecessor = block->predecessors()->at(0);
2258 HInstruction* end = predecessor->last();
2259
2260 if (!end->IsCompareIDAndBranch()) return false;
2261 HCompareIDAndBranch* branch = HCompareIDAndBranch::cast(end);
2262
2263 Token::Value token = branch->token();
2264 if (!Token::IsArithmeticCompareOp(token)) return false;
2265
2266 bool is_else_branch;
2267 HBasicBlock* other_target;
2268 if (block == branch->SuccessorAt(0)) {
2269 is_else_branch = false;
2270 other_target = branch->SuccessorAt(1);
2271 } else {
2272 is_else_branch = true;
2273 other_target = branch->SuccessorAt(0);
2274 ASSERT(block == branch->SuccessorAt(1));
2275 }
2276
2277 if (is_else_branch) {
2278 token = Token::NegateCompareOp(token);
2279 }
2280 bool limit_included = (Token::IsEqualityOp(token) ||
2281 token == Token::GTE || token == Token::LTE);
2282
2283 InductionVariableData* data;
2284
2285 data = GetInductionVariableData(branch->left());
2286 Token::Value actual_token = token;
2287 HValue* limit = branch->right();
2288 if (data == NULL) {
2289 data = GetInductionVariableData(branch->right());
2290 actual_token = Token::ReverseCompareOp(token);
2291 limit = branch->left();
2292 }
2293
2294 if (data != NULL) {
2295 if (data->ValidateToken(actual_token) &&
2296 data->CheckIfBranchIsLoopGuard(block, other_target)) {
2297 data->limit_ = limit;
2298 data->limit_included_ = limit_included;
2299 data->limit_validity_ = block;
2300 data->induction_exit_block_ = predecessor;
2301 data->induction_exit_target_ = other_target;
2302 return false;
2303 } else {
2304 additional_limit->updated_variable = data;
2305 additional_limit->limit = limit;
2306 additional_limit->limit_is_upper = (actual_token == Token::LTE ||
2307 actual_token == Token::LT ||
2308 actual_token == Token::NE);
2309 additional_limit->limit_is_included = limit_included;
2310 return true;
2311 }
2312 }
2313
2314 return false;
2315 }
2316
2317
1951 Range* HMathMinMax::InferRange(Zone* zone) { 2318 Range* HMathMinMax::InferRange(Zone* zone) {
1952 if (representation().IsInteger32()) { 2319 if (representation().IsInteger32()) {
1953 Range* a = left()->range(); 2320 Range* a = left()->range();
1954 Range* b = right()->range(); 2321 Range* b = right()->range();
1955 Range* res = a->Copy(zone); 2322 Range* res = a->Copy(zone);
1956 if (operation_ == kMathMax) { 2323 if (operation_ == kMathMax) {
1957 res->CombinedMax(b); 2324 res->CombinedMax(b);
1958 } else { 2325 } else {
1959 ASSERT(operation_ == kMathMin); 2326 ASSERT(operation_ == kMathMin);
1960 res->CombinedMin(b); 2327 res->CombinedMin(b);
(...skipping 1905 matching lines...) Expand 10 before | Expand all | Expand 10 after
3866 case kBackingStore: 4233 case kBackingStore:
3867 if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString()); 4234 if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString());
3868 stream->Add("[backing-store]"); 4235 stream->Add("[backing-store]");
3869 break; 4236 break;
3870 } 4237 }
3871 4238
3872 stream->Add("@%d", offset()); 4239 stream->Add("@%d", offset());
3873 } 4240 }
3874 4241
3875 } } // namespace v8::internal 4242 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698