Implement crankshaft support for pixel array stores.
authordanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 16 Feb 2011 13:31:12 +0000 (13:31 +0000)
committerdanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 16 Feb 2011 13:31:12 +0000 (13:31 +0000)
Review URL: http://codereview.chromium.org/6528013

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6817 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

12 files changed:
src/arm/lithium-arm.cc
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/hydrogen.h
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h
test/cctest/test-api.cc

index 903f77b..786ceeb 100644 (file)
@@ -1806,6 +1806,13 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
 }
 
 
+LInstruction* LChunkBuilder::DoStorePixelArrayElement(
+    HStorePixelArrayElement* instr) {
+  Abort("DoStorePixelArrayElement not implemented");
+  return NULL;
+}
+
+
 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
   LOperand* obj = UseFixed(instr->object(), r2);
   LOperand* key = UseFixed(instr->key(), r1);
index 5accc77..c59372a 100644 (file)
@@ -57,10 +57,13 @@ const char* Representation::Mnemonic() const {
     case kTagged: return "t";
     case kDouble: return "d";
     case kInteger32: return "i";
-    default:
+    case kExternal: return "x";
+    case kNumRepresentations:
       UNREACHABLE();
       return NULL;
   }
+  UNREACHABLE();
+  return NULL;
 }
 
 
@@ -1202,6 +1205,15 @@ void HStoreKeyed::PrintDataTo(StringStream* stream) const {
 }
 
 
+void HStorePixelArrayElement::PrintDataTo(StringStream* stream) const {
+  external_pointer()->PrintNameTo(stream);
+  stream->Add("[");
+  key()->PrintNameTo(stream);
+  stream->Add("] = ");
+  value()->PrintNameTo(stream);
+}
+
+
 void HLoadGlobal::PrintDataTo(StringStream* stream) const {
   stream->Add("[%p]", *cell());
   if (check_hole_value()) stream->Add(" (deleteable/read-only)");
index 9f5170c..b121335 100644 (file)
@@ -151,6 +151,7 @@ class LChunkBuilder;
   V(StoreContextSlot)                          \
   V(StoreGlobal)                               \
   V(StoreKeyedFastElement)                     \
+  V(StorePixelArrayElement)                    \
   V(StoreKeyedGeneric)                         \
   V(StoreNamedField)                           \
   V(StoreNamedGeneric)                         \
@@ -3182,6 +3183,43 @@ class HStoreKeyedFastElement: public HStoreKeyed {
 };
 
 
+class HStorePixelArrayElement: public HInstruction {
+ public:
+  HStorePixelArrayElement(HValue* external_elements, HValue* key, HValue* val) {
+    SetFlag(kChangesPixelArrayElements);
+    SetOperandAt(0, external_elements);
+    SetOperandAt(1, key);
+    SetOperandAt(2, val);
+  }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+  virtual int OperandCount() const { return operands_.length(); }
+  virtual HValue* OperandAt(int index) const { return operands_[index]; }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    if (index == 0) {
+      return Representation::External();
+    } else {
+      return Representation::Integer32();
+    }
+  }
+
+  HValue* external_pointer() const { return operands_[0]; }
+  HValue* key() const { return operands_[1]; }
+  HValue* value() const { return operands_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
+                               "store_pixel_array_element")
+
+ protected:
+  virtual void InternalSetOperandAt(int index, HValue* value) {
+    operands_[index] = value;
+  }
+
+  HOperandVector<3> operands_;
+};
+
+
 class HStoreKeyedGeneric: public HStoreKeyed {
  public:
   HStoreKeyedGeneric(HValue* context,
index 3ebd580..0e27c07 100644 (file)
@@ -3326,12 +3326,20 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
     HValue* key = Pop();
     HValue* object = Pop();
 
-    bool is_fast_elements = expr->IsMonomorphic() &&
-        expr->GetMonomorphicReceiverType()->has_fast_elements();
-
-    instr = is_fast_elements
-        ? BuildStoreKeyedFastElement(object, key, value, expr)
-        : BuildStoreKeyedGeneric(object, key, value);
+    if (expr->IsMonomorphic()) {
+      Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
+      // An object has either fast elements or pixel array elements, but never
+      // both. Pixel array maps that are assigned to pixel array elements are
+      // always created with the fast elements flag cleared.
+      if (receiver_type->has_pixel_array_elements()) {
+        instr = BuildStoreKeyedPixelArrayElement(object, key, value, expr);
+      } else if (receiver_type->has_fast_elements()) {
+        instr = BuildStoreKeyedFastElement(object, key, value, expr);
+      }
+    }
+    if (instr == NULL) {
+      instr = BuildStoreKeyedGeneric(object, key, value);
+    }
   }
 
   Push(value);
@@ -3711,7 +3719,8 @@ HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object,
   AddInstruction(new HCheckMap(object, map));
   HLoadElements* elements = new HLoadElements(object);
   AddInstruction(elements);
-  HInstruction* length = AddInstruction(new HPixelArrayLength(elements));
+  HInstruction* length = new HPixelArrayLength(elements);
+  AddInstruction(length);
   AddInstruction(new HBoundsCheck(key, length));
   HLoadPixelArrayExternalPointer* external_elements =
       new HLoadPixelArrayExternalPointer(elements);
@@ -3754,6 +3763,27 @@ HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
 }
 
 
+HInstruction* HGraphBuilder::BuildStoreKeyedPixelArrayElement(HValue* object,
+                                                              HValue* key,
+                                                              HValue* val,
+                                                              Expression* expr) {
+  ASSERT(expr->IsMonomorphic());
+  AddInstruction(new HCheckNonSmi(object));
+  Handle<Map> map = expr->GetMonomorphicReceiverType();
+  ASSERT(!map->has_fast_elements());
+  ASSERT(map->has_pixel_array_elements());
+  AddInstruction(new HCheckMap(object, map));
+  HLoadElements* elements = new HLoadElements(object);
+  AddInstruction(elements);
+  HInstruction* length = AddInstruction(new HPixelArrayLength(elements));
+  AddInstruction(new HBoundsCheck(key, length));
+  HLoadPixelArrayExternalPointer* external_elements =
+      new HLoadPixelArrayExternalPointer(elements);
+  AddInstruction(external_elements);
+  return new HStorePixelArrayElement(external_elements, key, val);
+}
+
+
 bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
   VariableProxy* proxy = expr->obj()->AsVariableProxy();
   if (proxy == NULL) return false;
index c911b6c..6d287ef 100644 (file)
@@ -816,6 +816,11 @@ class HGraphBuilder: public AstVisitor {
                                            HValue* val,
                                            Expression* expr);
 
+  HInstruction* BuildStoreKeyedPixelArrayElement(HValue* object,
+                                                 HValue* key,
+                                                 HValue* val,
+                                                 Expression* expr);
+
   HCompare* BuildSwitchCompare(HSubgraph* subgraph,
                                HValue* switch_value,
                                CaseClause* clause);
index a59b1a5..ca72c97 100644 (file)
@@ -2100,13 +2100,13 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
 
 
 void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
-  Register external_elements = ToRegister(instr->external_pointer());
+  Register external_pointer = ToRegister(instr->external_pointer());
   Register key = ToRegister(instr->key());
   Register result = ToRegister(instr->result());
-  ASSERT(result.is(external_elements));
+  ASSERT(result.is(external_pointer));
 
   // Load the result.
-  __ movzx_b(result, Operand(external_elements, key, times_1, 0));
+  __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
 }
 
 
@@ -2731,6 +2731,25 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
 }
 
 
+void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
+  Register external_pointer = ToRegister(instr->external_pointer());
+  Register key = ToRegister(instr->key());
+  Register value = ToRegister(instr->value());
+  ASSERT(ToRegister(instr->TempAt(0)).is(eax));
+
+  __ mov(eax, value);
+  {  // Clamp the value to [0..255].
+    NearLabel done;
+    __ test(eax, Immediate(0xFFFFFF00));
+    __ j(zero, &done);
+    __ setcc(negative, eax);  // 1 if negative, 0 if positive.
+    __ dec_b(eax);  // 0 if negative, 255 if positive.
+    __ bind(&done);
+  }
+  __ mov_b(Operand(external_pointer, key, times_1, 0), eax);
+}
+
+
 void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
   Register value = ToRegister(instr->value());
   Register elements = ToRegister(instr->object());
index a57e8c9..84fd08b 100644 (file)
@@ -1840,6 +1840,23 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
 }
 
 
+LInstruction* LChunkBuilder::DoStorePixelArrayElement(
+    HStorePixelArrayElement* instr) {
+  ASSERT(instr->value()->representation().IsInteger32());
+  ASSERT(instr->external_pointer()->representation().IsExternal());
+  ASSERT(instr->key()->representation().IsInteger32());
+
+  LOperand* external_pointer = UseRegister(instr->external_pointer());
+  LOperand* val = UseRegister(instr->value());
+  LOperand* key = UseRegister(instr->key());
+  // The generated code requires that the clamped value is in a byte
+  // register. eax is an arbitrary choice to satisfy this requirement.
+  LOperand* clamped = FixedTemp(eax);
+
+  return new LStorePixelArrayElement(external_pointer, key, val, clamped);
+}
+
+
 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
   LOperand* context = UseFixed(instr->context(), esi);
   LOperand* object = UseFixed(instr->object(), edx);
index f1b9ffc..2acd0c1 100644 (file)
@@ -150,6 +150,7 @@ class LCodeGen;
   V(StoreKeyedGeneric)                          \
   V(StoreNamedField)                            \
   V(StoreNamedGeneric)                          \
+  V(StorePixelArrayElement)                     \
   V(StringCharCodeAt)                           \
   V(StringLength)                               \
   V(SubI)                                       \
@@ -1662,6 +1663,28 @@ class LStoreKeyedFastElement: public LStoreKeyed {
 };
 
 
+class LStorePixelArrayElement: public LTemplateInstruction<0, 3, 1> {
+ public:
+  LStorePixelArrayElement(LOperand* external_pointer,
+                          LOperand* key,
+                          LOperand* val,
+                          LOperand* clamped) {
+    inputs_[0] = external_pointer;
+    inputs_[1] = key;
+    inputs_[2] = val;
+    temps_[0] = clamped;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
+                               "store-pixel-array-element")
+  DECLARE_HYDROGEN_ACCESSOR(StorePixelArrayElement)
+
+  LOperand* external_pointer() { return inputs_[0]; }
+  LOperand* key() { return inputs_[1]; }
+  LOperand* value() { return inputs_[2]; }
+};
+
+
 class LStoreKeyedGeneric: public LTemplateInstruction<0, 4, 0> {
  public:
   LStoreKeyedGeneric(LOperand* context,
index e1ebb3e..48d149e 100644 (file)
@@ -2148,6 +2148,24 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
 }
 
 
+void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
+  Register external_pointer = ToRegister(instr->external_pointer());
+  Register key = ToRegister(instr->key());
+  Register value = ToRegister(instr->value());
+
+  {  // Clamp the value to [0..255].
+    NearLabel done;
+    __ testl(value, Immediate(0xFFFFFF00));
+    __ j(zero, &done);
+    __ setcc(negative, value);  // 1 if negative, 0 if positive.
+    __ decb(value);  // 0 if negative, 255 if positive.
+    __ bind(&done);
+  }
+
+  __ movb(Operand(external_pointer, key, times_1, 0), value);
+}
+
+
 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
   if (instr->length()->IsRegister()) {
     __ cmpq(ToRegister(instr->index()), ToRegister(instr->length()));
index fba29a6..5b14639 100644 (file)
@@ -1716,6 +1716,20 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
 }
 
 
+LInstruction* LChunkBuilder::DoStorePixelArrayElement(
+    HStorePixelArrayElement* instr) {
+  ASSERT(instr->value()->representation().IsInteger32());
+  ASSERT(instr->external_pointer()->representation().IsExternal());
+  ASSERT(instr->key()->representation().IsInteger32());
+
+  LOperand* external_pointer = UseRegister(instr->external_pointer());
+  LOperand* val = UseTempRegister(instr->value());
+  LOperand* key = UseRegister(instr->key());
+
+  return new LStorePixelArrayElement(external_pointer, key, val);
+}
+
+
 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
   Abort("Unimplemented: %s", "DoStoreKeyedGeneric");
   return NULL;
index abffe50..80963d0 100644 (file)
@@ -146,6 +146,7 @@ class LCodeGen;
   V(StoreKeyedGeneric)                          \
   V(StoreNamedField)                            \
   V(StoreNamedGeneric)                          \
+  V(StorePixelArrayElement)                     \
   V(StringLength)                               \
   V(SubI)                                       \
   V(TaggedToI)                                  \
@@ -1542,6 +1543,26 @@ class LStoreKeyedFastElement: public LStoreKeyed {
 };
 
 
+class LStorePixelArrayElement: public LTemplateInstruction<0, 3, 0> {
+ public:
+  LStorePixelArrayElement(LOperand* external_pointer,
+                          LOperand* key,
+                          LOperand* val) {
+    inputs_[0] = external_pointer;
+    inputs_[1] = key;
+    inputs_[2] = val;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
+                               "store-pixel-array-element")
+  DECLARE_HYDROGEN_ACCESSOR(StorePixelArrayElement)
+
+  LOperand* external_pointer() { return inputs_[0]; }
+  LOperand* key() { return inputs_[1]; }
+  LOperand* value() { return inputs_[2]; }
+};
+
+
 class LStoreKeyedGeneric: public LStoreKeyed {
  public:
   LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val)
index 3de5b92..c43078d 100644 (file)
@@ -10825,6 +10825,24 @@ THREADED_TEST(PixelArray) {
                       "result");
   CHECK_EQ(32640, result->Int32Value());
 
+  // Make sure that pixel array stores are optimized by crankshaft.
+  result = CompileRun("function pa_init(p) {"
+                      "for (var i = 0; i < 256; ++i) { p[i] = i; }"
+                      "}"
+                      "function pa_load(p) {"
+                      "  var sum = 0;"
+                      "  for (var i=0; i<256; ++i) {"
+                      "    sum += p[i];"
+                      "  }"
+                      "  return sum; "
+                      "}"
+                      "for (var i = 0; i < 100000; ++i) {"
+                      "  pa_init(pixels);"
+                      "}"
+                      "result = pa_load(pixels);"
+                      "result");
+  CHECK_EQ(32640, result->Int32Value());
+
   free(pixel_data);
 }