Commit 12b4e0ef authored by danno@chromium.org's avatar danno@chromium.org

Implement crankshaft support for pixel array stores.

Review URL: http://codereview.chromium.org/6528013

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6817 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4235110a
......@@ -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);
......
......@@ -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)");
......
......@@ -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,
......
......@@ -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;
......
......@@ -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);
......
......@@ -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());
......
......@@ -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);
......
......@@ -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,
......
......@@ -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()));
......
......@@ -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;
......
......@@ -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)
......
......@@ -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);
}
......
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