X87: [turbofan] Avoid unnecessary write barriers and improve code generation.
port 1e2770123b
(r31914)
original commit message:
Avoid write barriers when storing values in the root set, and use
cheaper write barriers for storing maps or tagged pointers. Also
improve the generated code for write barriers, utilizing the out
of line code mechanism that is available to TurboFan backends,
which moves the unlikely case out of the hot path.
BUG=
Review URL: https://codereview.chromium.org/1435743003
Cr-Commit-Position: refs/heads/master@{#31935}
This commit is contained in:
parent
e9528b8300
commit
f1478bd141
@ -218,6 +218,46 @@ class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
|
||||
X87Register const input_;
|
||||
};
|
||||
|
||||
|
||||
class OutOfLineRecordWrite final : public OutOfLineCode {
|
||||
public:
|
||||
OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand operand,
|
||||
Register value, Register scratch0, Register scratch1,
|
||||
RecordWriteMode mode)
|
||||
: OutOfLineCode(gen),
|
||||
object_(object),
|
||||
operand_(operand),
|
||||
value_(value),
|
||||
scratch0_(scratch0),
|
||||
scratch1_(scratch1),
|
||||
mode_(mode) {}
|
||||
|
||||
void Generate() final {
|
||||
if (mode_ > RecordWriteMode::kValueIsPointer) {
|
||||
__ JumpIfSmi(value_, exit());
|
||||
}
|
||||
if (mode_ > RecordWriteMode::kValueIsMap) {
|
||||
__ CheckPageFlag(value_, scratch0_,
|
||||
MemoryChunk::kPointersToHereAreInterestingMask, zero,
|
||||
exit());
|
||||
}
|
||||
SaveFPRegsMode const save_fp_mode =
|
||||
frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
|
||||
RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
|
||||
EMIT_REMEMBERED_SET, save_fp_mode);
|
||||
__ lea(scratch1_, operand_);
|
||||
__ CallStub(&stub);
|
||||
}
|
||||
|
||||
private:
|
||||
Register const object_;
|
||||
Operand const operand_;
|
||||
Register const value_;
|
||||
Register const scratch0_;
|
||||
Register const scratch1_;
|
||||
RecordWriteMode const mode_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@ -456,6 +496,24 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kArchStoreWithWriteBarrier: {
|
||||
RecordWriteMode mode =
|
||||
static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
|
||||
Register object = i.InputRegister(0);
|
||||
size_t index = 0;
|
||||
Operand operand = i.MemoryOperand(&index);
|
||||
Register value = i.InputRegister(index);
|
||||
Register scratch0 = i.TempRegister(0);
|
||||
Register scratch1 = i.TempRegister(1);
|
||||
auto ool = new (zone()) OutOfLineRecordWrite(this, object, operand, value,
|
||||
scratch0, scratch1, mode);
|
||||
__ mov(operand, value);
|
||||
__ CheckPageFlag(object, scratch0,
|
||||
MemoryChunk::kPointersFromHereAreInterestingMask,
|
||||
not_zero, ool->entry());
|
||||
__ bind(ool->exit());
|
||||
break;
|
||||
}
|
||||
case kX87Add:
|
||||
if (HasImmediateInput(instr, 1)) {
|
||||
__ add(i.InputOperand(0), i.InputImmediate(1));
|
||||
@ -1216,24 +1274,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case kX87StoreWriteBarrier: {
|
||||
Register object = i.InputRegister(0);
|
||||
Register value = i.InputRegister(2);
|
||||
SaveFPRegsMode mode =
|
||||
frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
|
||||
if (HasImmediateInput(instr, 1)) {
|
||||
int index = i.InputInt32(1);
|
||||
Register scratch = i.TempRegister(1);
|
||||
__ mov(Operand(object, index), value);
|
||||
__ RecordWriteContextSlot(object, index, value, scratch, mode);
|
||||
} else {
|
||||
Register index = i.InputRegister(1);
|
||||
__ mov(Operand(object, index, times_1, 0), value);
|
||||
__ lea(index, Operand(object, index, times_1, 0));
|
||||
__ RecordWrite(object, index, value, mode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kCheckedLoadInt8:
|
||||
ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b);
|
||||
break;
|
||||
|
@ -81,7 +81,6 @@ namespace compiler {
|
||||
V(X87PushFloat64) \
|
||||
V(X87PushFloat32) \
|
||||
V(X87Poke) \
|
||||
V(X87StoreWriteBarrier) \
|
||||
V(X87StackCheck)
|
||||
|
||||
|
||||
|
@ -176,66 +176,89 @@ void InstructionSelector::VisitStore(Node* node) {
|
||||
Node* value = node->InputAt(2);
|
||||
|
||||
StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
|
||||
WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
|
||||
MachineType rep = RepresentationOf(store_rep.machine_type());
|
||||
if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
|
||||
|
||||
if (write_barrier_kind != kNoWriteBarrier) {
|
||||
DCHECK_EQ(kRepTagged, rep);
|
||||
// TODO(dcarney): refactor RecordWrite function to take temp registers
|
||||
// and pass them here instead of using fixed regs
|
||||
AddressingMode addressing_mode;
|
||||
InstructionOperand inputs[3];
|
||||
size_t input_count = 0;
|
||||
inputs[input_count++] = g.UseUniqueRegister(base);
|
||||
if (g.CanBeImmediate(index)) {
|
||||
InstructionOperand temps[] = {g.TempRegister(ecx), g.TempRegister()};
|
||||
Emit(kX87StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, ebx),
|
||||
g.UseImmediate(index), g.UseFixed(value, ecx), arraysize(temps),
|
||||
temps);
|
||||
inputs[input_count++] = g.UseImmediate(index);
|
||||
addressing_mode = kMode_MRI;
|
||||
} else {
|
||||
InstructionOperand temps[] = {g.TempRegister(ecx), g.TempRegister(edx)};
|
||||
Emit(kX87StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, ebx),
|
||||
g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps),
|
||||
temps);
|
||||
inputs[input_count++] = g.UseUniqueRegister(index);
|
||||
addressing_mode = kMode_MR1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
|
||||
|
||||
ArchOpcode opcode;
|
||||
switch (rep) {
|
||||
case kRepFloat32:
|
||||
opcode = kX87Movss;
|
||||
break;
|
||||
case kRepFloat64:
|
||||
opcode = kX87Movsd;
|
||||
break;
|
||||
case kRepBit: // Fall through.
|
||||
case kRepWord8:
|
||||
opcode = kX87Movb;
|
||||
break;
|
||||
case kRepWord16:
|
||||
opcode = kX87Movw;
|
||||
break;
|
||||
case kRepTagged: // Fall through.
|
||||
case kRepWord32:
|
||||
opcode = kX87Movl;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
InstructionOperand val;
|
||||
if (g.CanBeImmediate(value)) {
|
||||
val = g.UseImmediate(value);
|
||||
} else if (rep == kRepWord8 || rep == kRepBit) {
|
||||
val = g.UseByteRegister(value);
|
||||
inputs[input_count++] = (write_barrier_kind == kMapWriteBarrier)
|
||||
? g.UseRegister(value)
|
||||
: g.UseUniqueRegister(value);
|
||||
RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
|
||||
switch (write_barrier_kind) {
|
||||
case kNoWriteBarrier:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case kMapWriteBarrier:
|
||||
record_write_mode = RecordWriteMode::kValueIsMap;
|
||||
break;
|
||||
case kPointerWriteBarrier:
|
||||
record_write_mode = RecordWriteMode::kValueIsPointer;
|
||||
break;
|
||||
case kFullWriteBarrier:
|
||||
record_write_mode = RecordWriteMode::kValueIsAny;
|
||||
break;
|
||||
}
|
||||
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
|
||||
size_t const temp_count = arraysize(temps);
|
||||
InstructionCode code = kArchStoreWithWriteBarrier;
|
||||
code |= AddressingModeField::encode(addressing_mode);
|
||||
code |= MiscField::encode(static_cast<int>(record_write_mode));
|
||||
Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
|
||||
} else {
|
||||
val = g.UseRegister(value);
|
||||
}
|
||||
ArchOpcode opcode;
|
||||
switch (rep) {
|
||||
case kRepFloat32:
|
||||
opcode = kX87Movss;
|
||||
break;
|
||||
case kRepFloat64:
|
||||
opcode = kX87Movsd;
|
||||
break;
|
||||
case kRepBit: // Fall through.
|
||||
case kRepWord8:
|
||||
opcode = kX87Movb;
|
||||
break;
|
||||
case kRepWord16:
|
||||
opcode = kX87Movw;
|
||||
break;
|
||||
case kRepTagged: // Fall through.
|
||||
case kRepWord32:
|
||||
opcode = kX87Movl;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
InstructionOperand inputs[4];
|
||||
size_t input_count = 0;
|
||||
AddressingMode mode =
|
||||
g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
|
||||
InstructionCode code = opcode | AddressingModeField::encode(mode);
|
||||
inputs[input_count++] = val;
|
||||
Emit(code, 0, static_cast<InstructionOperand*>(NULL), input_count, inputs);
|
||||
InstructionOperand val;
|
||||
if (g.CanBeImmediate(value)) {
|
||||
val = g.UseImmediate(value);
|
||||
} else if (rep == kRepWord8 || rep == kRepBit) {
|
||||
val = g.UseByteRegister(value);
|
||||
} else {
|
||||
val = g.UseRegister(value);
|
||||
}
|
||||
|
||||
InstructionOperand inputs[4];
|
||||
size_t input_count = 0;
|
||||
AddressingMode addressing_mode =
|
||||
g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
|
||||
InstructionCode code =
|
||||
opcode | AddressingModeField::encode(addressing_mode);
|
||||
inputs[input_count++] = val;
|
||||
Emit(code, 0, static_cast<InstructionOperand*>(NULL), input_count, inputs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user