Revision: 11596
Author:   [email protected]
Date:     Mon May 21 00:59:50 2012
Log:      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
http://code.google.com/p/v8/source/detail?r=11596

Modified:
 /branches/bleeding_edge/src/arm/lithium-arm.h
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/flag-definitions.h
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/hydrogen.h
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h
 /branches/bleeding_edge/src/ia32/lithium-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-ia32.h
 /branches/bleeding_edge/src/v8-counters.h
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.h
 /branches/bleeding_edge/src/x64/lithium-x64.h

=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h       Thu Apr 26 05:43:00 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.h       Mon May 21 00:59:50 2012
@@ -1236,6 +1236,7 @@

   LOperand* elements() { return inputs_[0]; }
   LOperand* key() { return inputs_[1]; }
+  uint32_t additional_index() const { return hydrogen()->index_offset(); }
 };


@@ -1252,13 +1253,13 @@

   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 @@
   ElementsKind elements_kind() const {
     return hydrogen()->elements_kind();
   }
+  uint32_t additional_index() const { return hydrogen()->index_offset(); }
 };


@@ -1740,6 +1742,7 @@
   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 @@
   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 @@
   ElementsKind elements_kind() const {
     return hydrogen()->elements_kind();
   }
+  uint32_t additional_index() const { return hydrogen()->index_offset(); }
 };


=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri May 11 02:13:02 2012 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon May 21 00:59:50 2012
@@ -2744,7 +2744,9 @@

   // 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 @@
   }

   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 @@
     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 @@
     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 @@
   }
   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 @@
             vs);
   }

-  __ vstr(value, scratch, 0);
+  __ vstr(value, scratch, instr->additional_index() << shift_size);
 }


@@ -3810,25 +3826,33 @@
     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:
=======================================
--- /branches/bleeding_edge/src/flag-definitions.h      Tue May 15 02:01:06 2012
+++ /branches/bleeding_edge/src/flag-definitions.h      Mon May 21 00:59:50 2012
@@ -197,6 +197,8 @@
 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")
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Tue Apr 24 08:59:07 2012 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Mon May 21 00:59:50 2012
@@ -3946,15 +3946,27 @@
   virtual bool DataEquals(HValue* other) { return true; }
 };

-
-class HLoadKeyedFastElement: public HTemplateInstruction<2> {
+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>, 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 @@

   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 @@
   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 @@

   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 @@

  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 @@
   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 @@

  private:
   ElementsKind elements_kind_;
+  uint32_t index_offset_;
+  bool is_dehoisted_;
 };


@@ -4188,11 +4233,12 @@
 };


-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 @@
   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 @@

  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 @@
   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 @@
   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 @@
   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_;
 };


=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Thu May 17 13:53:32 2012
+++ /branches/bleeding_edge/src/hydrogen.cc     Mon May 21 00:59:50 2012
@@ -2758,6 +2758,7 @@
   sce.Process();

   graph()->EliminateRedundantBoundsChecks();
+  graph()->DehoistSimpleArrayIndexComputations();

   return graph();
 }
@@ -3016,7 +3017,6 @@
     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 @@
       *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
@@ -3080,6 +3078,93 @@
   BoundsCheckTable checks_table;
   EliminateRedundantBoundsChecks(entry_block(), &checks_table);
 }
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Wed May  2 06:07:31 2012
+++ /branches/bleeding_edge/src/hydrogen.h      Mon May 21 00:59:50 2012
@@ -267,6 +267,7 @@
   void AssignDominators();
   void ReplaceCheckedValues();
   void EliminateRedundantBoundsChecks();
+  void DehoistSimpleArrayIndexComputations();
   void PropagateDeoptimizingMark();

   // Returns false if there are phi-uses of the arguments-object
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri May 11 02:13:02 2012 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon May 21 00:59:50 2012
@@ -2421,9 +2421,11 @@

   // 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 @@
   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 @@
     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 @@
       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 @@
     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 @@
     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 @@
   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 @@
   }

   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);
 }

=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Wed Apr 18 02:38:45 2012 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Mon May 21 00:59:50 2012
@@ -242,7 +242,8 @@
   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);
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Fri Apr 27 06:05:45 2012 +++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Mon May 21 00:59:50 2012
@@ -1990,8 +1990,7 @@
   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.
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h     Thu Apr 26 05:43:00 2012
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h     Mon May 21 00:59:50 2012
@@ -1238,13 +1238,13 @@

   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 @@

   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 @@
   ElementsKind elements_kind() const {
     return hydrogen()->elements_kind();
   }
+  uint32_t additional_index() const { return hydrogen()->index_offset(); }
 };


@@ -1775,6 +1776,7 @@
   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 @@
   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 @@
   ElementsKind elements_kind() const {
     return hydrogen()->elements_kind();
   }
+  uint32_t additional_index() const { return hydrogen()->index_offset(); }
 };


=======================================
--- /branches/bleeding_edge/src/v8-counters.h   Wed Apr 25 07:32:27 2012
+++ /branches/bleeding_edge/src/v8-counters.h   Mon May 21 00:59:50 2012
@@ -236,8 +236,6 @@
   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)                            \
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Fri May 11 02:13:02 2012 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon May 21 00:59:50 2012
@@ -2369,11 +2369,20 @@
 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 @@
     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 @@
     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 @@
       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 @@
     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 @@
     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 @@
   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 @@
   }

   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);
 }

=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Wed Apr 18 02:38:45 2012 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Mon May 21 00:59:50 2012
@@ -231,7 +231,8 @@
       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);
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h       Thu Apr 26 05:43:00 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.h       Mon May 21 00:59:50 2012
@@ -1199,6 +1199,7 @@

   LOperand* elements() { return inputs_[0]; }
   LOperand* key() { return inputs_[1]; }
+  uint32_t additional_index() const { return hydrogen()->index_offset(); }
 };


@@ -1215,13 +1216,13 @@

   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 @@
   ElementsKind elements_kind() const {
     return hydrogen()->elements_kind();
   }
+  uint32_t additional_index() const { return hydrogen()->index_offset(); }
 };


@@ -1692,6 +1694,7 @@
   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 @@
   LOperand* value() { return inputs_[2]; }

bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
+  uint32_t additional_index() const { return hydrogen()->index_offset(); }
 };


@@ -1739,6 +1743,7 @@
   ElementsKind elements_kind() const {
     return hydrogen()->elements_kind();
   }
+  uint32_t additional_index() const { return hydrogen()->index_offset(); }
 };


--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to