Commit 09ecf6ce authored by mbrandy's avatar mbrandy Committed by Commit bot

PPC: New hydrogen instruction to reduce cost of growing an array on keyed stores.

Port 3bce9c3a

Original commit message:
HMaybeGrowElements moves the situation where you actually have to grow
into deferred code. This means crankshaft doesn't have to spill registers
just to make the bounds comparison to see if it'll need to grow or not.

It makes the growing case a bit more expensive, but reduces the cost of
the general case.

R=mvstanton@chromium.org, dstence@us.ibm.com, michael_dawson@ca.ibm.com
BUG=

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

Cr-Commit-Position: refs/heads/master@{#28372}
parent ae6ec186
......@@ -56,7 +56,6 @@ const Register MathPowIntegerDescriptor::exponent() {
const Register GrowArrayElementsDescriptor::ObjectRegister() { return r3; }
const Register GrowArrayElementsDescriptor::KeyRegister() { return r6; }
const Register GrowArrayElementsDescriptor::CapacityRegister() { return r5; }
void FastNewClosureDescriptor::Initialize(CallInterfaceDescriptorData* data) {
......
......@@ -4769,6 +4769,99 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
}
void LCodeGen::DoMaybeGrowElements(LMaybeGrowElements* instr) {
class DeferredMaybeGrowElements final : public LDeferredCode {
public:
DeferredMaybeGrowElements(LCodeGen* codegen, LMaybeGrowElements* instr)
: LDeferredCode(codegen), instr_(instr) {}
void Generate() override { codegen()->DoDeferredMaybeGrowElements(instr_); }
LInstruction* instr() override { return instr_; }
private:
LMaybeGrowElements* instr_;
};
Register result = r3;
DeferredMaybeGrowElements* deferred =
new (zone()) DeferredMaybeGrowElements(this, instr);
LOperand* key = instr->key();
LOperand* current_capacity = instr->current_capacity();
DCHECK(instr->hydrogen()->key()->representation().IsInteger32());
DCHECK(instr->hydrogen()->current_capacity()->representation().IsInteger32());
DCHECK(key->IsConstantOperand() || key->IsRegister());
DCHECK(current_capacity->IsConstantOperand() ||
current_capacity->IsRegister());
if (key->IsConstantOperand() && current_capacity->IsConstantOperand()) {
int32_t constant_key = ToInteger32(LConstantOperand::cast(key));
int32_t constant_capacity =
ToInteger32(LConstantOperand::cast(current_capacity));
if (constant_key >= constant_capacity) {
// Deferred case.
__ b(deferred->entry());
}
} else if (key->IsConstantOperand()) {
int32_t constant_key = ToInteger32(LConstantOperand::cast(key));
__ Cmpwi(ToRegister(current_capacity), Operand(constant_key), r0);
__ ble(deferred->entry());
} else if (current_capacity->IsConstantOperand()) {
int32_t constant_capacity =
ToInteger32(LConstantOperand::cast(current_capacity));
__ Cmpwi(ToRegister(key), Operand(constant_capacity), r0);
__ bge(deferred->entry());
} else {
__ cmpw(ToRegister(key), ToRegister(current_capacity));
__ bge(deferred->entry());
}
if (instr->elements()->IsRegister()) {
__ Move(result, ToRegister(instr->elements()));
} else {
__ LoadP(result, ToMemOperand(instr->elements()));
}
__ bind(deferred->exit());
}
void LCodeGen::DoDeferredMaybeGrowElements(LMaybeGrowElements* instr) {
// TODO(3095996): Get rid of this. For now, we need to make the
// result register contain a valid pointer because it is already
// contained in the register pointer map.
Register result = r3;
__ li(result, Operand::Zero());
// We have to call a stub.
{
PushSafepointRegistersScope scope(this);
if (instr->object()->IsRegister()) {
__ Move(result, ToRegister(instr->object()));
} else {
__ LoadP(result, ToMemOperand(instr->object()));
}
LOperand* key = instr->key();
if (key->IsConstantOperand()) {
__ LoadSmiLiteral(r6, ToSmi(LConstantOperand::cast(key)));
} else {
__ SmiTag(r6, ToRegister(key));
}
GrowArrayElementsStub stub(isolate(), instr->hydrogen()->is_js_array(),
instr->hydrogen()->kind());
__ CallStub(&stub);
RecordSafepointWithLazyDeopt(
instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
__ StoreToSafepointRegisterSlot(result, result);
}
// Deopt on smi, which means the elements array changed to dictionary mode.
__ TestIfSmi(result, r0);
DeoptimizeIf(eq, instr, Deoptimizer::kSmi, cr0);
}
void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
Register object_reg = ToRegister(instr->object());
Register scratch = scratch0();
......
......@@ -108,6 +108,7 @@ class LCodeGen : public LCodeGenBase {
void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredMaybeGrowElements(LMaybeGrowElements* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredAllocate(LAllocate* instr);
......
......@@ -2322,6 +2322,21 @@ LInstruction* LChunkBuilder::DoTrapAllocationMemento(
}
LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
info()->MarkAsDeferredCalling();
LOperand* context = UseFixed(instr->context(), cp);
LOperand* object = Use(instr->object());
LOperand* elements = Use(instr->elements());
LOperand* key = UseRegisterOrConstant(instr->key());
LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());
LMaybeGrowElements* result = new (zone())
LMaybeGrowElements(context, object, elements, key, current_capacity);
DefineFixed(result, r3);
return AssignPointerMap(AssignEnvironment(result));
}
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
bool is_in_object = instr->access().IsInobject();
bool needs_write_barrier = instr->NeedsWriteBarrier();
......
......@@ -117,6 +117,7 @@ class LCodeGen;
V(MathPowHalf) \
V(MathRound) \
V(MathSqrt) \
V(MaybeGrowElements) \
V(ModByConstI) \
V(ModByPowerOf2I) \
V(ModI) \
......@@ -2226,6 +2227,28 @@ class LTrapAllocationMemento final : public LTemplateInstruction<0, 1, 1> {
};
class LMaybeGrowElements final : public LTemplateInstruction<1, 5, 0> {
public:
LMaybeGrowElements(LOperand* context, LOperand* object, LOperand* elements,
LOperand* key, LOperand* current_capacity) {
inputs_[0] = context;
inputs_[1] = object;
inputs_[2] = elements;
inputs_[3] = key;
inputs_[4] = current_capacity;
}
LOperand* context() { return inputs_[0]; }
LOperand* object() { return inputs_[1]; }
LOperand* elements() { return inputs_[2]; }
LOperand* key() { return inputs_[3]; }
LOperand* current_capacity() { return inputs_[4]; }
DECLARE_HYDROGEN_ACCESSOR(MaybeGrowElements)
DECLARE_CONCRETE_INSTRUCTION(MaybeGrowElements, "maybe-grow-elements")
};
class LStringAdd final : public LTemplateInstruction<1, 3, 0> {
public:
LStringAdd(LOperand* context, LOperand* left, LOperand* right) {
......
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