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

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

Issue 172093002: Fix Hydrogen bounds check elimination (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 10 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
« no previous file with comments | « no previous file | test/mjsunit/regress/regress-crbug-344186.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 } else { 84 } else {
85 *offset = 0; 85 *offset = 0;
86 index_base = check->index(); 86 index_base = check->index();
87 } 87 }
88 88
89 return new(zone) BoundsCheckKey(index_base, check->length()); 89 return new(zone) BoundsCheckKey(index_base, check->length());
90 } 90 }
91 91
92 private: 92 private:
93 BoundsCheckKey(HValue* index_base, HValue* length) 93 BoundsCheckKey(HValue* index_base, HValue* length)
94 : index_base_(index_base), 94 : index_base_(index_base),
95 length_(length) { } 95 length_(length) { }
96 96
97 HValue* index_base_; 97 HValue* index_base_;
98 HValue* length_; 98 HValue* length_;
99 99
100 DISALLOW_COPY_AND_ASSIGN(BoundsCheckKey); 100 DISALLOW_COPY_AND_ASSIGN(BoundsCheckKey);
101 }; 101 };
102 102
103 103
104 // Data about each HBoundsCheck that can be eliminated or moved. 104 // Data about each HBoundsCheck that can be eliminated or moved.
105 // It is the "value" in the dictionary indexed by "base-index, length" 105 // It is the "value" in the dictionary indexed by "base-index, length"
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 // range grows). 137 // range grows).
138 // 138 //
139 // The precondition is that new_check follows UpperCheck() and 139 // The precondition is that new_check follows UpperCheck() and
140 // LowerCheck() in the same basic block, and that new_offset is not 140 // LowerCheck() in the same basic block, and that new_offset is not
141 // covered (otherwise we could simply remove new_check). 141 // covered (otherwise we could simply remove new_check).
142 // 142 //
143 // If HasSingleCheck() is true then new_check is added as "second check" 143 // If HasSingleCheck() is true then new_check is added as "second check"
144 // (either upper or lower; note that HasSingleCheck() becomes false). 144 // (either upper or lower; note that HasSingleCheck() becomes false).
145 // Otherwise one of the current checks is modified so that it also covers 145 // Otherwise one of the current checks is modified so that it also covers
146 // new_offset, and new_check is removed. 146 // new_offset, and new_check is removed.
147 // 147 void CoverCheck(HBoundsCheck* new_check,
148 // If the check cannot be modified because the context is unknown it
149 // returns false, otherwise it returns true.
150 bool CoverCheck(HBoundsCheck* new_check,
151 int32_t new_offset) { 148 int32_t new_offset) {
152 ASSERT(new_check->index()->representation().IsSmiOrInteger32()); 149 ASSERT(new_check->index()->representation().IsSmiOrInteger32());
153 bool keep_new_check = false; 150 bool keep_new_check = false;
154 151
155 if (new_offset > upper_offset_) { 152 if (new_offset > upper_offset_) {
156 upper_offset_ = new_offset; 153 upper_offset_ = new_offset;
157 if (HasSingleCheck()) { 154 if (HasSingleCheck()) {
158 keep_new_check = true; 155 keep_new_check = true;
159 upper_check_ = new_check; 156 upper_check_ = new_check;
160 } else { 157 } else {
161 bool result = BuildOffsetAdd(upper_check_, 158 TightenCheck(upper_check_, new_check);
162 &added_upper_index_,
163 &added_upper_offset_,
164 Key()->IndexBase(),
165 new_check->index()->representation(),
166 new_offset);
167 if (!result) return false;
168 upper_check_->ReplaceAllUsesWith(upper_check_->index());
169 upper_check_->SetOperandAt(0, added_upper_index_);
170 } 159 }
171 } else if (new_offset < lower_offset_) { 160 } else if (new_offset < lower_offset_) {
172 lower_offset_ = new_offset; 161 lower_offset_ = new_offset;
173 if (HasSingleCheck()) { 162 if (HasSingleCheck()) {
174 keep_new_check = true; 163 keep_new_check = true;
175 lower_check_ = new_check; 164 lower_check_ = new_check;
176 } else { 165 } else {
177 bool result = BuildOffsetAdd(lower_check_, 166 TightenCheck(lower_check_, new_check);
178 &added_lower_index_,
179 &added_lower_offset_,
180 Key()->IndexBase(),
181 new_check->index()->representation(),
182 new_offset);
183 if (!result) return false;
184 lower_check_->ReplaceAllUsesWith(lower_check_->index());
185 lower_check_->SetOperandAt(0, added_lower_index_);
186 } 167 }
187 } else { 168 } else {
188 ASSERT(false); 169 // Should never have called CoverCheck() in this case.
170 UNREACHABLE();
189 } 171 }
190 172
191 if (!keep_new_check) { 173 if (!keep_new_check) {
192 new_check->block()->graph()->isolate()->counters()-> 174 new_check->block()->graph()->isolate()->counters()->
193 bounds_checks_eliminated()->Increment(); 175 bounds_checks_eliminated()->Increment();
194 new_check->DeleteAndReplaceWith(new_check->ActualValue()); 176 new_check->DeleteAndReplaceWith(new_check->ActualValue());
177 } else {
178 HBoundsCheck* first_check = new_check == lower_check_ ? upper_check_
179 : lower_check_;
180 // The length is guaranteed to be live at first_check.
181 ASSERT(new_check->length() == first_check->length());
182 HInstruction* old_position = new_check->next();
183 new_check->Unlink();
184 new_check->InsertAfter(first_check);
185 MoveIndexIfNecessary(new_check->index(), new_check, old_position);
195 } 186 }
196
197 return true;
198 }
199
200 void RemoveZeroOperations() {
201 RemoveZeroAdd(&added_lower_index_, &added_lower_offset_);
202 RemoveZeroAdd(&added_upper_index_, &added_upper_offset_);
203 } 187 }
204 188
205 BoundsCheckBbData(BoundsCheckKey* key, 189 BoundsCheckBbData(BoundsCheckKey* key,
206 int32_t lower_offset, 190 int32_t lower_offset,
207 int32_t upper_offset, 191 int32_t upper_offset,
208 HBasicBlock* bb, 192 HBasicBlock* bb,
209 HBoundsCheck* lower_check, 193 HBoundsCheck* lower_check,
210 HBoundsCheck* upper_check, 194 HBoundsCheck* upper_check,
211 BoundsCheckBbData* next_in_bb, 195 BoundsCheckBbData* next_in_bb,
212 BoundsCheckBbData* father_in_dt) 196 BoundsCheckBbData* father_in_dt)
213 : key_(key), 197 : key_(key),
214 lower_offset_(lower_offset), 198 lower_offset_(lower_offset),
215 upper_offset_(upper_offset), 199 upper_offset_(upper_offset),
216 basic_block_(bb), 200 basic_block_(bb),
217 lower_check_(lower_check), 201 lower_check_(lower_check),
218 upper_check_(upper_check), 202 upper_check_(upper_check),
219 added_lower_index_(NULL), 203 next_in_bb_(next_in_bb),
220 added_lower_offset_(NULL), 204 father_in_dt_(father_in_dt) { }
221 added_upper_index_(NULL),
222 added_upper_offset_(NULL),
223 next_in_bb_(next_in_bb),
224 father_in_dt_(father_in_dt) { }
225 205
226 private: 206 private:
227 BoundsCheckKey* key_; 207 BoundsCheckKey* key_;
228 int32_t lower_offset_; 208 int32_t lower_offset_;
229 int32_t upper_offset_; 209 int32_t upper_offset_;
230 HBasicBlock* basic_block_; 210 HBasicBlock* basic_block_;
231 HBoundsCheck* lower_check_; 211 HBoundsCheck* lower_check_;
232 HBoundsCheck* upper_check_; 212 HBoundsCheck* upper_check_;
233 HInstruction* added_lower_index_;
234 HConstant* added_lower_offset_;
235 HInstruction* added_upper_index_;
236 HConstant* added_upper_offset_;
237 BoundsCheckBbData* next_in_bb_; 213 BoundsCheckBbData* next_in_bb_;
238 BoundsCheckBbData* father_in_dt_; 214 BoundsCheckBbData* father_in_dt_;
239 215
240 // Given an existing add instruction and a bounds check it tries to 216 void MoveIndexIfNecessary(HValue* index_raw,
241 // find the current context (either of the add or of the check index). 217 HBoundsCheck* insert_before,
242 HValue* IndexContext(HInstruction* add, HBoundsCheck* check) { 218 HInstruction* end_of_scan_range) {
243 if (add != NULL && add->IsAdd()) { 219 ASSERT(index_raw->IsAdd() || index_raw->IsSub());
244 return HAdd::cast(add)->context(); 220 HArithmeticBinaryOperation* index =
221 HArithmeticBinaryOperation::cast(index_raw);
222 HValue* left_input = index->left();
223 HValue* right_input = index->right();
224 bool must_move_index = false;
225 bool must_move_left_input = false;
226 bool must_move_right_input = false;
227 for (HInstruction* cursor = end_of_scan_range; cursor != insert_before;) {
228 if (cursor == left_input) must_move_left_input = true;
229 if (cursor == right_input) must_move_right_input = true;
230 if (cursor == index) must_move_index = true;
231 if (cursor->previous() == NULL) {
232 cursor = cursor->block()->dominator()->end();
233 } else {
234 cursor = cursor->previous();
235 }
245 } 236 }
246 if (check->index()->IsBinaryOperation()) { 237 if (must_move_index) {
247 return HBinaryOperation::cast(check->index())->context(); 238 index->Unlink();
239 index->InsertBefore(insert_before);
248 } 240 }
249 return NULL; 241 // The BCE algorithm only selects mergeable bounds checks that share
250 } 242 // the same "index_base", so we'll only ever have to move constants.
251 243 if (must_move_left_input) {
252 // This function returns false if it cannot build the add because the 244 HConstant::cast(left_input)->Unlink();
253 // current context cannot be determined. 245 HConstant::cast(left_input)->InsertBefore(index);
254 bool BuildOffsetAdd(HBoundsCheck* check,
255 HInstruction** add,
256 HConstant** constant,
257 HValue* original_value,
258 Representation representation,
259 int32_t new_offset) {
260 HValue* index_context = IndexContext(*add, check);
261 if (index_context == NULL) return false;
262
263 Zone* zone = BasicBlock()->zone();
264 HConstant* new_constant = HConstant::New(zone, index_context,
265 new_offset, representation);
266 if (*add == NULL) {
267 new_constant->InsertBefore(check);
268 (*add) = HAdd::New(zone, index_context, original_value, new_constant);
269 (*add)->AssumeRepresentation(representation);
270 (*add)->InsertBefore(check);
271 } else {
272 new_constant->InsertBefore(*add);
273 (*constant)->DeleteAndReplaceWith(new_constant);
274 } 246 }
275 *constant = new_constant; 247 if (must_move_right_input) {
276 return true; 248 HConstant::cast(right_input)->Unlink();
277 } 249 HConstant::cast(right_input)->InsertBefore(index);
278
279 void RemoveZeroAdd(HInstruction** add, HConstant** constant) {
280 if (*add != NULL && (*add)->IsAdd() && (*constant)->Integer32Value() == 0) {
281 (*add)->DeleteAndReplaceWith(HAdd::cast(*add)->left());
282 (*constant)->DeleteAndReplaceWith(NULL);
283 } 250 }
284 } 251 }
285 252
253 void TightenCheck(HBoundsCheck* original_check,
254 HBoundsCheck* tighter_check) {
255 ASSERT(original_check->length() == tighter_check->length());
256 MoveIndexIfNecessary(tighter_check->index(), original_check, tighter_check);
257 original_check->ReplaceAllUsesWith(original_check->index());
258 original_check->SetOperandAt(0, tighter_check->index());
259 }
260
286 DISALLOW_COPY_AND_ASSIGN(BoundsCheckBbData); 261 DISALLOW_COPY_AND_ASSIGN(BoundsCheckBbData);
287 }; 262 };
288 263
289 264
290 static bool BoundsCheckKeyMatch(void* key1, void* key2) { 265 static bool BoundsCheckKeyMatch(void* key1, void* key2) {
291 BoundsCheckKey* k1 = static_cast<BoundsCheckKey*>(key1); 266 BoundsCheckKey* k1 = static_cast<BoundsCheckKey*>(key1);
292 BoundsCheckKey* k2 = static_cast<BoundsCheckKey*>(key2); 267 BoundsCheckKey* k2 = static_cast<BoundsCheckKey*>(key2);
293 return k1->IndexBase() == k2->IndexBase() && k1->Length() == k2->Length(); 268 return k1->IndexBase() == k2->IndexBase() && k1->Length() == k2->Length();
294 } 269 }
295 270
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 bb, 362 bb,
388 check, 363 check,
389 check, 364 check,
390 bb_data_list, 365 bb_data_list,
391 NULL); 366 NULL);
392 *data_p = bb_data_list; 367 *data_p = bb_data_list;
393 } else if (data->OffsetIsCovered(offset)) { 368 } else if (data->OffsetIsCovered(offset)) {
394 bb->graph()->isolate()->counters()-> 369 bb->graph()->isolate()->counters()->
395 bounds_checks_eliminated()->Increment(); 370 bounds_checks_eliminated()->Increment();
396 check->DeleteAndReplaceWith(check->ActualValue()); 371 check->DeleteAndReplaceWith(check->ActualValue());
397 } else if (data->BasicBlock() != bb || 372 } else if (data->BasicBlock() == bb) {
398 !data->CoverCheck(check, offset)) { 373 data->CoverCheck(check, offset);
399 // If the check is in the current BB we try to modify it by calling 374 } else {
400 // "CoverCheck", but if also that fails we record the current offsets
401 // in a new data instance because from now on they are covered.
402 int32_t new_lower_offset = offset < data->LowerOffset() 375 int32_t new_lower_offset = offset < data->LowerOffset()
403 ? offset 376 ? offset
404 : data->LowerOffset(); 377 : data->LowerOffset();
405 int32_t new_upper_offset = offset > data->UpperOffset() 378 int32_t new_upper_offset = offset > data->UpperOffset()
406 ? offset 379 ? offset
407 : data->UpperOffset(); 380 : data->UpperOffset();
408 bb_data_list = new(zone()) BoundsCheckBbData(key, 381 bb_data_list = new(zone()) BoundsCheckBbData(key,
409 new_lower_offset, 382 new_lower_offset,
410 new_upper_offset, 383 new_upper_offset,
411 bb, 384 bb,
412 data->LowerCheck(), 385 data->LowerCheck(),
413 data->UpperCheck(), 386 data->UpperCheck(),
414 bb_data_list, 387 bb_data_list,
415 data); 388 data);
416 table_.Insert(key, bb_data_list, zone()); 389 table_.Insert(key, bb_data_list, zone());
417 } 390 }
418 } 391 }
419 392
420 return bb_data_list; 393 return bb_data_list;
421 } 394 }
422 395
423 396
424 void HBoundsCheckEliminationPhase::PostProcessBlock( 397 void HBoundsCheckEliminationPhase::PostProcessBlock(
425 HBasicBlock* block, BoundsCheckBbData* data) { 398 HBasicBlock* block, BoundsCheckBbData* data) {
426 while (data != NULL) { 399 while (data != NULL) {
427 data->RemoveZeroOperations();
428 if (data->FatherInDominatorTree()) { 400 if (data->FatherInDominatorTree()) {
429 table_.Insert(data->Key(), data->FatherInDominatorTree(), zone()); 401 table_.Insert(data->Key(), data->FatherInDominatorTree(), zone());
430 } else { 402 } else {
431 table_.Delete(data->Key()); 403 table_.Delete(data->Key());
432 } 404 }
433 data = data->NextInBasicBlock(); 405 data = data->NextInBasicBlock();
434 } 406 }
435 } 407 }
436 408
437 } } // namespace v8::internal 409 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | test/mjsunit/regress/regress-crbug-344186.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698