Commit 2fd1e1bb authored by mmassi@chromium.org's avatar mmassi@chromium.org

Array index computation dehoisting.

When an array index (in an array access) is a simple "expression + constant", just embed the constant in the array access operation so that the full index expression is (potentially) no longer used and its live range can be much shorter.
This is effective in conjunction with array bounds check removal (otherwise the index is anyway used in the check).

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11596 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 750e2cda
......@@ -1236,6 +1236,7 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......@@ -1252,13 +1253,13 @@ class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
LOperand* key) {
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
......@@ -1272,6 +1273,7 @@ class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......@@ -1740,6 +1742,7 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
LOperand* object() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......@@ -1762,6 +1765,7 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
};
......@@ -1806,6 +1810,7 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......
......@@ -2744,7 +2744,9 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
// Load the result.
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
__ ldr(result, FieldMemOperand(scratch, FixedArray::kHeaderSize));
uint32_t offset = FixedArray::kHeaderSize +
(instr->additional_index() << kPointerSizeLog2);
__ ldr(result, FieldMemOperand(scratch, offset));
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
......@@ -2776,13 +2778,14 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
}
Operand operand = key_is_constant
? Operand(constant_key * (1 << shift_size) +
? Operand(((constant_key + instr->additional_index()) << shift_size) +
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
: Operand(key, LSL, shift_size);
__ add(elements, elements, operand);
if (!key_is_constant) {
__ add(elements, elements,
Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
Operand((FixedDoubleArray::kHeaderSize - kHeapObjectTag) +
(instr->additional_index() << shift_size)));
}
__ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
......@@ -2809,26 +2812,33 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
key = ToRegister(instr->key());
}
int shift_size = ElementsKindToShiftSize(elements_kind);
int additional_offset = instr->additional_index() << shift_size;
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister result = ToDoubleRegister(instr->result());
Operand operand = key_is_constant
? Operand(constant_key * (1 << shift_size))
? Operand(constant_key << shift_size)
: Operand(key, LSL, shift_size);
__ add(scratch0(), external_pointer, operand);
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ vldr(result.low(), scratch0(), 0);
__ vldr(result.low(), scratch0(), additional_offset);
__ vcvt_f64_f32(result, result.low());
} else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
__ vldr(result, scratch0(), 0);
__ vldr(result, scratch0(), additional_offset);
}
} else {
Register result = ToRegister(instr->result());
if (instr->additional_index() != 0 && !key_is_constant) {
__ add(scratch0(), key, Operand(instr->additional_index()));
}
MemOperand mem_operand(key_is_constant
? MemOperand(external_pointer, constant_key * (1 << shift_size))
: MemOperand(external_pointer, key, LSL, shift_size));
? MemOperand(external_pointer,
(constant_key << shift_size) + additional_offset)
: (instr->additional_index() == 0
? MemOperand(external_pointer, key, LSL, shift_size)
: MemOperand(external_pointer, scratch0(), LSL, shift_size)));
switch (elements_kind) {
case EXTERNAL_BYTE_ELEMENTS:
__ ldrsb(result, mem_operand);
......@@ -3726,10 +3736,16 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
int offset =
ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
(ToInteger32(const_operand) + instr->additional_index()) * kPointerSize
+ FixedArray::kHeaderSize;
__ str(value, FieldMemOperand(elements, offset));
} else {
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
if (instr->additional_index() != 0) {
__ add(scratch,
scratch,
Operand(instr->additional_index() << kPointerSizeLog2));
}
__ str(value, FieldMemOperand(scratch, FixedArray::kHeaderSize));
}
......@@ -3771,7 +3787,7 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
}
int shift_size = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
Operand operand = key_is_constant
? Operand(constant_key * (1 << shift_size) +
? Operand((constant_key << shift_size) +
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
: Operand(key, LSL, shift_size);
__ add(scratch, elements, operand);
......@@ -3789,7 +3805,7 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
vs);
}
__ vstr(value, scratch, 0);
__ vstr(value, scratch, instr->additional_index() << shift_size);
}
......@@ -3810,25 +3826,33 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
key = ToRegister(instr->key());
}
int shift_size = ElementsKindToShiftSize(elements_kind);
int additional_offset = instr->additional_index() << shift_size;
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister value(ToDoubleRegister(instr->value()));
Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
Operand operand(key_is_constant ? Operand(constant_key << shift_size)
: Operand(key, LSL, shift_size));
__ add(scratch0(), external_pointer, operand);
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ vcvt_f32_f64(double_scratch0().low(), value);
__ vstr(double_scratch0().low(), scratch0(), 0);
__ vstr(double_scratch0().low(), scratch0(), additional_offset);
} else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
__ vstr(value, scratch0(), 0);
__ vstr(value, scratch0(), additional_offset);
}
} else {
Register value(ToRegister(instr->value()));
if (instr->additional_index() != 0 && !key_is_constant) {
__ add(scratch0(), key, Operand(instr->additional_index()));
}
MemOperand mem_operand(key_is_constant
? MemOperand(external_pointer, constant_key * (1 << shift_size))
: MemOperand(external_pointer, key, LSL, shift_size));
? MemOperand(external_pointer,
((constant_key + instr->additional_index())
<< shift_size))
: (instr->additional_index() == 0
? MemOperand(external_pointer, key, LSL, shift_size)
: MemOperand(external_pointer, scratch0(), LSL, shift_size)));
switch (elements_kind) {
case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
......
......@@ -197,6 +197,8 @@ DEFINE_bool(polymorphic_inlining, true, "polymorphic inlining")
DEFINE_bool(use_osr, true, "use on-stack replacement")
DEFINE_bool(array_bounds_checks_elimination, true,
"perform array bounds checks elimination")
DEFINE_bool(array_index_dehoisting, true,
"perform array index dehoisting")
DEFINE_bool(trace_osr, false, "trace on-stack replacement")
DEFINE_int(stress_runs, 0, "number of stress runs")
......
......@@ -3946,15 +3946,27 @@ class HLoadFunctionPrototype: public HUnaryOperation {
virtual bool DataEquals(HValue* other) { return true; }
};
class ArrayInstructionInterface {
public:
virtual HValue* GetKey() = 0;
virtual void SetKey(HValue* key) = 0;
virtual void SetIndexOffset(uint32_t index_offset) = 0;
virtual bool IsDehoisted() = 0;
virtual void SetDehoisted(bool is_dehoisted) = 0;
virtual ~ArrayInstructionInterface() { };
};
class HLoadKeyedFastElement: public HTemplateInstruction<2> {
class HLoadKeyedFastElement
: public HTemplateInstruction<2>, public ArrayInstructionInterface {
public:
enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK };
HLoadKeyedFastElement(HValue* obj,
HValue* key,
HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK)
: hole_check_mode_(hole_check_mode) {
: hole_check_mode_(hole_check_mode),
index_offset_(0),
is_dehoisted_(false) {
SetOperandAt(0, obj);
SetOperandAt(1, key);
set_representation(Representation::Tagged());
......@@ -3964,6 +3976,12 @@ class HLoadKeyedFastElement: public HTemplateInstruction<2> {
HValue* object() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
uint32_t index_offset() { return index_offset_; }
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
HValue* GetKey() { return key(); }
void SetKey(HValue* key) { SetOperandAt(1, key); }
bool IsDehoisted() { return is_dehoisted_; }
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
virtual Representation RequiredInputRepresentation(int index) {
// The key is supposed to be Integer32.
......@@ -3982,17 +4000,23 @@ class HLoadKeyedFastElement: public HTemplateInstruction<2> {
virtual bool DataEquals(HValue* other) {
if (!other->IsLoadKeyedFastElement()) return false;
HLoadKeyedFastElement* other_load = HLoadKeyedFastElement::cast(other);
if (is_dehoisted_ && index_offset_ != other_load->index_offset_)
return false;
return hole_check_mode_ == other_load->hole_check_mode_;
}
private:
HoleCheckMode hole_check_mode_;
uint32_t index_offset_;
bool is_dehoisted_;
};
class HLoadKeyedFastDoubleElement: public HTemplateInstruction<2> {
class HLoadKeyedFastDoubleElement
: public HTemplateInstruction<2>, public ArrayInstructionInterface {
public:
HLoadKeyedFastDoubleElement(HValue* elements, HValue* key) {
HLoadKeyedFastDoubleElement(HValue* elements, HValue* key)
: index_offset_(0), is_dehoisted_(false) {
SetOperandAt(0, elements);
SetOperandAt(1, key);
set_representation(Representation::Double());
......@@ -4002,6 +4026,12 @@ class HLoadKeyedFastDoubleElement: public HTemplateInstruction<2> {
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
uint32_t index_offset() { return index_offset_; }
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
HValue* GetKey() { return key(); }
void SetKey(HValue* key) { SetOperandAt(1, key); }
bool IsDehoisted() { return is_dehoisted_; }
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
virtual Representation RequiredInputRepresentation(int index) {
// The key is supposed to be Integer32.
......@@ -4016,15 +4046,22 @@ class HLoadKeyedFastDoubleElement: public HTemplateInstruction<2> {
protected:
virtual bool DataEquals(HValue* other) { return true; }
private:
uint32_t index_offset_;
bool is_dehoisted_;
};
class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
class HLoadKeyedSpecializedArrayElement
: public HTemplateInstruction<2>, public ArrayInstructionInterface {
public:
HLoadKeyedSpecializedArrayElement(HValue* external_elements,
HValue* key,
ElementsKind elements_kind)
: elements_kind_(elements_kind) {
: elements_kind_(elements_kind),
index_offset_(0),
is_dehoisted_(false) {
SetOperandAt(0, external_elements);
SetOperandAt(1, key);
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
......@@ -4052,6 +4089,12 @@ class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
HValue* external_pointer() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
ElementsKind elements_kind() const { return elements_kind_; }
uint32_t index_offset() { return index_offset_; }
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
HValue* GetKey() { return key(); }
void SetKey(HValue* key) { SetOperandAt(1, key); }
bool IsDehoisted() { return is_dehoisted_; }
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
virtual Range* InferRange(Zone* zone);
......@@ -4067,6 +4110,8 @@ class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
private:
ElementsKind elements_kind_;
uint32_t index_offset_;
bool is_dehoisted_;
};
......@@ -4188,11 +4233,12 @@ class HStoreNamedGeneric: public HTemplateInstruction<3> {
};
class HStoreKeyedFastElement: public HTemplateInstruction<3> {
class HStoreKeyedFastElement
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
HStoreKeyedFastElement(HValue* obj, HValue* key, HValue* val,
ElementsKind elements_kind = FAST_ELEMENTS)
: elements_kind_(elements_kind) {
: elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) {
SetOperandAt(0, obj);
SetOperandAt(1, key);
SetOperandAt(2, val);
......@@ -4212,6 +4258,12 @@ class HStoreKeyedFastElement: public HTemplateInstruction<3> {
bool value_is_smi() {
return elements_kind_ == FAST_SMI_ONLY_ELEMENTS;
}
uint32_t index_offset() { return index_offset_; }
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
HValue* GetKey() { return key(); }
void SetKey(HValue* key) { SetOperandAt(1, key); }
bool IsDehoisted() { return is_dehoisted_; }
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
bool NeedsWriteBarrier() {
if (value_is_smi()) {
......@@ -4227,14 +4279,18 @@ class HStoreKeyedFastElement: public HTemplateInstruction<3> {
private:
ElementsKind elements_kind_;
uint32_t index_offset_;
bool is_dehoisted_;
};
class HStoreKeyedFastDoubleElement: public HTemplateInstruction<3> {
class HStoreKeyedFastDoubleElement
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
HStoreKeyedFastDoubleElement(HValue* elements,
HValue* key,
HValue* val) {
HValue* val)
: index_offset_(0), is_dehoisted_(false) {
SetOperandAt(0, elements);
SetOperandAt(1, key);
SetOperandAt(2, val);
......@@ -4254,6 +4310,12 @@ class HStoreKeyedFastDoubleElement: public HTemplateInstruction<3> {
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
uint32_t index_offset() { return index_offset_; }
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
HValue* GetKey() { return key(); }
void SetKey(HValue* key) { SetOperandAt(1, key); }
bool IsDehoisted() { return is_dehoisted_; }
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
bool NeedsWriteBarrier() {
return StoringValueNeedsWriteBarrier(value());
......@@ -4264,16 +4326,21 @@ class HStoreKeyedFastDoubleElement: public HTemplateInstruction<3> {
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement)
private:
uint32_t index_offset_;
bool is_dehoisted_;
};
class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
class HStoreKeyedSpecializedArrayElement
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
HStoreKeyedSpecializedArrayElement(HValue* external_elements,
HValue* key,
HValue* val,
ElementsKind elements_kind)
: elements_kind_(elements_kind) {
: elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) {
SetGVNFlag(kChangesSpecializedArrayElements);
SetOperandAt(0, external_elements);
SetOperandAt(1, key);
......@@ -4301,11 +4368,19 @@ class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
ElementsKind elements_kind() const { return elements_kind_; }
uint32_t index_offset() { return index_offset_; }
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
HValue* GetKey() { return key(); }
void SetKey(HValue* key) { SetOperandAt(1, key); }
bool IsDehoisted() { return is_dehoisted_; }
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement)
private:
ElementsKind elements_kind_;
uint32_t index_offset_;
bool is_dehoisted_;
};
......
......@@ -2758,6 +2758,7 @@ HGraph* HGraphBuilder::CreateGraph() {
sce.Process();
graph()->EliminateRedundantBoundsChecks();
graph()->DehoistSimpleArrayIndexComputations();
return graph();
}
......@@ -3016,7 +3017,6 @@ void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb,
HBoundsCheck* check = HBoundsCheck::cast(i);
check->ReplaceAllUsesWith(check->index());
isolate()->counters()->array_bounds_checks_seen()->Increment();
if (!FLAG_array_bounds_checks_elimination) continue;
int32_t offset;
......@@ -3035,10 +3035,8 @@ void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb,
*data_p = bb_data_list;
} else if (data->OffsetIsCovered(offset)) {
check->DeleteAndReplaceWith(NULL);
isolate()->counters()->array_bounds_checks_removed()->Increment();
} else if (data->BasicBlock() == bb) {
data->CoverCheck(check, offset);
isolate()->counters()->array_bounds_checks_removed()->Increment();
} else {
int32_t new_lower_offset = offset < data->LowerOffset()
? offset
......@@ -3082,6 +3080,93 @@ void HGraph::EliminateRedundantBoundsChecks() {
}
static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) {
HValue* index = array_operation->GetKey();
HConstant* constant;
HValue* subexpression;
int32_t sign;
if (index->IsAdd()) {
sign = 1;
HAdd* add = HAdd::cast(index);
if (add->left()->IsConstant()) {
subexpression = add->right();
constant = HConstant::cast(add->left());
} else if (add->right()->IsConstant()) {
subexpression = add->left();
constant = HConstant::cast(add->right());
} else {
return;
}
} else if (index->IsSub()) {
sign = -1;
HSub* sub = HSub::cast(index);
if (sub->left()->IsConstant()) {
subexpression = sub->right();
constant = HConstant::cast(sub->left());
} else if (sub->right()->IsConstant()) {
subexpression = sub->left();
constant = HConstant::cast(sub->right());
} return;
} else {
return;
}
if (!constant->HasInteger32Value()) return;
int32_t value = constant->Integer32Value() * sign;
// We limit offset values to 30 bits because we want to avoid the risk of
// overflows when the offset is added to the object header size.
if (value >= 1 << 30 || value < 0) return;
array_operation->SetKey(subexpression);
if (index->HasNoUses()) {
index->DeleteAndReplaceWith(NULL);
}
ASSERT(value >= 0);
array_operation->SetIndexOffset(static_cast<uint32_t>(value));
array_operation->SetDehoisted(true);
}
void HGraph::DehoistSimpleArrayIndexComputations() {
if (!FLAG_array_index_dehoisting) return;
HPhase phase("H_Dehoist index computations", this);
for (int i = 0; i < blocks()->length(); ++i) {
for (HInstruction* instr = blocks()->at(i)->first();
instr != NULL;
instr = instr->next()) {
ArrayInstructionInterface* array_instruction = NULL;
if (instr->IsLoadKeyedFastElement()) {
HLoadKeyedFastElement* op = HLoadKeyedFastElement::cast(instr);
array_instruction = static_cast<ArrayInstructionInterface*>(op);
} else if (instr->IsLoadKeyedFastDoubleElement()) {
HLoadKeyedFastDoubleElement* op =
HLoadKeyedFastDoubleElement::cast(instr);
array_instruction = static_cast<ArrayInstructionInterface*>(op);
} else if (instr->IsLoadKeyedSpecializedArrayElement()) {
HLoadKeyedSpecializedArrayElement* op =
HLoadKeyedSpecializedArrayElement::cast(instr);
array_instruction = static_cast<ArrayInstructionInterface*>(op);
} else if (instr->IsStoreKeyedFastElement()) {
HStoreKeyedFastElement* op = HStoreKeyedFastElement::cast(instr);
array_instruction = static_cast<ArrayInstructionInterface*>(op);
} else if (instr->IsStoreKeyedFastDoubleElement()) {
HStoreKeyedFastDoubleElement* op =
HStoreKeyedFastDoubleElement::cast(instr);
array_instruction = static_cast<ArrayInstructionInterface*>(op);
} else if (instr->IsStoreKeyedSpecializedArrayElement()) {
HStoreKeyedSpecializedArrayElement* op =
HStoreKeyedSpecializedArrayElement::cast(instr);
array_instruction = static_cast<ArrayInstructionInterface*>(op);
} else {
continue;
}
DehoistArrayIndex(array_instruction);
}
}
}
HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
ASSERT(current_block() != NULL);
current_block()->AddInstruction(instr);
......
......@@ -267,6 +267,7 @@ class HGraph: public ZoneObject {
void AssignDominators();
void ReplaceCheckedValues();
void EliminateRedundantBoundsChecks();
void DehoistSimpleArrayIndexComputations();
void PropagateDeoptimizingMark();
// Returns false if there are phi-uses of the arguments-object
......
......@@ -2421,9 +2421,11 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
// Load the result.
__ mov(result,
BuildFastArrayOperand(instr->elements(), instr->key(),
BuildFastArrayOperand(instr->elements(),
instr->key(),
FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag));
FixedArray::kHeaderSize - kHeapObjectTag,
instr->additional_index()));
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
......@@ -2442,13 +2444,17 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(), instr->key(),
FAST_DOUBLE_ELEMENTS,
offset);
offset,
instr->additional_index());
__ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
DeoptimizeIf(equal, instr->environment());
Operand double_load_operand = BuildFastArrayOperand(
instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
instr->elements(),
instr->key(),
FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
__ movdbl(result, double_load_operand);
}
......@@ -2457,7 +2463,8 @@ Operand LCodeGen::BuildFastArrayOperand(
LOperand* elements_pointer,
LOperand* key,
ElementsKind elements_kind,
uint32_t offset) {
uint32_t offset,
uint32_t additional_index) {
Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) {
......@@ -2466,10 +2473,14 @@ Operand LCodeGen::BuildFastArrayOperand(
Abort("array index constant value too big");
}
return Operand(elements_pointer_reg,
constant_value * (1 << shift_size) + offset);
((constant_value + additional_index) << shift_size)
+ offset);
} else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
return Operand(elements_pointer_reg, ToRegister(key), scale_factor, offset);
return Operand(elements_pointer_reg,
ToRegister(key),
scale_factor,
offset + (additional_index << shift_size));
}
}
......@@ -2478,7 +2489,10 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
instr->key(),
elements_kind,
0,
instr->additional_index()));
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
......@@ -3415,7 +3429,10 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
instr->key(),
elements_kind,
0,
instr->additional_index()));
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
__ movss(operand, xmm0);
......@@ -3456,31 +3473,21 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
Register elements = ToRegister(instr->object());
Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
// Do the store.
if (instr->key()->IsConstantOperand()) {
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
int offset =
ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
__ mov(FieldOperand(elements, offset), value);
} else {
__ mov(FieldOperand(elements,
key,
times_pointer_size,
FixedArray::kHeaderSize),
value);
}
Operand operand = BuildFastArrayOperand(
instr->object(),
instr->key(),
FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
__ mov(operand, value);
if (instr->hydrogen()->NeedsWriteBarrier()) {
ASSERT(!instr->key()->IsConstantOperand());
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
__ lea(key,
FieldOperand(elements,
key,
times_pointer_size,
FixedArray::kHeaderSize));
__ lea(key, operand);
__ RecordWrite(elements,
key,
value,
......@@ -3508,8 +3515,11 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
}
Operand double_store_operand = BuildFastArrayOperand(
instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
instr->elements(),
instr->key(),
FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
__ movdbl(double_store_operand, value);
}
......
......@@ -242,7 +242,8 @@ class LCodeGen BASE_EMBEDDED {
Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key,
ElementsKind elements_kind,
uint32_t offset);
uint32_t offset,
uint32_t additional_index = 0);
// Specific math operations - used from DoUnaryMathOperation.
void EmitIntegerMathAbs(LUnaryMathOperation* instr);
......
......@@ -1990,8 +1990,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
LLoadKeyedSpecializedArrayElement* result =
new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer,
key);
new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key);
LInstruction* load_instr = DefineAsRegister(result);
// An unsigned int array load might overflow and cause a deopt, make sure it
// has an environment.
......
......@@ -1238,13 +1238,13 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedFastDoubleElement(LOperand* elements,
LOperand* key) {
LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) {
inputs_[0] = elements;
inputs_[1] = key;
}
......@@ -1255,13 +1255,13 @@ class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
LOperand* key) {
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
......@@ -1275,6 +1275,7 @@ class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......@@ -1775,6 +1776,7 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
LOperand* object() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......@@ -1797,6 +1799,7 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
};
......@@ -1822,6 +1825,7 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......
......@@ -236,8 +236,6 @@ namespace internal {
SC(math_sin, V8.MathSin) \
SC(math_sqrt, V8.MathSqrt) \
SC(math_tan, V8.MathTan) \
SC(array_bounds_checks_seen, V8.ArrayBoundsChecksSeen) \
SC(array_bounds_checks_removed, V8.ArrayBoundsChecksRemoved) \
SC(transcendental_cache_hit, V8.TranscendentalCacheHit) \
SC(transcendental_cache_miss, V8.TranscendentalCacheMiss) \
SC(stack_interrupts, V8.StackInterrupts) \
......
......@@ -2369,11 +2369,20 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
Register result = ToRegister(instr->result());
if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
// Sign extend key because it could be a 32 bit negative value
// and the dehoisted address computation happens in 64 bits.
Register key_reg = ToRegister(instr->key());
__ movsxlq(key_reg, key_reg);
}
// Load the result.
__ movq(result,
BuildFastArrayOperand(instr->elements(), instr->key(),
BuildFastArrayOperand(instr->elements(),
instr->key(),
FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag));
FixedArray::kHeaderSize - kHeapObjectTag,
instr->additional_index()));
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
......@@ -2387,19 +2396,30 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
LLoadKeyedFastDoubleElement* instr) {
XMMRegister result(ToDoubleRegister(instr->result()));
if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
// Sign extend key because it could be a 32 bit negative value
// and the dehoisted address computation happens in 64 bits
Register key_reg = ToRegister(instr->key());
__ movsxlq(key_reg, key_reg);
}
int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
sizeof(kHoleNanLower32);
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(),
instr->key(),
FAST_DOUBLE_ELEMENTS,
offset);
offset,
instr->additional_index());
__ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
DeoptimizeIf(equal, instr->environment());
Operand double_load_operand = BuildFastArrayOperand(
instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
instr->elements(),
instr->key(),
FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
__ movsd(result, double_load_operand);
}
......@@ -2408,7 +2428,8 @@ Operand LCodeGen::BuildFastArrayOperand(
LOperand* elements_pointer,
LOperand* key,
ElementsKind elements_kind,
uint32_t offset) {
uint32_t offset,
uint32_t additional_index) {
Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) {
......@@ -2417,11 +2438,14 @@ Operand LCodeGen::BuildFastArrayOperand(
Abort("array index constant value too big");
}
return Operand(elements_pointer_reg,
constant_value * (1 << shift_size) + offset);
((constant_value + additional_index) << shift_size)
+ offset);
} else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
return Operand(elements_pointer_reg, ToRegister(key),
scale_factor, offset);
return Operand(elements_pointer_reg,
ToRegister(key),
scale_factor,
offset + (additional_index << shift_size));
}
}
......@@ -2430,7 +2454,17 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
instr->key(),
elements_kind,
0,
instr->additional_index()));
if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
// Sign extend key because it could be a 32 bit negative value
// and the dehoisted address computation happens in 64 bits
Register key_reg = ToRegister(instr->key());
__ movsxlq(key_reg, key_reg);
}
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
......@@ -3332,7 +3366,18 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
instr->key(),
elements_kind,
0,
instr->additional_index()));
if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
// Sign extend key because it could be a 32 bit negative value
// and the dehoisted address computation happens in 64 bits
Register key_reg = ToRegister(instr->key());
__ movsxlq(key_reg, key_reg);
}
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister value(ToDoubleRegister(instr->value()));
__ cvtsd2ss(value, value);
......@@ -3402,30 +3447,29 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
Register elements = ToRegister(instr->object());
Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
// Do the store.
if (instr->key()->IsConstantOperand()) {
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
int offset =
ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
__ movq(FieldOperand(elements, offset), value);
} else {
__ movq(FieldOperand(elements,
key,
times_pointer_size,
FixedArray::kHeaderSize),
value);
Operand operand =
BuildFastArrayOperand(instr->object(),
instr->key(),
FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
// Sign extend key because it could be a 32 bit negative value
// and the dehoisted address computation happens in 64 bits
Register key_reg = ToRegister(instr->key());
__ movsxlq(key_reg, key_reg);
}
__ movq(operand, value);
if (instr->hydrogen()->NeedsWriteBarrier()) {
ASSERT(!instr->key()->IsConstantOperand());
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
__ lea(key, FieldOperand(elements,
key,
times_pointer_size,
FixedArray::kHeaderSize));
__ lea(key, operand);
__ RecordWrite(elements,
key,
value,
......@@ -3454,8 +3498,19 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
}
Operand double_store_operand = BuildFastArrayOperand(
instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
instr->elements(),
instr->key(),
FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
// Sign extend key because it could be a 32 bit negative value
// and the dehoisted address computation happens in 64 bits
Register key_reg = ToRegister(instr->key());
__ movsxlq(key_reg, key_reg);
}
__ movsd(double_store_operand, value);
}
......
......@@ -231,7 +231,8 @@ class LCodeGen BASE_EMBEDDED {
LOperand* elements_pointer,
LOperand* key,
ElementsKind elements_kind,
uint32_t offset);
uint32_t offset,
uint32_t additional_index = 0);
// Specific math operations - used from DoUnaryMathOperation.
void EmitIntegerMathAbs(LUnaryMathOperation* instr);
......
......@@ -1199,6 +1199,7 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......@@ -1215,13 +1216,13 @@ class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
LOperand* key) {
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
......@@ -1235,6 +1236,7 @@ class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......@@ -1692,6 +1694,7 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
LOperand* object() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......@@ -1716,6 +1719,7 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
LOperand* value() { return inputs_[2]; }
bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......@@ -1739,6 +1743,7 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
......
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