Commit c74871f3 authored by mmassi@chromium.org's avatar mmassi@chromium.org

Fixed array bounds check elimination (Chromium issue 132114).

BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/10698125

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12025 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1007696c
......@@ -198,7 +198,7 @@ DEFINE_bool(trap_on_deopt, false, "put a break point before deoptimizing")
DEFINE_bool(deoptimize_uncommon_cases, true, "deoptimize uncommon cases")
DEFINE_bool(polymorphic_inlining, true, "polymorphic inlining")
DEFINE_bool(use_osr, true, "use on-stack replacement")
DEFINE_bool(array_bounds_checks_elimination, false,
DEFINE_bool(array_bounds_checks_elimination, true,
"perform array bounds checks elimination")
DEFINE_bool(array_index_dehoisting, false,
"perform array index dehoisting")
......
......@@ -3266,7 +3266,8 @@ class BoundsCheckBbData: public ZoneObject {
int32_t LowerOffset() const { return lower_offset_; }
int32_t UpperOffset() const { return upper_offset_; }
HBasicBlock* BasicBlock() const { return basic_block_; }
HBoundsCheck* Check() const { return check_; }
HBoundsCheck* LowerCheck() const { return lower_check_; }
HBoundsCheck* UpperCheck() const { return upper_check_; }
BoundsCheckBbData* NextInBasicBlock() const { return next_in_bb_; }
BoundsCheckBbData* FatherInDominatorTree() const { return father_in_dt_; }
......@@ -3274,76 +3275,85 @@ class BoundsCheckBbData: public ZoneObject {
return offset >= LowerOffset() && offset <= UpperOffset();
}
// This method removes new_check and modifies the current check so that it
// also "covers" what new_check covered.
// The obvious precondition is that new_check follows Check() in the
// same basic block, and that new_offset is not covered (otherwise we
// could simply remove new_check).
// As a consequence LowerOffset() or UpperOffset() change (the covered
bool HasSingleCheck() { return lower_check_ == upper_check_; }
// The goal of this method is to modify either upper_offset_ or
// lower_offset_ so that also new_offset is covered (the covered
// range grows).
//
// In the general case the check covering the current range should be like
// these two checks:
// 0 <= Key()->IndexBase() + LowerOffset()
// Key()->IndexBase() + UpperOffset() < Key()->Length()
//
// We can transform the second check like this:
// Key()->IndexBase() + LowerOffset() <
// Key()->Length() + (LowerOffset() - UpperOffset())
// so we can handle both checks with a single unsigned comparison.
// The precondition is that new_check follows UpperCheck() and
// LowerCheck() in the same basic block, and that new_offset is not
// covered (otherwise we could simply remove new_check).
//
// The bulk of this method changes Check()->index() and Check()->length()
// replacing them with new HAdd instructions to perform the transformation
// described above.
// If HasSingleCheck() is true then new_check is added as "second check"
// (either upper or lower; note that HasSingleCheck() becomes false).
// Otherwise one of the current checks is modified so that it also covers
// new_offset, and new_check is removed.
void CoverCheck(HBoundsCheck* new_check,
int32_t new_offset) {
ASSERT(new_check->index()->representation().IsInteger32());
bool keep_new_check = false;
if (new_offset > upper_offset_) {
upper_offset_ = new_offset;
if (HasSingleCheck()) {
keep_new_check = true;
upper_check_ = new_check;
} else {
BuildOffsetAdd(upper_check_,
&added_upper_index_,
&added_upper_offset_,
Key()->IndexBase(),
new_check->index()->representation(),
new_offset);
upper_check_->SetOperandAt(0, added_upper_index_);
}
} else if (new_offset < lower_offset_) {
lower_offset_ = new_offset;
if (HasSingleCheck()) {
keep_new_check = true;
lower_check_ = new_check;
} else {
BuildOffsetAdd(lower_check_,
&added_lower_index_,
&added_lower_offset_,
Key()->IndexBase(),
new_check->index()->representation(),
new_offset);
lower_check_->SetOperandAt(0, added_lower_index_);
}
} else {
ASSERT(false);
}
BuildOffsetAdd(&added_index_,
&added_index_offset_,
Key()->IndexBase(),
new_check->index()->representation(),
lower_offset_);
Check()->SetOperandAt(0, added_index_);
BuildOffsetAdd(&added_length_,
&added_length_offset_,
Key()->Length(),
new_check->length()->representation(),
lower_offset_ - upper_offset_);
Check()->SetOperandAt(1, added_length_);
new_check->DeleteAndReplaceWith(NULL);
if (!keep_new_check) {
new_check->DeleteAndReplaceWith(NULL);
}
}
void RemoveZeroOperations() {
RemoveZeroAdd(&added_index_, &added_index_offset_);
RemoveZeroAdd(&added_length_, &added_length_offset_);
RemoveZeroAdd(&added_lower_index_, &added_lower_offset_);
RemoveZeroAdd(&added_upper_index_, &added_upper_offset_);
}
BoundsCheckBbData(BoundsCheckKey* key,
int32_t lower_offset,
int32_t upper_offset,
HBasicBlock* bb,
HBoundsCheck* check,
HBoundsCheck* lower_check,
HBoundsCheck* upper_check,
BoundsCheckBbData* next_in_bb,
BoundsCheckBbData* father_in_dt)
: key_(key),
lower_offset_(lower_offset),
upper_offset_(upper_offset),
basic_block_(bb),
check_(check),
added_index_offset_(NULL),
added_index_(NULL),
added_length_offset_(NULL),
added_length_(NULL),
lower_check_(lower_check),
upper_check_(upper_check),
added_lower_index_(NULL),
added_lower_offset_(NULL),
added_upper_index_(NULL),
added_upper_offset_(NULL),
next_in_bb_(next_in_bb),
father_in_dt_(father_in_dt) { }
......@@ -3352,15 +3362,17 @@ class BoundsCheckBbData: public ZoneObject {
int32_t lower_offset_;
int32_t upper_offset_;
HBasicBlock* basic_block_;
HBoundsCheck* check_;
HConstant* added_index_offset_;
HAdd* added_index_;
HConstant* added_length_offset_;
HAdd* added_length_;
HBoundsCheck* lower_check_;
HBoundsCheck* upper_check_;
HAdd* added_lower_index_;
HConstant* added_lower_offset_;
HAdd* added_upper_index_;
HConstant* added_upper_offset_;
BoundsCheckBbData* next_in_bb_;
BoundsCheckBbData* father_in_dt_;
void BuildOffsetAdd(HAdd** add,
void BuildOffsetAdd(HBoundsCheck* check,
HAdd** add,
HConstant** constant,
HValue* original_value,
Representation representation,
......@@ -3369,12 +3381,12 @@ class BoundsCheckBbData: public ZoneObject {
HConstant(Handle<Object>(Smi::FromInt(new_offset)),
Representation::Integer32());
if (*add == NULL) {
new_constant->InsertBefore(Check());
new_constant->InsertBefore(check);
*add = new(BasicBlock()->zone()) HAdd(NULL,
original_value,
new_constant);
(*add)->AssumeRepresentation(representation);
(*add)->InsertBefore(Check());
(*add)->InsertBefore(check);
} else {
new_constant->InsertBefore(*add);
(*constant)->DeleteAndReplaceWith(new_constant);
......@@ -3447,6 +3459,7 @@ void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb,
offset,
bb,
check,
check,
bb_data_list,
NULL);
*data_p = bb_data_list;
......@@ -3465,7 +3478,8 @@ void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb,
new_lower_offset,
new_upper_offset,
bb,
check,
data->LowerCheck(),
data->UpperCheck(),
bb_data_list,
data);
table->Insert(key, bb_data_list, zone());
......
......@@ -123,7 +123,7 @@ check_test_minus(7,false);
// ALWAYS: 3
// NEVER: 4
if (false) {
// Test that we still deopt on failed bound checks
test_base(5,true);
test_base(6,true);
test_base(5,false);
......@@ -139,7 +139,21 @@ test_base(6,false);
%OptimizeFunctionOnNextCall(test_base);
test_base(2048,true);
assertTrue(%GetOptimizationStatus(test_base) != 1);
// Specific test on negative offsets
var short_a = new Array(100);
for (var i = 0; i < short_a.length; i++) short_a[i] = 0;
function short_test(a, i) {
a[i + 9] = 0;
a[i - 10] = 0;
}
short_test(short_a, 50);
short_test(short_a, 50);
%OptimizeFunctionOnNextCall(short_test);
short_a.length = 10;
short_test(a, 0);
assertTrue(%GetOptimizationStatus(short_test) != 1);
gc();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment