X87: enable the crankshaft compiler for X87 port.

BUG=
R=weiliang.lin@intel.com

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

Patch from Chunyang Dai <chunyang.dai@intel.com>.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24102 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ffd7362f
......@@ -411,7 +411,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
// Update the write barrier for the map field.
__ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
if (details.type() == CONSTANT) {
DCHECK(value_reg.is(eax));
......@@ -445,7 +445,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
__ mov(storage_reg, value_reg);
}
__ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
EMIT_REMEMBERED_SET, smi_check);
kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
}
} else {
// Write to the properties array.
......@@ -464,7 +464,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
__ mov(storage_reg, value_reg);
}
__ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
EMIT_REMEMBERED_SET, smi_check);
kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
}
}
......
......@@ -133,7 +133,7 @@ static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label,
// Update write barrier. Make sure not to clobber the value.
__ mov(r1, value);
__ RecordWrite(elements, r0, r1);
__ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
}
......@@ -546,7 +546,7 @@ void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
__ mov(mapped_location, value);
__ lea(ecx, mapped_location);
__ mov(edx, value);
__ RecordWrite(ebx, ecx, edx);
__ RecordWrite(ebx, ecx, edx, kDontSaveFPRegs);
__ Ret();
__ bind(&notin);
// The unmapped lookup expects that the parameter map is in ebx.
......@@ -555,7 +555,7 @@ void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
__ mov(unmapped_location, value);
__ lea(edi, unmapped_location);
__ mov(edx, value);
__ RecordWrite(ebx, edi, edx);
__ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
__ Ret();
__ bind(&slow);
GenerateMiss(masm);
......@@ -624,7 +624,8 @@ static void KeyedStoreGenerateGenericHelper(
__ mov(FixedArrayElementOperand(ebx, key), value);
// Update write barrier for the elements array address.
__ mov(edx, value); // Preserve the value which is returned.
__ RecordWriteArray(ebx, edx, key, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ RecordWriteArray(ebx, edx, key, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ ret(0);
__ bind(fast_double);
......
......@@ -45,7 +45,7 @@
namespace v8 {
namespace internal {
bool CpuFeatures::SupportsCrankshaft() { return false; }
bool CpuFeatures::SupportsCrankshaft() { return true; }
static const byte kCallOpcode = 0xE8;
......
......@@ -1519,6 +1519,20 @@ void Assembler::fst_s(const Operand& adr) {
}
void Assembler::fldcw(const Operand& adr) {
EnsureSpace ensure_space(this);
EMIT(0xD9);
emit_operand(ebp, adr);
}
void Assembler::fnstcw(const Operand& adr) {
EnsureSpace ensure_space(this);
EMIT(0xD9);
emit_operand(edi, adr);
}
void Assembler::fstp_d(const Operand& adr) {
EnsureSpace ensure_space(this);
EMIT(0xDD);
......@@ -1598,6 +1612,13 @@ void Assembler::fchs() {
}
void Assembler::fsqrt() {
EnsureSpace ensure_space(this);
EMIT(0xD9);
EMIT(0xFA);
}
void Assembler::fcos() {
EnsureSpace ensure_space(this);
EMIT(0xD9);
......@@ -1659,6 +1680,13 @@ void Assembler::fadd_i(int i) {
}
void Assembler::fadd_d(const Operand& adr) {
EnsureSpace ensure_space(this);
EMIT(0xDC);
emit_operand(eax, adr);
}
void Assembler::fsub(int i) {
EnsureSpace ensure_space(this);
emit_farith(0xDC, 0xE8, i);
......@@ -1772,6 +1800,13 @@ void Assembler::ftst() {
}
void Assembler::fxam() {
EnsureSpace ensure_space(this);
EMIT(0xD9);
EMIT(0xE5);
}
void Assembler::fucomp(int i) {
EnsureSpace ensure_space(this);
emit_farith(0xDD, 0xE8, i);
......@@ -1833,6 +1868,20 @@ void Assembler::fnclex() {
}
void Assembler::fnsave(const Operand& adr) {
EnsureSpace ensure_space(this);
EMIT(0xDD);
emit_operand(esi, adr);
}
void Assembler::frstor(const Operand& adr) {
EnsureSpace ensure_space(this);
EMIT(0xDD);
emit_operand(esp, adr);
}
void Assembler::sahf() {
EnsureSpace ensure_space(this);
EMIT(0x9E);
......
......@@ -142,7 +142,7 @@ inline Register Register::FromAllocationIndex(int index) {
struct X87Register {
static const int kMaxNumAllocatableRegisters = 8;
static const int kMaxNumAllocatableRegisters = 6;
static const int kMaxNumRegisters = 8;
static int NumAllocatableRegisters() {
return kMaxNumAllocatableRegisters;
......@@ -852,6 +852,7 @@ class Assembler : public AssemblerBase {
void fabs();
void fchs();
void fsqrt();
void fcos();
void fsin();
void fptan();
......@@ -862,6 +863,7 @@ class Assembler : public AssemblerBase {
void fadd(int i);
void fadd_i(int i);
void fadd_d(const Operand& adr);
void fsub(int i);
void fsub_i(int i);
void fmul(int i);
......@@ -884,14 +886,19 @@ class Assembler : public AssemblerBase {
void ffree(int i = 0);
void ftst();
void fxam();
void fucomp(int i);
void fucompp();
void fucomi(int i);
void fucomip();
void fcompp();
void fnstsw_ax();
void fldcw(const Operand& adr);
void fnstcw(const Operand& adr);
void fwait();
void fnclex();
void fnsave(const Operand& adr);
void frstor(const Operand& adr);
void frndint();
......
......@@ -660,7 +660,8 @@ void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
}
static void Generate_NotifyStubFailureHelper(MacroAssembler* masm) {
static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
SaveFPRegsMode save_doubles) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
......@@ -669,7 +670,7 @@ static void Generate_NotifyStubFailureHelper(MacroAssembler* masm) {
// stubs that tail call the runtime on deopts passing their parameters in
// registers.
__ pushad();
__ CallRuntime(Runtime::kNotifyStubFailure, 0);
__ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
__ popad();
// Tear down internal frame.
}
......@@ -680,13 +681,12 @@ static void Generate_NotifyStubFailureHelper(MacroAssembler* masm) {
void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
Generate_NotifyStubFailureHelper(masm);
Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
}
void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
// SaveDoubles is meanless for X87, just used by deoptimizer.cc
Generate_NotifyStubFailureHelper(masm);
Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
}
......
......@@ -127,6 +127,11 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
// store the registers in any particular way, but we do have to store and
// restore them.
__ pushad();
if (save_doubles()) {
// Save FPU stat in m108byte.
__ sub(esp, Immediate(108));
__ fnsave(Operand(esp, 0));
}
const int argument_count = 1;
AllowExternalCallThatCantCauseGC scope(masm);
......@@ -136,6 +141,11 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
__ CallCFunction(
ExternalReference::store_buffer_overflow_function(isolate()),
argument_count);
if (save_doubles()) {
// Restore FPU stat in m108byte.
__ frstor(Operand(esp, 0));
__ add(esp, Immediate(108));
}
__ popad();
__ ret(0);
}
......@@ -1115,16 +1125,12 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ mov(eax, Operand(esp, kSubjectOffset));
__ mov(ecx, eax);
__ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax);
__ RecordWriteField(ebx,
RegExpImpl::kLastSubjectOffset,
eax,
edi);
__ RecordWriteField(ebx, RegExpImpl::kLastSubjectOffset, eax, edi,
kDontSaveFPRegs);
__ mov(eax, ecx);
__ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax);
__ RecordWriteField(ebx,
RegExpImpl::kLastInputOffset,
eax,
edi);
__ RecordWriteField(ebx, RegExpImpl::kLastInputOffset, eax, edi,
kDontSaveFPRegs);
// Get the static offsets vector filled by the native regexp code.
ExternalReference address_of_static_offsets_vector =
......@@ -1618,7 +1624,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
__ push(edi);
__ push(ebx);
__ push(edx);
__ RecordWriteArray(ebx, edi, edx, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ RecordWriteArray(ebx, edi, edx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ pop(edx);
__ pop(ebx);
__ pop(edi);
......@@ -1989,12 +1996,19 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
void CodeStub::GenerateFPStubs(Isolate* isolate) {
// Do nothing.
CEntryStub save_doubles(isolate, 1, kSaveFPRegs);
// Stubs might already be in the snapshot, detect that and don't regenerate,
// which would lead to code stub initialization state being messed up.
Code* save_doubles_code;
if (!save_doubles.FindCodeInCache(&save_doubles_code)) {
save_doubles_code = *(save_doubles.GetCode());
}
isolate->set_fp_stubs_generated(true);
}
void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
CEntryStub stub(isolate, 1);
CEntryStub stub(isolate, 1, kDontSaveFPRegs);
stub.GetCode();
}
......@@ -2010,7 +2024,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
ProfileEntryHookStub::MaybeCallEntryHook(masm);
// Enter the exit frame that transitions from JavaScript to C++.
__ EnterExitFrame();
__ EnterExitFrame(save_doubles());
// ebx: pointer to C function (C callee-saved)
// ebp: frame pointer (restored after C call)
......@@ -2066,7 +2080,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
}
// Exit the JavaScript to C++ exit frame.
__ LeaveExitFrame();
__ LeaveExitFrame(save_doubles());
__ ret(0);
// Handling of exception.
......@@ -3545,6 +3559,8 @@ void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
Isolate* isolate) {
StoreBufferOverflowStub stub(isolate, kDontSaveFPRegs);
stub.GetCode();
StoreBufferOverflowStub stub2(isolate, kSaveFPRegs);
stub2.GetCode();
}
......@@ -3564,7 +3580,7 @@ void RecordWriteStub::Generate(MacroAssembler* masm) {
__ jmp(&skip_to_incremental_compacting, Label::kFar);
if (remembered_set_action() == EMIT_REMEMBERED_SET) {
__ RememberedSetHelper(object(), address(), value(),
__ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
MacroAssembler::kReturnAtEnd);
} else {
__ ret(0);
......@@ -3608,7 +3624,7 @@ void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
mode);
InformIncrementalMarker(masm);
regs_.Restore(masm);
__ RememberedSetHelper(object(), address(), value(),
__ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
MacroAssembler::kReturnAtEnd);
__ bind(&dont_need_remembered_set);
......@@ -3625,7 +3641,7 @@ void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
regs_.SaveCallerSaveRegisters(masm);
regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode());
int argument_count = 3;
__ PrepareCallCFunction(argument_count, regs_.scratch0());
__ mov(Operand(esp, 0 * kPointerSize), regs_.object());
......@@ -3638,7 +3654,7 @@ void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
ExternalReference::incremental_marking_record_write_function(isolate()),
argument_count);
regs_.RestoreCallerSaveRegisters(masm);
regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode());
}
......@@ -3669,7 +3685,7 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
regs_.Restore(masm);
if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
__ RememberedSetHelper(object(), address(), value(),
__ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
MacroAssembler::kReturnAtEnd);
} else {
__ ret(0);
......@@ -3714,7 +3730,7 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
regs_.Restore(masm);
if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
__ RememberedSetHelper(object(), address(), value(),
__ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
MacroAssembler::kReturnAtEnd);
} else {
__ ret(0);
......@@ -3784,8 +3800,7 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
FixedArrayBase::kHeaderSize));
__ mov(Operand(ecx, 0), eax);
// Update the write barrier for the array store.
__ RecordWrite(ebx, ecx, eax,
EMIT_REMEMBERED_SET,
__ RecordWrite(ebx, ecx, eax, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ ret(0);
......@@ -3814,7 +3829,7 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
CEntryStub ces(isolate(), 1);
CEntryStub ces(isolate(), 1, kSaveFPRegs);
__ call(ces.GetCode(), RelocInfo::CODE_TARGET);
int parameter_count_offset =
StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
......
......@@ -116,11 +116,9 @@ class NameDictionaryLookupStub: public PlatformCodeStub {
class RecordWriteStub: public PlatformCodeStub {
public:
RecordWriteStub(Isolate* isolate,
Register object,
Register value,
Register address,
RememberedSetAction remembered_set_action)
RecordWriteStub(Isolate* isolate, Register object, Register value,
Register address, RememberedSetAction remembered_set_action,
SaveFPRegsMode fp_mode)
: PlatformCodeStub(isolate),
regs_(object, // An input reg.
address, // An input reg.
......@@ -128,7 +126,8 @@ class RecordWriteStub: public PlatformCodeStub {
minor_key_ = ObjectBits::encode(object.code()) |
ValueBits::encode(value.code()) |
AddressBits::encode(address.code()) |
RememberedSetActionBits::encode(remembered_set_action);
RememberedSetActionBits::encode(remembered_set_action) |
SaveFPRegsModeBits::encode(fp_mode);
}
RecordWriteStub(uint32_t key, Isolate* isolate)
......@@ -271,12 +270,23 @@ class RecordWriteStub: public PlatformCodeStub {
// saved registers that were not already preserved. The caller saved
// registers are eax, ecx and edx. The three scratch registers (incl. ecx)
// will be restored by other means so we don't bother pushing them here.
void SaveCallerSaveRegisters(MacroAssembler* masm) {
void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax);
if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx);
if (mode == kSaveFPRegs) {
// Save FPU state in m108byte.
masm->sub(esp, Immediate(108));
masm->fnsave(Operand(esp, 0));
}
}
inline void RestoreCallerSaveRegisters(MacroAssembler*masm) {
inline void RestoreCallerSaveRegisters(MacroAssembler* masm,
SaveFPRegsMode mode) {
if (mode == kSaveFPRegs) {
// Restore FPU state in m108byte.
masm->frstor(Operand(esp, 0));
masm->add(esp, Immediate(108));
}
if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx);
if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax);
}
......@@ -348,10 +358,15 @@ class RecordWriteStub: public PlatformCodeStub {
return RememberedSetActionBits::decode(minor_key_);
}
SaveFPRegsMode save_fp_regs_mode() const {
return SaveFPRegsModeBits::decode(minor_key_);
}
class ObjectBits: public BitField<int, 0, 3> {};
class ValueBits: public BitField<int, 3, 3> {};
class AddressBits: public BitField<int, 6, 3> {};
class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
class SaveFPRegsModeBits : public BitField<SaveFPRegsMode, 10, 1> {};
RegisterAllocation regs_;
......
......@@ -217,12 +217,8 @@ void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
// Set transitioned map.
__ mov(FieldOperand(receiver, HeapObject::kMapOffset), target_map);
__ RecordWriteField(receiver,
HeapObject::kMapOffset,
target_map,
scratch,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch,
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
}
......@@ -275,12 +271,8 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
// Replace receiver's backing store with newly created FixedDoubleArray.
__ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
__ mov(ebx, eax);
__ RecordWriteField(edx,
JSObject::kElementsOffset,
ebx,
edi,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ RecordWriteField(edx, JSObject::kElementsOffset, ebx, edi, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
......@@ -339,12 +331,8 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
// ebx: target map
// Set transitioned map.
__ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
__ RecordWriteField(edx,
HeapObject::kMapOffset,
ebx,
edi,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ RecordWriteField(edx, HeapObject::kMapOffset, ebx, edi, kDontSaveFPRegs,
OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
}
......@@ -399,12 +387,8 @@ void ElementsTransitionGenerator::GenerateDoubleToObject(
// Set transitioned map.
__ bind(&only_change_map);
__ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
__ RecordWriteField(edx,
HeapObject::kMapOffset,
ebx,
edi,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ RecordWriteField(edx, HeapObject::kMapOffset, ebx, edi, kDontSaveFPRegs,
OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ jmp(&success);
// Call into runtime if GC is required.
......@@ -433,10 +417,7 @@ void ElementsTransitionGenerator::GenerateDoubleToObject(
__ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
__ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
__ mov(esi, ebx);
__ RecordWriteArray(eax,
edx,
esi,
EMIT_REMEMBERED_SET,
__ RecordWriteArray(eax, edx, esi, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ jmp(&entry, Label::kNear);
......@@ -455,20 +436,12 @@ void ElementsTransitionGenerator::GenerateDoubleToObject(
// edx: receiver
// Set transitioned map.
__ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
__ RecordWriteField(edx,
HeapObject::kMapOffset,
ebx,
edi,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ RecordWriteField(edx, HeapObject::kMapOffset, ebx, edi, kDontSaveFPRegs,
OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
// Replace receiver's backing store with newly created and filled FixedArray.
__ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
__ RecordWriteField(edx,
JSObject::kElementsOffset,
eax,
edi,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ RecordWriteField(edx, JSObject::kElementsOffset, eax, edi, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
// Restore registers.
__ pop(eax);
......
......@@ -204,8 +204,10 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
// Do nothing for X87.
return;
for (int i = 0; i < X87Register::kMaxNumAllocatableRegisters; ++i) {
double double_value = input_->GetDoubleRegister(i);
output_frame->SetDoubleRegister(i, double_value);
}
}
......@@ -230,9 +232,42 @@ void Deoptimizer::EntryGenerator::Generate() {
// Save all general purpose registers before messing with them.
const int kNumberOfRegisters = Register::kNumRegisters;
const int kDoubleRegsSize =
kDoubleSize * X87Register::kMaxNumAllocatableRegisters;
// Reserve space for x87 fp registers.
__ sub(esp, Immediate(kDoubleRegsSize));
__ pushad();
const int kSavedRegistersAreaSize = kNumberOfRegisters * kPointerSize;
// GP registers are safe to use now.
// Save used x87 fp registers in correct position of previous reserve space.
Label loop, done;
// Get the layout of x87 stack.
__ sub(esp, Immediate(kPointerSize));
__ fistp_s(MemOperand(esp, 0));
__ pop(eax);
// Preserve stack layout in edi
__ mov(edi, eax);
// Get the x87 stack depth, the first 3 bits.
__ mov(ecx, eax);
__ and_(ecx, 0x7);
__ j(zero, &done, Label::kNear);
__ bind(&loop);
__ shr(eax, 0x3);
__ mov(ebx, eax);
__ and_(ebx, 0x7); // Extract the st_x index into ebx.
// Pop TOS to the correct position. The disp(0x20) is due to pushad.
// The st_i should be saved to (esp + ebx * kDoubleSize + 0x20).
__ fstp_d(Operand(esp, ebx, times_8, 0x20));
__ dec(ecx); // Decrease stack depth.
__ j(not_zero, &loop, Label::kNear);
__ bind(&done);
const int kSavedRegistersAreaSize =
kNumberOfRegisters * kPointerSize + kDoubleRegsSize;
// Get the bailout id from the stack.
__ mov(ebx, Operand(esp, kSavedRegistersAreaSize));
......@@ -245,6 +280,7 @@ void Deoptimizer::EntryGenerator::Generate() {
__ sub(edx, ebp);
__ neg(edx);
__ push(edi);
// Allocate a new deoptimizer object.
__ PrepareCallCFunction(6, eax);
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
......@@ -260,6 +296,8 @@ void Deoptimizer::EntryGenerator::Generate() {
__ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6);
}
__ pop(edi);
// Preserve deoptimizer object in register eax and get the input
// frame descriptor pointer.
__ mov(ebx, Operand(eax, Deoptimizer::input_offset()));
......@@ -270,13 +308,22 @@ void Deoptimizer::EntryGenerator::Generate() {
__ pop(Operand(ebx, offset));
}
int double_regs_offset = FrameDescription::double_registers_offset();
// Fill in the double input registers.
for (int i = 0; i < X87Register::kMaxNumAllocatableRegisters; ++i) {
int dst_offset = i * kDoubleSize + double_regs_offset;
int src_offset = i * kDoubleSize;
__ fld_d(Operand(esp, src_offset));
__ fstp_d(Operand(ebx, dst_offset));
}
// Clear FPU all exceptions.
// TODO(ulan): Find out why the TOP register is not zero here in some cases,
// and check that the generated code never deoptimizes with unbalanced stack.
__ fnclex();
// Remove the bailout id, return address and the double registers.
__ add(esp, Immediate(2 * kPointerSize));
__ add(esp, Immediate(kDoubleRegsSize + 2 * kPointerSize));
// Compute a pointer to the unwinding limit in register ecx; that is
// the first stack slot not part of the input frame.
......@@ -298,6 +345,7 @@ void Deoptimizer::EntryGenerator::Generate() {
__ j(not_equal, &pop_loop);
// Compute the output frame in the deoptimizer.
__ push(edi);
__ push(eax);
__ PrepareCallCFunction(1, ebx);
__ mov(Operand(esp, 0 * kPointerSize), eax);
......@@ -307,6 +355,7 @@ void Deoptimizer::EntryGenerator::Generate() {
ExternalReference::compute_output_frames_function(isolate()), 1);
}
__ pop(eax);
__ pop(edi);
// If frame was dynamically aligned, pop padding.
Label no_padding;
......@@ -345,6 +394,25 @@ void Deoptimizer::EntryGenerator::Generate() {
__ cmp(eax, edx);
__ j(below, &outer_push_loop);
// In case of a failed STUB, we have to restore the x87 stack.
// x87 stack layout is in edi.
Label loop2, done2;
// Get the x87 stack depth, the first 3 bits.
__ mov(ecx, edi);
__ and_(ecx, 0x7);
__ j(zero, &done2, Label::kNear);
__ lea(ecx, Operand(ecx, ecx, times_2, 0));
__ bind(&loop2);
__ mov(eax, edi);
__ shr_cl(eax);
__ and_(eax, 0x7);
__ fld_d(Operand(ebx, eax, times_8, double_regs_offset));
__ sub(ecx, Immediate(0x3));
__ j(not_zero, &loop2, Label::kNear);
__ bind(&done2);
// Push state, pc, and continuation from the last output frame.
__ push(Operand(ebx, FrameDescription::state_offset()));
__ push(Operand(ebx, FrameDescription::pc_offset()));
......
......@@ -702,7 +702,12 @@ int DisassemblerX87::MemoryFPUInstruction(int escape_opcode,
case 0: mnem = "fld_s"; break;
case 2: mnem = "fst_s"; break;
case 3: mnem = "fstp_s"; break;
case 7: mnem = "fstcw"; break;
case 5:
mnem = "fldcw";
break;
case 7:
mnem = "fnstcw";
break;
default: UnimplementedInstruction();
}
break;
......@@ -716,11 +721,27 @@ int DisassemblerX87::MemoryFPUInstruction(int escape_opcode,
}
break;
case 0xDC:
switch (regop) {
case 0:
mnem = "fadd_d";
break;
default:
UnimplementedInstruction();
}
break;
case 0xDD: switch (regop) {
case 0: mnem = "fld_d"; break;
case 1: mnem = "fisttp_d"; break;
case 2: mnem = "fst_d"; break;
case 3: mnem = "fstp_d"; break;
case 4:
mnem = "frstor";
break;
case 6:
mnem = "fnsave";
break;
default: UnimplementedInstruction();
}
break;
......
......@@ -221,10 +221,8 @@ void FullCodeGenerator::Generate() {
__ mov(Operand(esi, context_offset), eax);
// Update the write barrier. This clobbers eax and ebx.
if (need_write_barrier) {
__ RecordWriteContextSlot(esi,
context_offset,
eax,
ebx);
__ RecordWriteContextSlot(esi, context_offset, eax, ebx,
kDontSaveFPRegs);
} else if (FLAG_debug_code) {
Label done;
__ JumpIfInNewSpace(esi, eax, &done, Label::kNear);
......@@ -708,7 +706,7 @@ void FullCodeGenerator::SetVar(Variable* var,
if (var->IsContextSlot()) {
int offset = Context::SlotOffset(var->index());
DCHECK(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
__ RecordWriteContextSlot(scratch0, offset, src, scratch1);
__ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
}
}
......@@ -838,12 +836,9 @@ void FullCodeGenerator::VisitFunctionDeclaration(
VisitForAccumulatorValue(declaration->fun());
__ mov(ContextOperand(esi, variable->index()), result_register());
// We know that we have written a function, which is not a smi.
__ RecordWriteContextSlot(esi,
Context::SlotOffset(variable->index()),
result_register(),
ecx,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ RecordWriteContextSlot(esi, Context::SlotOffset(variable->index()),
result_register(), ecx, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
break;
}
......@@ -877,11 +872,8 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
// Assign it.
__ mov(ContextOperand(esi, variable->index()), eax);
// We know that we have written a module, which is not a smi.
__ RecordWriteContextSlot(esi,
Context::SlotOffset(variable->index()),
eax,
ecx,
EMIT_REMEMBERED_SET,
__ RecordWriteContextSlot(esi, Context::SlotOffset(variable->index()), eax,
ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
......@@ -1783,9 +1775,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
// Store the subexpression value in the array's elements.
__ mov(FieldOperand(ebx, offset), result_register());
// Update the write barrier for the array store.
__ RecordWriteField(ebx, offset, result_register(), ecx,
EMIT_REMEMBERED_SET,
INLINE_SMI_CHECK);
__ RecordWriteField(ebx, offset, result_register(), ecx, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, INLINE_SMI_CHECK);
} else {
// Store the subexpression value in the array's elements.
__ mov(ecx, Immediate(Smi::FromInt(i)));
......@@ -1942,7 +1933,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
Immediate(Smi::FromInt(continuation.pos())));
__ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
__ mov(ecx, esi);
__ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx);
__ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
kDontSaveFPRegs);
__ lea(ebx, Operand(ebp, StandardFrameConstants::kExpressionsOffset));
__ cmp(esp, ebx);
__ j(equal, &post_runtime);
......@@ -2016,7 +2008,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
Immediate(Smi::FromInt(l_continuation.pos())));
__ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
__ mov(ecx, esi);
__ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx);
__ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
kDontSaveFPRegs);
__ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
__ mov(context_register(),
Operand(ebp, StandardFrameConstants::kContextOffset));
......@@ -2224,8 +2217,8 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
// Only the value field needs a write barrier, as the other values are in the
// root set.
__ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset,
ecx, edx);
__ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset, ecx,
edx, kDontSaveFPRegs);
}
......@@ -2433,7 +2426,7 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
if (var->IsContextSlot()) {
__ mov(edx, eax);
int offset = Context::SlotOffset(var->index());
__ RecordWriteContextSlot(ecx, offset, edx, ebx);
__ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
}
}
......@@ -3532,7 +3525,7 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
// Update the write barrier. Save the value as it will be
// overwritten by the write barrier code and is needed afterward.
__ mov(edx, eax);
__ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx);
__ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);
__ bind(&done);
context()->Plug(eax);
......
This diff is collapsed.
......@@ -5,6 +5,7 @@
#ifndef V8_X87_LITHIUM_CODEGEN_X87_H_
#define V8_X87_LITHIUM_CODEGEN_X87_H_
#include <map>
#include "src/x87/lithium-x87.h"
#include "src/base/logging.h"
......@@ -84,6 +85,8 @@ class LCodeGen: public LCodeGenBase {
X87OperandType operand = kX87DoubleOperand);
void X87Mov(Operand src, X87Register reg,
X87OperandType operand = kX87DoubleOperand);
void X87Mov(X87Register reg, X87Register src,
X87OperandType operand = kX87DoubleOperand);
void X87PrepareBinaryOp(
X87Register left, X87Register right, X87Register result);
......@@ -198,9 +201,8 @@ class LCodeGen: public LCodeGenBase {
LInstruction* instr,
SafepointMode safepoint_mode);
void CallRuntime(const Runtime::Function* fun,
int argc,
LInstruction* instr);
void CallRuntime(const Runtime::Function* fun, int argc, LInstruction* instr,
SaveFPRegsMode save_doubles = kDontSaveFPRegs);
void CallRuntime(Runtime::FunctionId id,
int argc,
......@@ -376,7 +378,7 @@ class LCodeGen: public LCodeGenBase {
int osr_pc_offset_;
bool frame_is_built_;
class X87Stack {
class X87Stack : public ZoneObject {
public:
explicit X87Stack(MacroAssembler* masm)
: stack_depth_(0), is_mutable_(true), masm_(masm) { }
......@@ -393,14 +395,23 @@ class LCodeGen: public LCodeGenBase {
}
return true;
}
X87Stack& operator=(const X87Stack& other) {
stack_depth_ = other.stack_depth_;
for (int i = 0; i < stack_depth_; i++) {
stack_[i] = other.stack_[i];
}
return *this;
}
bool Contains(X87Register reg);
void Fxch(X87Register reg, int other_slot = 0);
void Free(X87Register reg);
void PrepareToWrite(X87Register reg);
void CommitWrite(X87Register reg);
void FlushIfNecessary(LInstruction* instr, LCodeGen* cgen);
void LeavingBlock(int current_block_id, LGoto* goto_instr);
void LeavingBlock(int current_block_id, LGoto* goto_instr, LCodeGen* cgen);
int depth() const { return stack_depth_; }
int GetLayout();
int st(X87Register reg) { return st2idx(ArrayIndex(reg)); }
void pop() {
DCHECK(is_mutable_);
stack_depth_--;
......@@ -425,6 +436,9 @@ class LCodeGen: public LCodeGenBase {
MacroAssembler* masm_;
};
X87Stack x87_stack_;
// block_id -> X87Stack*;
typedef std::map<int, X87Stack*> X87StackMap;
X87StackMap x87_stack_map_;
// Builder that keeps track of safepoints in the code. The table
// itself is emitted at the end of the generated code.
......@@ -458,6 +472,7 @@ class LCodeGen: public LCodeGenBase {
friend class LDeferredCode;
friend class LEnvironment;
friend class SafepointGenerator;
friend class X87Stack;
DISALLOW_COPY_AND_ASSIGN(LCodeGen);
};
......
......@@ -317,10 +317,15 @@ void LGapResolver::EmitMove(int index) {
} else if (source->IsDoubleRegister()) {
// load from the register onto the stack, store in destination, which must
// be a double stack slot in the non-SSE2 case.
DCHECK(destination->IsDoubleStackSlot());
Operand dst = cgen_->ToOperand(destination);
X87Register src = cgen_->ToX87Register(source);
cgen_->X87Mov(dst, src);
if (destination->IsDoubleStackSlot()) {
Operand dst = cgen_->ToOperand(destination);
X87Register src = cgen_->ToX87Register(source);
cgen_->X87Mov(dst, src);
} else {
X87Register dst = cgen_->ToX87Register(destination);
X87Register src = cgen_->ToX87Register(source);
cgen_->X87Mov(dst, src);
}
} else if (source->IsDoubleStackSlot()) {
// load from the stack slot on top of the floating point stack, and then
// store in destination. If destination is a double register, then it
......
......@@ -484,6 +484,12 @@ LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
}
LUnallocated* LChunkBuilder::ToUnallocated(X87Register reg) {
return new (zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
X87Register::ToAllocationIndex(reg));
}
LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
return Use(value, ToUnallocated(fixed_register));
}
......@@ -616,6 +622,12 @@ LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
}
LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
X87Register reg) {
return Define(instr, ToUnallocated(reg));
}
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
int argument_index_accumulator = 0;
......@@ -872,6 +884,14 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
if (current->IsControlInstruction() &&
HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
successor != NULL) {
// Always insert a fpu register barrier here when branch is optimized to
// be a direct goto.
// TODO(weiliang): require a better solution.
if (!current->IsGoto()) {
LClobberDoubles* clobber = new (zone()) LClobberDoubles(isolate());
clobber->set_hydrogen_value(current);
chunk_->AddInstruction(clobber, current_block_);
}
instr = new(zone()) LGoto(successor);
} else {
instr = current->CompileToLithium(this);
......@@ -931,7 +951,8 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr);
}
if (instr->IsGoto() && LGoto::cast(instr)->jumps_to_join()) {
if (instr->IsGoto() &&
(LGoto::cast(instr)->jumps_to_join() || next_block_->is_osr_entry())) {
// TODO(olivf) Since phis of spilled values are joined as registers
// (not in the stack slot), we need to allow the goto gaps to keep one
// x87 register alive. To ensure all other values are still spilled, we
......@@ -979,7 +1000,9 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
type.IsJSArray() || type.IsHeapNumber() || type.IsString();
LOperand* temp = !easy_case && expected.NeedsMap() ? TempRegister() : NULL;
LInstruction* branch = new(zone()) LBranch(UseRegister(value), temp);
LInstruction* branch =
temp != NULL ? new (zone()) LBranch(UseRegister(value), temp)
: new (zone()) LBranch(UseRegisterAtStart(value), temp);
if (!easy_case &&
((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
!expected.IsGeneric())) {
......@@ -1182,16 +1205,16 @@ LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
// Crankshaft is turned off for nosse2.
UNREACHABLE();
return NULL;
LOperand* input = UseRegisterAtStart(instr->value());
LInstruction* result = DefineAsRegister(new (zone()) LMathRound(input));
return AssignEnvironment(result);
}
LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
LOperand* input = UseRegisterAtStart(instr->value());
LOperand* input = UseRegister(instr->value());
LMathFround* result = new (zone()) LMathFround(input);
return AssignEnvironment(DefineAsRegister(result));
return DefineSameAsFirst(result);
}
......@@ -1225,11 +1248,11 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
DCHECK(instr->representation().IsDouble());
DCHECK(instr->value()->representation().IsDouble());
LOperand* value = UseTempRegister(instr->value());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LOperand* value = UseRegisterAtStart(instr->value());
LOperand* temp1 = FixedTemp(ecx);
LOperand* temp2 = FixedTemp(edx);
LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
return DefineAsRegister(result);
return MarkAsCall(DefineSameAsFirst(result), instr);
}
......@@ -1242,8 +1265,7 @@ LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
LOperand* input = UseRegisterAtStart(instr->value());
LOperand* temp = TempRegister();
LMathPowHalf* result = new(zone()) LMathPowHalf(input, temp);
LMathPowHalf* result = new (zone()) LMathPowHalf(input);
return DefineSameAsFirst(result);
}
......@@ -1615,6 +1637,8 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
LOperand* left = NULL;
LOperand* right = NULL;
LOperand* scratch = TempRegister();
if (instr->representation().IsSmiOrInteger32()) {
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
......@@ -1627,15 +1651,19 @@ LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
left = UseRegisterAtStart(instr->left());
right = UseRegisterAtStart(instr->right());
}
LMathMinMax* minmax = new(zone()) LMathMinMax(left, right);
LMathMinMax* minmax = new (zone()) LMathMinMax(left, right, scratch);
return DefineSameAsFirst(minmax);
}
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
// Crankshaft is turned off for nosse2.
UNREACHABLE();
return NULL;
// Unlike ia32, we don't have a MathPowStub and directly call c function.
DCHECK(instr->representation().IsDouble());
DCHECK(instr->left()->representation().IsDouble());
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right());
LPower* result = new (zone()) LPower(left, right);
return MarkAsCall(DefineSameAsFirst(result), instr);
}
......@@ -1697,9 +1725,8 @@ LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
HCompareMinusZeroAndBranch* instr) {
LOperand* value = UseRegister(instr->value());
LOperand* scratch = TempRegister();
return new(zone()) LCompareMinusZeroAndBranch(value, scratch);
LOperand* value = UseRegisterAtStart(instr->value());
return new (zone()) LCompareMinusZeroAndBranch(value);
}
......@@ -2022,8 +2049,8 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
HValue* value = instr->value();
Representation input_rep = value->representation();
if (input_rep.IsDouble()) {
UNREACHABLE();
return NULL;
LOperand* reg = UseRegister(value);
return DefineFixed(new (zone()) LClampDToUint8(reg), eax);
} else if (input_rep.IsInteger32()) {
LOperand* reg = UseFixed(value, eax);
return DefineFixed(new(zone()) LClampIToUint8(reg), eax);
......
......@@ -413,6 +413,7 @@ class LGoto FINAL : public LTemplateInstruction<0, 0, 0> {
}
bool jumps_to_join() const { return block_->predecessors()->length() > 1; }
HBasicBlock* block() const { return block_; }
private:
HBasicBlock* block_;
......@@ -984,15 +985,11 @@ class LMathSqrt FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LMathPowHalf FINAL : public LTemplateInstruction<1, 1, 1> {
class LMathPowHalf FINAL : public LTemplateInstruction<1, 1, 0> {
public:
LMathPowHalf(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
explicit LMathPowHalf(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
};
......@@ -1025,15 +1022,11 @@ class LCmpHoleAndBranch FINAL : public LControlInstruction<1, 0> {
};
class LCompareMinusZeroAndBranch FINAL : public LControlInstruction<1, 1> {
class LCompareMinusZeroAndBranch FINAL : public LControlInstruction<1, 0> {
public:
LCompareMinusZeroAndBranch(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
explicit LCompareMinusZeroAndBranch(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch,
"cmp-minus-zero-and-branch")
......@@ -1508,15 +1501,17 @@ class LAddI FINAL : public LTemplateInstruction<1, 2, 0> {
};
class LMathMinMax FINAL : public LTemplateInstruction<1, 2, 0> {
class LMathMinMax FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LMathMinMax(LOperand* left, LOperand* right) {
LMathMinMax(LOperand* left, LOperand* right, LOperand* temp) {
inputs_[0] = left;
inputs_[1] = right;
temps_[0] = temp;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
......@@ -2037,11 +2032,12 @@ class LCallRuntime FINAL : public LTemplateInstruction<1, 1, 0> {
DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
return true;
return save_doubles() == kDontSaveFPRegs;
}
const Runtime::Function* function() const { return hydrogen()->function(); }
int arity() const { return hydrogen()->argument_count(); }
SaveFPRegsMode save_doubles() const { return hydrogen()->save_doubles(); }
};
......@@ -2881,6 +2877,8 @@ class LChunkBuilder FINAL : public LChunkBuilderBase {
LInstruction* DefineSameAsFirst(LTemplateResultInstruction<1>* instr);
LInstruction* DefineFixed(LTemplateResultInstruction<1>* instr,
Register reg);
LInstruction* DefineFixed(LTemplateResultInstruction<1>* instr,
X87Register reg);
LInstruction* DefineX87TOS(LTemplateResultInstruction<1>* instr);
// Assigns an environment to an instruction. An instruction which can
// deoptimize must have an environment.
......
......@@ -148,8 +148,7 @@ void MacroAssembler::InNewSpace(
void MacroAssembler::RememberedSetHelper(
Register object, // Only used for debug checks.
Register addr,
Register scratch,
Register addr, Register scratch, SaveFPRegsMode save_fp,
MacroAssembler::RememberedSetFinalAction and_then) {
Label done;
if (emit_debug_code()) {
......@@ -180,7 +179,7 @@ void MacroAssembler::RememberedSetHelper(
DCHECK(and_then == kFallThroughAtEnd);
j(equal, &done, Label::kNear);
}
StoreBufferOverflowStub store_buffer_overflow(isolate(), kDontSaveFPRegs);
StoreBufferOverflowStub store_buffer_overflow(isolate(), save_fp);
CallStub(&store_buffer_overflow);
if (and_then == kReturnAtEnd) {
ret(0);
......@@ -191,6 +190,31 @@ void MacroAssembler::RememberedSetHelper(
}
void MacroAssembler::ClampTOSToUint8(Register result_reg) {
Label done, conv_failure;
sub(esp, Immediate(kPointerSize));
fnclex();
fist_s(Operand(esp, 0));
pop(result_reg);
X87CheckIA();
j(equal, &conv_failure, Label::kNear);
test(result_reg, Immediate(0xFFFFFF00));
j(zero, &done, Label::kNear);
setcc(sign, result_reg);
sub(result_reg, Immediate(1));
and_(result_reg, Immediate(255));
jmp(&done, Label::kNear);
bind(&conv_failure);
fnclex();
fldz();
fld(1);
FCmp();
setcc(below, result_reg); // 1 if negative, 0 if positive.
dec_b(result_reg); // 0 if negative, 255 if positive.
bind(&done);
}
void MacroAssembler::ClampUint8(Register reg) {
Label done;
test(reg, Immediate(0xFFFFFF00));
......@@ -270,11 +294,8 @@ void MacroAssembler::LoadUint32NoSSE2(Register src) {
void MacroAssembler::RecordWriteArray(
Register object,
Register value,
Register index,
RememberedSetAction remembered_set_action,
SmiCheck smi_check,
Register object, Register value, Register index, SaveFPRegsMode save_fp,
RememberedSetAction remembered_set_action, SmiCheck smi_check,
PointersToHereCheck pointers_to_here_check_for_value) {
// First, check if a write barrier is even needed. The tests below
// catch stores of Smis.
......@@ -294,8 +315,8 @@ void MacroAssembler::RecordWriteArray(
lea(dst, Operand(object, index, times_half_pointer_size,
FixedArray::kHeaderSize - kHeapObjectTag));
RecordWrite(object, dst, value, remembered_set_action, OMIT_SMI_CHECK,
pointers_to_here_check_for_value);
RecordWrite(object, dst, value, save_fp, remembered_set_action,
OMIT_SMI_CHECK, pointers_to_here_check_for_value);
bind(&done);
......@@ -309,13 +330,9 @@ void MacroAssembler::RecordWriteArray(
void MacroAssembler::RecordWriteField(
Register object,
int offset,
Register value,
Register dst,
RememberedSetAction remembered_set_action,
SmiCheck smi_check,
PointersToHereCheck pointers_to_here_check_for_value) {
Register object, int offset, Register value, Register dst,
SaveFPRegsMode save_fp, RememberedSetAction remembered_set_action,
SmiCheck smi_check, PointersToHereCheck pointers_to_here_check_for_value) {
// First, check if a write barrier is even needed. The tests below
// catch stores of Smis.
Label done;
......@@ -338,8 +355,8 @@ void MacroAssembler::RecordWriteField(
bind(&ok);
}
RecordWrite(object, dst, value, remembered_set_action, OMIT_SMI_CHECK,
pointers_to_here_check_for_value);
RecordWrite(object, dst, value, save_fp, remembered_set_action,
OMIT_SMI_CHECK, pointers_to_here_check_for_value);
bind(&done);
......@@ -352,11 +369,9 @@ void MacroAssembler::RecordWriteField(
}
void MacroAssembler::RecordWriteForMap(
Register object,
Handle<Map> map,
Register scratch1,
Register scratch2) {
void MacroAssembler::RecordWriteForMap(Register object, Handle<Map> map,
Register scratch1, Register scratch2,
SaveFPRegsMode save_fp) {
Label done;
Register address = scratch1;
......@@ -393,7 +408,8 @@ void MacroAssembler::RecordWriteForMap(
&done,
Label::kNear);
RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET);
RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET,
save_fp);
CallStub(&stub);
bind(&done);
......@@ -413,11 +429,8 @@ void MacroAssembler::RecordWriteForMap(
void MacroAssembler::RecordWrite(
Register object,
Register address,
Register value,
RememberedSetAction remembered_set_action,
SmiCheck smi_check,
Register object, Register address, Register value, SaveFPRegsMode fp_mode,
RememberedSetAction remembered_set_action, SmiCheck smi_check,
PointersToHereCheck pointers_to_here_check_for_value) {
DCHECK(!object.is(value));
DCHECK(!object.is(address));
......@@ -461,8 +474,8 @@ void MacroAssembler::RecordWrite(
&done,
Label::kNear);
RecordWriteStub stub(isolate(), object, value, address,
remembered_set_action);
RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
fp_mode);
CallStub(&stub);
bind(&done);
......@@ -707,6 +720,53 @@ void MacroAssembler::FCmp() {
}
void MacroAssembler::FXamMinusZero() {
fxam();
push(eax);
fnstsw_ax();
and_(eax, Immediate(0x4700));
// For minus zero, C3 == 1 && C1 == 1.
cmp(eax, Immediate(0x4200));
pop(eax);
fstp(0);
}
void MacroAssembler::FXamSign() {
fxam();
push(eax);
fnstsw_ax();
// For negative value (including -0.0), C1 == 1.
and_(eax, Immediate(0x0200));
pop(eax);
fstp(0);
}
void MacroAssembler::X87CheckIA() {
push(eax);
fnstsw_ax();
// For #IA, IE == 1 && SF == 0.
and_(eax, Immediate(0x0041));
cmp(eax, Immediate(0x0001));
pop(eax);
}
// rc=00B, round to nearest.
// rc=01B, round down.
// rc=10B, round up.
// rc=11B, round toward zero.
void MacroAssembler::X87SetRC(int rc) {
sub(esp, Immediate(kPointerSize));
fnstcw(MemOperand(esp, 0));
and_(MemOperand(esp, 0), Immediate(0xF3FF));
or_(MemOperand(esp, 0), Immediate(rc));
fldcw(MemOperand(esp, 0));
add(esp, Immediate(kPointerSize));
}
void MacroAssembler::AssertNumber(Register object) {
if (emit_debug_code()) {
Label ok;
......@@ -844,8 +904,17 @@ void MacroAssembler::EnterExitFramePrologue() {
}
void MacroAssembler::EnterExitFrameEpilogue(int argc) {
sub(esp, Immediate(argc * kPointerSize));
void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
// Optionally save FPU state.
if (save_doubles) {
// Store FPU state to m108byte.
int space = 108 + argc * kPointerSize;
sub(esp, Immediate(space));
const int offset = -2 * kPointerSize; // entry fp + code object.
fnsave(MemOperand(ebp, offset - 108));
} else {
sub(esp, Immediate(argc * kPointerSize));
}
// Get the required frame alignment for the OS.
const int kFrameAlignment = base::OS::ActivationFrameAlignment();
......@@ -859,7 +928,7 @@ void MacroAssembler::EnterExitFrameEpilogue(int argc) {
}
void MacroAssembler::EnterExitFrame() {
void MacroAssembler::EnterExitFrame(bool save_doubles) {
EnterExitFramePrologue();
// Set up argc and argv in callee-saved registers.
......@@ -868,17 +937,23 @@ void MacroAssembler::EnterExitFrame() {
lea(esi, Operand(ebp, eax, times_4, offset));
// Reserve space for argc, argv and isolate.
EnterExitFrameEpilogue(3);
EnterExitFrameEpilogue(3, save_doubles);
}
void MacroAssembler::EnterApiExitFrame(int argc) {
EnterExitFramePrologue();
EnterExitFrameEpilogue(argc);
EnterExitFrameEpilogue(argc, false);
}
void MacroAssembler::LeaveExitFrame() {
void MacroAssembler::LeaveExitFrame(bool save_doubles) {
// Optionally restore FPU state.
if (save_doubles) {
const int offset = -2 * kPointerSize;
frstor(MemOperand(ebp, offset - 108));
}
// Get the return address from the stack and restore the frame pointer.
mov(ecx, Operand(ebp, 1 * kPointerSize));
mov(ebp, Operand(ebp, 0 * kPointerSize));
......@@ -1908,8 +1983,8 @@ void MacroAssembler::IndexFromHash(Register hash, Register index) {
}
void MacroAssembler::CallRuntime(const Runtime::Function* f,
int num_arguments) {
void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
SaveFPRegsMode save_doubles) {
// If the expected number of arguments of the runtime function is
// constant, we check that the actual number of arguments match the
// expectation.
......@@ -1921,7 +1996,7 @@ void MacroAssembler::CallRuntime(const Runtime::Function* f,
// smarter.
Move(eax, Immediate(num_arguments));
mov(ebx, Immediate(ExternalReference(f, isolate())));
CEntryStub ces(isolate(), 1);
CEntryStub ces(isolate(), 1, save_doubles);
CallStub(&ces);
}
......
......@@ -74,8 +74,8 @@ class MacroAssembler: public Assembler {
// at the address pointed to by the addr register. Only works if addr is not
// in new space.
void RememberedSetHelper(Register object, // Used for debug code.
Register addr,
Register scratch,
Register addr, Register scratch,
SaveFPRegsMode save_fp,
RememberedSetFinalAction and_then);
void CheckPageFlag(Register object,
......@@ -146,10 +146,8 @@ class MacroAssembler: public Assembler {
// The offset is the offset from the start of the object, not the offset from
// the tagged HeapObject pointer. For use with FieldOperand(reg, off).
void RecordWriteField(
Register object,
int offset,
Register value,
Register scratch,
Register object, int offset, Register value, Register scratch,
SaveFPRegsMode save_fp,
RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
SmiCheck smi_check = INLINE_SMI_CHECK,
PointersToHereCheck pointers_to_here_check_for_value =
......@@ -158,20 +156,14 @@ class MacroAssembler: public Assembler {
// As above, but the offset has the tag presubtracted. For use with
// Operand(reg, off).
void RecordWriteContextSlot(
Register context,
int offset,
Register value,
Register scratch,
Register context, int offset, Register value, Register scratch,
SaveFPRegsMode save_fp,
RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
SmiCheck smi_check = INLINE_SMI_CHECK,
PointersToHereCheck pointers_to_here_check_for_value =
kPointersToHereMaybeInteresting) {
RecordWriteField(context,
offset + kHeapObjectTag,
value,
scratch,
remembered_set_action,
smi_check,
RecordWriteField(context, offset + kHeapObjectTag, value, scratch, save_fp,
remembered_set_action, smi_check,
pointers_to_here_check_for_value);
}
......@@ -182,9 +174,7 @@ class MacroAssembler: public Assembler {
// filters out smis so it does not update the write barrier if the
// value is a smi.
void RecordWriteArray(
Register array,
Register value,
Register index,
Register array, Register value, Register index, SaveFPRegsMode save_fp,
RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
SmiCheck smi_check = INLINE_SMI_CHECK,
PointersToHereCheck pointers_to_here_check_for_value =
......@@ -196,9 +186,7 @@ class MacroAssembler: public Assembler {
// operation. RecordWrite filters out smis so it does not update the
// write barrier if the value is a smi.
void RecordWrite(
Register object,
Register address,
Register value,
Register object, Register address, Register value, SaveFPRegsMode save_fp,
RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
SmiCheck smi_check = INLINE_SMI_CHECK,
PointersToHereCheck pointers_to_here_check_for_value =
......@@ -207,11 +195,8 @@ class MacroAssembler: public Assembler {
// For page containing |object| mark the region covering the object's map
// dirty. |object| is the object being stored into, |map| is the Map object
// that was stored.
void RecordWriteForMap(
Register object,
Handle<Map> map,
Register scratch1,
Register scratch2);
void RecordWriteForMap(Register object, Handle<Map> map, Register scratch1,
Register scratch2, SaveFPRegsMode save_fp);
// ---------------------------------------------------------------------------
// Debugger Support
......@@ -226,14 +211,14 @@ class MacroAssembler: public Assembler {
// arguments in register eax and sets up the number of arguments in
// register edi and the pointer to the first argument in register
// esi.
void EnterExitFrame();
void EnterExitFrame(bool save_doubles);
void EnterApiExitFrame(int argc);
// Leave the current exit frame. Expects the return value in
// register eax:edx (untouched) and the pointer to the first
// argument in register esi.
void LeaveExitFrame();
void LeaveExitFrame(bool save_doubles);
// Leave the current exit frame. Expects the return value in
// register eax (untouched).
......@@ -435,8 +420,13 @@ class MacroAssembler: public Assembler {
// FCmp is similar to integer cmp, but requires unsigned
// jcc instructions (je, ja, jae, jb, jbe, je, and jz).
void FCmp();
void FXamMinusZero();
void FXamSign();
void X87CheckIA();
void X87SetRC(int rc);
void ClampUint8(Register reg);
void ClampTOSToUint8(Register result_reg);
void SlowTruncateToI(Register result_reg, Register input_reg,
int offset = HeapNumber::kValueOffset - kHeapObjectTag);
......@@ -717,14 +707,17 @@ class MacroAssembler: public Assembler {
void StubReturn(int argc);
// Call a runtime routine.
void CallRuntime(const Runtime::Function* f, int num_arguments);
// Convenience function: Same as above, but takes the fid instead.
void CallRuntime(Runtime::FunctionId id) {
void CallRuntime(const Runtime::Function* f, int num_arguments,
SaveFPRegsMode save_doubles = kDontSaveFPRegs);
void CallRuntimeSaveDoubles(Runtime::FunctionId id) {
const Runtime::Function* function = Runtime::FunctionForId(id);
CallRuntime(function, function->nargs);
CallRuntime(function, function->nargs, kSaveFPRegs);
}
void CallRuntime(Runtime::FunctionId id, int num_arguments) {
CallRuntime(Runtime::FunctionForId(id), num_arguments);
// Convenience function: Same as above, but takes the fid instead.
void CallRuntime(Runtime::FunctionId id, int num_arguments,
SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
CallRuntime(Runtime::FunctionForId(id), num_arguments, save_doubles);
}
// Convenience function: call an external reference.
......@@ -956,7 +949,7 @@ class MacroAssembler: public Assembler {
const CallWrapper& call_wrapper = NullCallWrapper());
void EnterExitFramePrologue();
void EnterExitFrameEpilogue(int argc);
void EnterExitFrameEpilogue(int argc, bool save_doubles);
void LeaveExitFrameEpilogue(bool restore_context);
......
......@@ -349,6 +349,7 @@ TEST(DisasmIa320) {
__ fprem1();
__ fincstp();
__ ftst();
__ fxam();
__ fxch(3);
__ fld_s(Operand(ebx, ecx, times_4, 10000));
__ fstp_s(Operand(ebx, ecx, times_4, 10000));
......@@ -378,6 +379,12 @@ TEST(DisasmIa320) {
__ fninit();
__ nop();
__ fldcw(Operand(ebx, ecx, times_4, 10000));
__ fnstcw(Operand(ebx, ecx, times_4, 10000));
__ fadd_d(Operand(ebx, ecx, times_4, 10000));
__ fnsave(Operand(ebx, ecx, times_4, 10000));
__ frstor(Operand(ebx, ecx, times_4, 10000));
// xchg.
{
__ xchg(eax, eax);
......
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