Commit 9492c1b5 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

Add support to load/store byte fields.

This adds a new Byte representation and support for zero-extended
loads in HLoadNamedField and truncated stores in HStoreNamedField.

R=mvstanton@chromium.org

Review URL: https://codereview.chromium.org/25696004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17079 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 7e0ea6ab
...@@ -3042,7 +3042,12 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { ...@@ -3042,7 +3042,12 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
if (access.IsExternalMemory()) { if (access.IsExternalMemory()) {
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
__ ldr(result, MemOperand(object, offset)); MemOperand operand = MemOperand(object, offset);
if (access.representation().IsByte()) {
__ ldrb(result, operand);
} else {
__ ldr(result, operand);
}
return; return;
} }
...@@ -3053,11 +3058,15 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { ...@@ -3053,11 +3058,15 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
} }
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
if (access.IsInobject()) { if (!access.IsInobject()) {
__ ldr(result, FieldMemOperand(object, offset));
} else {
__ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
__ ldr(result, FieldMemOperand(result, offset)); object = result;
}
MemOperand operand = FieldMemOperand(object, offset);
if (access.representation().IsByte()) {
__ ldrb(result, operand);
} else {
__ ldr(result, operand);
} }
} }
...@@ -4163,7 +4172,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { ...@@ -4163,7 +4172,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
if (access.IsExternalMemory()) { if (access.IsExternalMemory()) {
Register value = ToRegister(instr->value()); Register value = ToRegister(instr->value());
__ str(value, MemOperand(object, offset)); MemOperand operand = MemOperand(object, offset);
if (representation.IsByte()) {
__ strb(value, operand);
} else {
__ str(value, operand);
}
return; return;
} }
...@@ -4208,7 +4222,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { ...@@ -4208,7 +4222,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
instr->hydrogen()->value()->IsHeapObject() instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK; ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
if (access.IsInobject()) { if (access.IsInobject()) {
__ str(value, FieldMemOperand(object, offset)); MemOperand operand = FieldMemOperand(object, offset);
if (representation.IsByte()) {
__ strb(value, operand);
} else {
__ str(value, operand);
}
if (instr->hydrogen()->NeedsWriteBarrier()) { if (instr->hydrogen()->NeedsWriteBarrier()) {
// Update the write barrier for the object for in-object properties. // Update the write barrier for the object for in-object properties.
__ RecordWriteField(object, __ RecordWriteField(object,
...@@ -4222,7 +4241,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { ...@@ -4222,7 +4241,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
} }
} else { } else {
__ ldr(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset)); __ ldr(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset));
__ str(value, FieldMemOperand(scratch, offset)); MemOperand operand = FieldMemOperand(scratch, offset);
if (representation.IsByte()) {
__ strb(value, operand);
} else {
__ str(value, operand);
}
if (instr->hydrogen()->NeedsWriteBarrier()) { if (instr->hydrogen()->NeedsWriteBarrier()) {
// Update the write barrier for the properties array. // Update the write barrier for the properties array.
// object is used as a scratch register. // object is used as a scratch register.
......
...@@ -2829,6 +2829,9 @@ Range* HShl::InferRange(Zone* zone) { ...@@ -2829,6 +2829,9 @@ Range* HShl::InferRange(Zone* zone) {
Range* HLoadNamedField::InferRange(Zone* zone) { Range* HLoadNamedField::InferRange(Zone* zone) {
if (access().representation().IsByte()) {
return new(zone) Range(0, 255);
}
if (access().IsStringLength()) { if (access().IsStringLength()) {
return new(zone) Range(0, String::kMaxLength); return new(zone) Range(0, String::kMaxLength);
} }
......
...@@ -5934,7 +5934,9 @@ class HLoadNamedField V8_FINAL : public HTemplateInstruction<1> { ...@@ -5934,7 +5934,9 @@ class HLoadNamedField V8_FINAL : public HTemplateInstruction<1> {
SetOperandAt(0, object); SetOperandAt(0, object);
Representation representation = access.representation(); Representation representation = access.representation();
if (representation.IsSmi()) { if (representation.IsByte()) {
set_representation(Representation::Integer32());
} else if (representation.IsSmi()) {
set_type(HType::Smi()); set_type(HType::Smi());
set_representation(representation); set_representation(representation);
} else if (representation.IsDouble() || } else if (representation.IsDouble() ||
...@@ -6232,12 +6234,15 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> { ...@@ -6232,12 +6234,15 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
if (index == 0 && access().IsExternalMemory()) { if (index == 0 && access().IsExternalMemory()) {
// object must be external in case of external memory access // object must be external in case of external memory access
return Representation::External(); return Representation::External();
} else if (index == 1 && } else if (index == 1) {
(field_representation().IsDouble() || if (field_representation().IsByte() ||
field_representation().IsSmi() || field_representation().IsInteger32()) {
field_representation().IsInteger32())) { return Representation::Integer32();
} else if (field_representation().IsDouble() ||
field_representation().IsSmi()) {
return field_representation(); return field_representation();
} }
}
return Representation::Tagged(); return Representation::Tagged();
} }
virtual void HandleSideEffectDominator(GVNFlag side_effect, virtual void HandleSideEffectDominator(GVNFlag side_effect,
......
...@@ -3225,12 +3225,15 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { ...@@ -3225,12 +3225,15 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
if (access.IsExternalMemory()) { if (access.IsExternalMemory()) {
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
if (instr->object()->IsConstantOperand()) { MemOperand operand = instr->object()->IsConstantOperand()
ExternalReference external_reference = ToExternalReference( ? MemOperand::StaticVariable(ToExternalReference(
LConstantOperand::cast(instr->object())); LConstantOperand::cast(instr->object())))
__ mov(result, MemOperand::StaticVariable(external_reference)); : MemOperand(ToRegister(instr->object()), offset);
if (access.representation().IsByte()) {
ASSERT(instr->hydrogen()->representation().IsInteger32());
__ movzx_b(result, operand);
} else { } else {
__ mov(result, MemOperand(ToRegister(instr->object()), offset)); __ mov(result, operand);
} }
return; return;
} }
...@@ -3249,11 +3252,15 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { ...@@ -3249,11 +3252,15 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
} }
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
if (access.IsInobject()) { if (!access.IsInobject()) {
__ mov(result, FieldOperand(object, offset));
} else {
__ mov(result, FieldOperand(object, JSObject::kPropertiesOffset)); __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
__ mov(result, FieldOperand(result, offset)); object = result;
}
if (access.representation().IsByte()) {
ASSERT(instr->hydrogen()->representation().IsInteger32());
__ movzx_b(result, FieldOperand(object, offset));
} else {
__ mov(result, FieldOperand(object, offset));
} }
} }
...@@ -4429,11 +4436,19 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { ...@@ -4429,11 +4436,19 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
: MemOperand(ToRegister(instr->object()), offset); : MemOperand(ToRegister(instr->object()), offset);
if (instr->value()->IsConstantOperand()) { if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
if (representation.IsByte()) {
__ mov_b(operand, ToInteger32(operand_value));
} else {
__ mov(operand, Immediate(ToInteger32(operand_value))); __ mov(operand, Immediate(ToInteger32(operand_value)));
}
} else { } else {
Register value = ToRegister(instr->value()); Register value = ToRegister(instr->value());
if (representation.IsByte()) {
__ mov_b(operand, value);
} else {
__ mov(operand, value); __ mov(operand, value);
} }
}
return; return;
} }
...@@ -4505,17 +4520,28 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { ...@@ -4505,17 +4520,28 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
__ mov(write_register, FieldOperand(object, JSObject::kPropertiesOffset)); __ mov(write_register, FieldOperand(object, JSObject::kPropertiesOffset));
} }
MemOperand operand = FieldOperand(write_register, offset);
if (instr->value()->IsConstantOperand()) { if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
if (operand_value->IsRegister()) { if (operand_value->IsRegister()) {
__ mov(FieldOperand(write_register, offset), ToRegister(operand_value)); Register value = ToRegister(operand_value);
if (representation.IsByte()) {
__ mov_b(operand, value);
} else {
__ mov(operand, value);
}
} else { } else {
Handle<Object> handle_value = ToHandle(operand_value); Handle<Object> handle_value = ToHandle(operand_value);
ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
__ mov(FieldOperand(write_register, offset), handle_value); __ mov(operand, handle_value);
} }
} else { } else {
__ mov(FieldOperand(write_register, offset), ToRegister(instr->value())); Register value = ToRegister(instr->value());
if (representation.IsByte()) {
__ mov_b(operand, value);
} else {
__ mov(operand, value);
}
} }
if (instr->hydrogen()->NeedsWriteBarrier()) { if (instr->hydrogen()->NeedsWriteBarrier()) {
......
...@@ -82,6 +82,7 @@ class Representation { ...@@ -82,6 +82,7 @@ class Representation {
public: public:
enum Kind { enum Kind {
kNone, kNone,
kByte,
kSmi, kSmi,
kInteger32, kInteger32,
kDouble, kDouble,
...@@ -95,6 +96,7 @@ class Representation { ...@@ -95,6 +96,7 @@ class Representation {
static Representation None() { return Representation(kNone); } static Representation None() { return Representation(kNone); }
static Representation Tagged() { return Representation(kTagged); } static Representation Tagged() { return Representation(kTagged); }
static Representation Byte() { return Representation(kByte); }
static Representation Smi() { return Representation(kSmi); } static Representation Smi() { return Representation(kSmi); }
static Representation Integer32() { return Representation(kInteger32); } static Representation Integer32() { return Representation(kInteger32); }
static Representation Double() { return Representation(kDouble); } static Representation Double() { return Representation(kDouble); }
...@@ -139,6 +141,7 @@ class Representation { ...@@ -139,6 +141,7 @@ class Representation {
Kind kind() const { return static_cast<Kind>(kind_); } Kind kind() const { return static_cast<Kind>(kind_); }
bool IsNone() const { return kind_ == kNone; } bool IsNone() const { return kind_ == kNone; }
bool IsByte() const { return kind_ == kByte; }
bool IsTagged() const { return kind_ == kTagged; } bool IsTagged() const { return kind_ == kTagged; }
bool IsSmi() const { return kind_ == kSmi; } bool IsSmi() const { return kind_ == kSmi; }
bool IsSmiOrTagged() const { return IsSmi() || IsTagged(); } bool IsSmiOrTagged() const { return IsSmi() || IsTagged(); }
...@@ -148,7 +151,7 @@ class Representation { ...@@ -148,7 +151,7 @@ class Representation {
bool IsHeapObject() const { return kind_ == kHeapObject; } bool IsHeapObject() const { return kind_ == kHeapObject; }
bool IsExternal() const { return kind_ == kExternal; } bool IsExternal() const { return kind_ == kExternal; }
bool IsSpecialization() const { bool IsSpecialization() const {
return kind_ == kInteger32 || kind_ == kDouble || kind_ == kSmi; return IsByte() || IsSmi() || IsInteger32() || IsDouble();
} }
const char* Mnemonic() const; const char* Mnemonic() const;
......
...@@ -2726,14 +2726,13 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { ...@@ -2726,14 +2726,13 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
int offset = access.offset(); int offset = access.offset();
if (access.IsExternalMemory()) { if (access.IsExternalMemory()) {
ASSERT(!access.representation().IsInteger32());
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
if (instr->object()->IsConstantOperand()) { if (instr->object()->IsConstantOperand()) {
ASSERT(result.is(rax)); ASSERT(result.is(rax));
__ load_rax(ToExternalReference(LConstantOperand::cast(instr->object()))); __ load_rax(ToExternalReference(LConstantOperand::cast(instr->object())));
} else { } else {
Register object = ToRegister(instr->object()); Register object = ToRegister(instr->object());
__ movq(result, MemOperand(object, offset)); __ Load(result, MemOperand(object, offset), access.representation());
} }
return; return;
} }
...@@ -2747,20 +2746,11 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { ...@@ -2747,20 +2746,11 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
} }
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
if (access.IsInobject()) { if (!access.IsInobject()) {
if (access.representation().IsInteger32()) {
__ movl(result, FieldOperand(object, offset));
} else {
__ movq(result, FieldOperand(object, offset));
}
} else {
__ movq(result, FieldOperand(object, JSObject::kPropertiesOffset)); __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset));
if (access.representation().IsInteger32()) { object = result;
__ movl(result, FieldOperand(result, offset));
} else {
__ movq(result, FieldOperand(result, offset));
}
} }
__ Load(result, FieldOperand(object, offset), access.representation());
} }
...@@ -3878,16 +3868,16 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { ...@@ -3878,16 +3868,16 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
int offset = access.offset(); int offset = access.offset();
if (access.IsExternalMemory()) { if (access.IsExternalMemory()) {
ASSERT(!access.representation().IsInteger32());
ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
Register value = ToRegister(instr->value()); Register value = ToRegister(instr->value());
if (instr->object()->IsConstantOperand()) { if (instr->object()->IsConstantOperand()) {
ASSERT(value.is(rax)); ASSERT(value.is(rax));
ASSERT(!access.representation().IsSpecialization());
LConstantOperand* object = LConstantOperand::cast(instr->object()); LConstantOperand* object = LConstantOperand::cast(instr->object());
__ store_rax(ToExternalReference(object)); __ store_rax(ToExternalReference(object));
} else { } else {
Register object = ToRegister(instr->object()); Register object = ToRegister(instr->object());
__ movq(MemOperand(object, offset), value); __ Store(MemOperand(object, offset), value, representation);
} }
return; return;
} }
...@@ -3956,24 +3946,16 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { ...@@ -3956,24 +3946,16 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
if (instr->value()->IsConstantOperand()) { if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
if (operand_value->IsRegister()) { if (operand_value->IsRegister()) {
if (access.representation().IsInteger32()) { Register value = ToRegister(operand_value);
__ movl(FieldOperand(write_register, offset), __ Store(FieldOperand(write_register, offset), value, representation);
ToRegister(operand_value));
} else {
__ movq(FieldOperand(write_register, offset),
ToRegister(operand_value));
}
} else { } else {
Handle<Object> handle_value = ToHandle(operand_value); Handle<Object> handle_value = ToHandle(operand_value);
ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
__ Move(FieldOperand(write_register, offset), handle_value); __ Move(FieldOperand(write_register, offset), handle_value);
} }
} else { } else {
if (access.representation().IsInteger32()) { Register value = ToRegister(instr->value());
__ movl(FieldOperand(write_register, offset), ToRegister(instr->value())); __ Store(FieldOperand(write_register, offset), value, representation);
} else {
__ movq(FieldOperand(write_register, offset), ToRegister(instr->value()));
}
} }
if (instr->hydrogen()->NeedsWriteBarrier()) { if (instr->hydrogen()->NeedsWriteBarrier()) {
......
...@@ -2068,7 +2068,14 @@ LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) { ...@@ -2068,7 +2068,14 @@ LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
if (instr->access().IsExternalMemory() && instr->access().offset() == 0) { // Use the special mov rax, moffs64 encoding for external
// memory accesses with 64-bit word-sized values.
if (instr->access().IsExternalMemory() &&
instr->access().offset() == 0 &&
(instr->access().representation().IsSmi() ||
instr->access().representation().IsTagged() ||
instr->access().representation().IsHeapObject() ||
instr->access().representation().IsExternal())) {
LOperand* obj = UseRegisterOrConstantAtStart(instr->object()); LOperand* obj = UseRegisterOrConstantAtStart(instr->object());
return DefineFixed(new(zone()) LLoadNamedField(obj), rax); return DefineFixed(new(zone()) LLoadNamedField(obj), rax);
} }
......
...@@ -947,6 +947,28 @@ void MacroAssembler::Cvtlsi2sd(XMMRegister dst, const Operand& src) { ...@@ -947,6 +947,28 @@ void MacroAssembler::Cvtlsi2sd(XMMRegister dst, const Operand& src) {
} }
void MacroAssembler::Load(Register dst, const Operand& src, Representation r) {
if (r.IsByte()) {
movzxbl(dst, src);
} else if (r.IsInteger32()) {
movl(dst, src);
} else {
movq(dst, src);
}
}
void MacroAssembler::Store(const Operand& dst, Register src, Representation r) {
if (r.IsByte()) {
movb(dst, src);
} else if (r.IsInteger32()) {
movl(dst, src);
} else {
movq(dst, src);
}
}
void MacroAssembler::Set(Register dst, int64_t x) { void MacroAssembler::Set(Register dst, int64_t x) {
if (x == 0) { if (x == 0) {
xorl(dst, dst); xorl(dst, dst);
......
...@@ -781,6 +781,10 @@ class MacroAssembler: public Assembler { ...@@ -781,6 +781,10 @@ class MacroAssembler: public Assembler {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Macro instructions. // Macro instructions.
// Load/store with specific representation.
void Load(Register dst, const Operand& src, Representation r);
void Store(const Operand& dst, Register src, Representation r);
// Load a register with a long value as efficiently as possible. // Load a register with a long value as efficiently as possible.
void Set(Register dst, int64_t x); void Set(Register dst, int64_t x);
void Set(const Operand& dst, int64_t x); void Set(const Operand& dst, int64_t x);
......
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