Commit f1478bd1 authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

X87: [turbofan] Avoid unnecessary write barriers and improve code generation.

   port 1e277012 (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}
parent e9528b83
......@@ -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;
}
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 {
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;
}
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);
} else {
val = g.UseRegister(value);
}
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);
}
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);
}
......
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