| Index: src/x87/lithium-codegen-x87.cc
|
| diff --git a/src/x87/lithium-codegen-x87.cc b/src/x87/lithium-codegen-x87.cc
|
| index ded2cd94ae6e08cd7865f075fe18b61e7e594ad3..63feb425b8467fcf0f53bcfddfcdaf046f598eed 100644
|
| --- a/src/x87/lithium-codegen-x87.cc
|
| +++ b/src/x87/lithium-codegen-x87.cc
|
| @@ -257,7 +257,8 @@ bool LCodeGen::GeneratePrologue() {
|
| __ RecordWriteContextSlot(esi,
|
| context_offset,
|
| eax,
|
| - ebx);
|
| + ebx,
|
| + kDontSaveFPRegs);
|
| } else if (FLAG_debug_code) {
|
| Label done;
|
| __ JumpIfInNewSpace(esi, eax, &done, Label::kNear);
|
| @@ -269,6 +270,8 @@ bool LCodeGen::GeneratePrologue() {
|
| Comment(";;; End allocate local context");
|
| }
|
|
|
| + // Initailize FPU state.
|
| + __ fninit();
|
| // Trace the call.
|
| if (FLAG_trace && info()->IsOptimizing()) {
|
| // We have not executed any compiled code yet, so esi still holds the
|
| @@ -327,6 +330,9 @@ void LCodeGen::GenerateOsrPrologue() {
|
| int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
|
| DCHECK(slots >= 1);
|
| __ sub(esp, Immediate((slots - 1) * kPointerSize));
|
| +
|
| + // Initailize FPU state.
|
| + __ fninit();
|
| }
|
|
|
|
|
| @@ -342,8 +348,21 @@ void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
|
|
|
|
|
| void LCodeGen::GenerateBodyInstructionPost(LInstruction* instr) {
|
| + // When return from function call, FPU should be initialized again.
|
| + if (instr->IsCall() && instr->ClobbersDoubleRegisters(isolate())) {
|
| + bool double_result = instr->HasDoubleRegisterResult();
|
| + if (double_result) {
|
| + __ lea(esp, Operand(esp, -kDoubleSize));
|
| + __ fstp_d(Operand(esp, 0));
|
| + }
|
| + __ fninit();
|
| + if (double_result) {
|
| + __ fld_d(Operand(esp, 0));
|
| + __ lea(esp, Operand(esp, kDoubleSize));
|
| + }
|
| + }
|
| if (instr->IsGoto()) {
|
| - x87_stack_.LeavingBlock(current_block_, LGoto::cast(instr));
|
| + x87_stack_.LeavingBlock(current_block_, LGoto::cast(instr), this);
|
| } else if (FLAG_debug_code && FLAG_enable_slow_asserts &&
|
| !instr->IsGap() && !instr->IsReturn()) {
|
| if (instr->ClobbersDoubleRegisters(isolate())) {
|
| @@ -494,10 +513,27 @@ void LCodeGen::X87LoadForUsage(X87Register reg) {
|
| void LCodeGen::X87LoadForUsage(X87Register reg1, X87Register reg2) {
|
| DCHECK(x87_stack_.Contains(reg1));
|
| DCHECK(x87_stack_.Contains(reg2));
|
| - x87_stack_.Fxch(reg1, 1);
|
| - x87_stack_.Fxch(reg2);
|
| - x87_stack_.pop();
|
| - x87_stack_.pop();
|
| + if (reg1.is(reg2) && x87_stack_.depth() == 1) {
|
| + __ fld(x87_stack_.st(reg1));
|
| + x87_stack_.push(reg1);
|
| + x87_stack_.pop();
|
| + x87_stack_.pop();
|
| + } else {
|
| + x87_stack_.Fxch(reg1, 1);
|
| + x87_stack_.Fxch(reg2);
|
| + x87_stack_.pop();
|
| + x87_stack_.pop();
|
| + }
|
| +}
|
| +
|
| +
|
| +int LCodeGen::X87Stack::GetLayout() {
|
| + int layout = stack_depth_;
|
| + for (int i = 0; i < stack_depth_; i++) {
|
| + layout |= (stack_[stack_depth_ - 1 - i].code() << ((i + 1) * 3));
|
| + }
|
| +
|
| + return layout;
|
| }
|
|
|
|
|
| @@ -572,6 +608,22 @@ void LCodeGen::X87Mov(X87Register dst, Operand src, X87OperandType opts) {
|
| }
|
|
|
|
|
| +void LCodeGen::X87Mov(X87Register dst, X87Register src, X87OperandType opts) {
|
| + if (x87_stack_.Contains(dst)) {
|
| + x87_stack_.Fxch(dst);
|
| + __ fstp(0);
|
| + x87_stack_.pop();
|
| + // Push ST(i) onto the FPU register stack
|
| + __ fld(x87_stack_.st(src));
|
| + x87_stack_.push(dst);
|
| + } else {
|
| + // Push ST(i) onto the FPU register stack
|
| + __ fld(x87_stack_.st(src));
|
| + x87_stack_.push(dst);
|
| + }
|
| +}
|
| +
|
| +
|
| void LCodeGen::X87Fld(Operand src, X87OperandType opts) {
|
| DCHECK(!src.is_reg_only());
|
| switch (opts) {
|
| @@ -597,6 +649,9 @@ void LCodeGen::X87Mov(Operand dst, X87Register src, X87OperandType opts) {
|
| case kX87DoubleOperand:
|
| __ fst_d(dst);
|
| break;
|
| + case kX87FloatOperand:
|
| + __ fst_s(dst);
|
| + break;
|
| case kX87IntOperand:
|
| __ fist_s(dst);
|
| break;
|
| @@ -660,15 +715,39 @@ void LCodeGen::X87Stack::FlushIfNecessary(LInstruction* instr, LCodeGen* cgen) {
|
| }
|
|
|
|
|
| -void LCodeGen::X87Stack::LeavingBlock(int current_block_id, LGoto* goto_instr) {
|
| - DCHECK(stack_depth_ <= 1);
|
| - // If ever used for new stubs producing two pairs of doubles joined into two
|
| - // phis this assert hits. That situation is not handled, since the two stacks
|
| - // might have st0 and st1 swapped.
|
| - if (current_block_id + 1 != goto_instr->block_id()) {
|
| +void LCodeGen::X87Stack::LeavingBlock(int current_block_id,
|
| + LGoto* goto_instr,
|
| + LCodeGen* cgen) {
|
| + // For going to a joined block, an explicit LClobberDoubles is inserted before
|
| + // LGoto. Because all used x87 registers are spilled to stack slots. The
|
| + // ResolvePhis phase of register allocator could guarantee the two input's x87
|
| + // stacks have the same layout. So don't check stack_depth_ <= 1 here.
|
| + int goto_block_id = goto_instr->block_id();
|
| + if (current_block_id + 1 != goto_block_id) {
|
| // If we have a value on the x87 stack on leaving a block, it must be a
|
| // phi input. If the next block we compile is not the join block, we have
|
| // to discard the stack state.
|
| + // Before discarding the stack state, we need to save it if the "goto block"
|
| + // has unreachable last predecessor when FLAG_unreachable_code_elimination.
|
| + if (FLAG_unreachable_code_elimination) {
|
| + int length = goto_instr->block()->predecessors()->length();
|
| + bool has_unreachable_last_predecessor = false;
|
| + for (int i = 0; i < length; i ++) {
|
| + HBasicBlock* block = goto_instr->block()->predecessors()->at(i);
|
| + if (block->IsUnreachable() && (block->block_id()+ 1) == goto_block_id) {
|
| + has_unreachable_last_predecessor = true;
|
| + }
|
| + }
|
| + if (has_unreachable_last_predecessor) {
|
| + if (cgen->x87_stack_map_.find(goto_block_id) ==
|
| + cgen->x87_stack_map_.end()) {
|
| + X87Stack* stack = new(cgen->zone()) X87Stack(*this);
|
| + cgen->x87_stack_map_.insert(std::make_pair(goto_block_id, stack));
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Discard the stack state.
|
| stack_depth_ = 0;
|
| }
|
| }
|
| @@ -678,13 +757,14 @@ void LCodeGen::EmitFlushX87ForDeopt() {
|
| // The deoptimizer does not support X87 Registers. But as long as we
|
| // deopt from a stub its not a problem, since we will re-materialize the
|
| // original stub inputs, which can't be double registers.
|
| - DCHECK(info()->IsStub());
|
| + // DCHECK(info()->IsStub());
|
| if (FLAG_debug_code && FLAG_enable_slow_asserts) {
|
| __ pushfd();
|
| __ VerifyX87StackDepth(x87_stack_.depth());
|
| __ popfd();
|
| }
|
| - for (int i = 0; i < x87_stack_.depth(); i++) __ fstp(0);
|
| +
|
| + // Flush X87 stack in the deoptimizer entry.
|
| }
|
|
|
|
|
| @@ -891,6 +971,9 @@ void LCodeGen::AddToTranslation(LEnvironment* environment,
|
| } else {
|
| translation->StoreInt32Register(reg);
|
| }
|
| + } else if (op->IsDoubleRegister()) {
|
| + X87Register reg = ToX87Register(op);
|
| + translation->StoreDoubleRegister(reg);
|
| } else if (op->IsConstantOperand()) {
|
| HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
|
| int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
|
| @@ -927,11 +1010,12 @@ void LCodeGen::CallCode(Handle<Code> code,
|
|
|
| void LCodeGen::CallRuntime(const Runtime::Function* fun,
|
| int argc,
|
| - LInstruction* instr) {
|
| + LInstruction* instr,
|
| + SaveFPRegsMode save_doubles) {
|
| DCHECK(instr != NULL);
|
| DCHECK(instr->HasPointerMap());
|
|
|
| - __ CallRuntime(fun, argc);
|
| + __ CallRuntime(fun, argc, save_doubles);
|
|
|
| RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
|
|
|
| @@ -961,7 +1045,7 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
|
| LOperand* context) {
|
| LoadContextFromDeferred(context);
|
|
|
| - __ CallRuntime(id);
|
| + __ CallRuntimeSaveDoubles(id);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
|
|
|
| @@ -1035,6 +1119,12 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
|
| __ pop(eax);
|
| __ popfd();
|
| DCHECK(frame_is_built_);
|
| + // Put the x87 stack layout in TOS.
|
| + if (x87_stack_.depth() > 0) EmitFlushX87ForDeopt();
|
| + __ push(Immediate(x87_stack_.GetLayout()));
|
| + __ fild_s(MemOperand(esp, 0));
|
| + // Don't touch eflags.
|
| + __ lea(esp, Operand(esp, kPointerSize));
|
| __ call(entry, RelocInfo::RUNTIME_ENTRY);
|
| __ bind(&no_deopt);
|
| __ mov(Operand::StaticVariable(count), eax);
|
| @@ -1042,14 +1132,18 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
|
| __ popfd();
|
| }
|
|
|
| - // Before Instructions which can deopt, we normally flush the x87 stack. But
|
| - // we can have inputs or outputs of the current instruction on the stack,
|
| - // thus we need to flush them here from the physical stack to leave it in a
|
| - // consistent state.
|
| - if (x87_stack_.depth() > 0) {
|
| + // Put the x87 stack layout in TOS, so that we can save x87 fp registers in
|
| + // the correct location.
|
| + {
|
| Label done;
|
| if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear);
|
| - EmitFlushX87ForDeopt();
|
| + if (x87_stack_.depth() > 0) EmitFlushX87ForDeopt();
|
| +
|
| + int x87_stack_layout = x87_stack_.GetLayout();
|
| + __ push(Immediate(x87_stack_layout));
|
| + __ fild_s(MemOperand(esp, 0));
|
| + // Don't touch eflags.
|
| + __ lea(esp, Operand(esp, kPointerSize));
|
| __ bind(&done);
|
| }
|
|
|
| @@ -1236,6 +1330,16 @@ void LCodeGen::DoLabel(LLabel* label) {
|
| LabelType(label));
|
| __ bind(label->label());
|
| current_block_ = label->block_id();
|
| + if (label->block()->predecessors()->length() > 1) {
|
| + // A join block's x87 stack is that of its last visited predecessor.
|
| + // If the last visited predecessor block is unreachable, the stack state
|
| + // will be wrong. In such case, use the x87 stack of reachable predecessor.
|
| + X87StackMap::const_iterator it = x87_stack_map_.find(current_block_);
|
| + // Restore x87 stack.
|
| + if (it != x87_stack_map_.end()) {
|
| + x87_stack_ = *(it->second);
|
| + }
|
| + }
|
| DoGap(label);
|
| }
|
|
|
| @@ -1737,7 +1841,7 @@ void LCodeGen::DoMulI(LMulI* instr) {
|
| // Bail out if the result is supposed to be negative zero.
|
| Label done;
|
| __ test(left, Operand(left));
|
| - __ j(not_zero, &done, Label::kNear);
|
| + __ j(not_zero, &done);
|
| if (right->IsConstantOperand()) {
|
| if (ToInteger32(LConstantOperand::cast(right)) < 0) {
|
| DeoptimizeIf(no_condition, instr);
|
| @@ -2118,8 +2222,58 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
|
| }
|
| __ bind(&return_left);
|
| } else {
|
| - // TODO(weiliang) use X87 for double representation.
|
| - UNIMPLEMENTED();
|
| + DCHECK(instr->hydrogen()->representation().IsDouble());
|
| + Label check_nan_left, check_zero, return_left, return_right;
|
| + Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
|
| + X87Register left_reg = ToX87Register(left);
|
| + X87Register right_reg = ToX87Register(right);
|
| +
|
| + X87PrepareBinaryOp(left_reg, right_reg, ToX87Register(instr->result()));
|
| + __ fld(1);
|
| + __ fld(1);
|
| + __ FCmp();
|
| + __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
|
| + __ j(equal, &check_zero, Label::kNear); // left == right.
|
| + __ j(condition, &return_left, Label::kNear);
|
| + __ jmp(&return_right, Label::kNear);
|
| +
|
| + __ bind(&check_zero);
|
| + __ fld(0);
|
| + __ fldz();
|
| + __ FCmp();
|
| + __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
|
| + // At this point, both left and right are either 0 or -0.
|
| + if (operation == HMathMinMax::kMathMin) {
|
| + // Push st0 and st1 to stack, then pop them to temp registers and OR them,
|
| + // load it to left.
|
| + Register scratch_reg = ToRegister(instr->temp());
|
| + __ fld(1);
|
| + __ fld(1);
|
| + __ sub(esp, Immediate(2*kPointerSize));
|
| + __ fstp_s(MemOperand(esp, 0));
|
| + __ fstp_s(MemOperand(esp, kPointerSize));
|
| + __ pop(scratch_reg);
|
| + __ xor_(MemOperand(esp, 0), scratch_reg);
|
| + X87Mov(left_reg, MemOperand(esp, 0), kX87FloatOperand);
|
| + __ pop(scratch_reg); // restore esp
|
| + } else {
|
| + // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
|
| + X87Fxch(left_reg);
|
| + __ fadd(1);
|
| + }
|
| + __ jmp(&return_left, Label::kNear);
|
| +
|
| + __ bind(&check_nan_left);
|
| + __ fld(0);
|
| + __ fld(0);
|
| + __ FCmp(); // NaN check.
|
| + __ j(parity_even, &return_left, Label::kNear); // left == NaN.
|
| +
|
| + __ bind(&return_right);
|
| + X87Fxch(left_reg);
|
| + X87Mov(left_reg, right_reg);
|
| +
|
| + __ bind(&return_left);
|
| }
|
| }
|
|
|
| @@ -2164,6 +2318,13 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
|
| UNREACHABLE();
|
| break;
|
| }
|
| +
|
| + // Only always explicitly storing to memory to force the round-down for double
|
| + // arithmetic.
|
| + __ lea(esp, Operand(esp, -kDoubleSize));
|
| + __ fstp_d(Operand(esp, 0));
|
| + __ fld_d(Operand(esp, 0));
|
| + __ lea(esp, Operand(esp, kDoubleSize));
|
| }
|
|
|
|
|
| @@ -2217,7 +2378,11 @@ void LCodeGen::DoBranch(LBranch* instr) {
|
| __ test(reg, Operand(reg));
|
| EmitBranch(instr, not_zero);
|
| } else if (r.IsDouble()) {
|
| - UNREACHABLE();
|
| + X87Register reg = ToX87Register(instr->value());
|
| + X87LoadForUsage(reg);
|
| + __ fldz();
|
| + __ FCmp();
|
| + EmitBranch(instr, not_zero);
|
| } else {
|
| DCHECK(r.IsTagged());
|
| Register reg = ToRegister(instr->value());
|
| @@ -2473,7 +2638,10 @@ void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
|
| DCHECK(!rep.IsInteger32());
|
|
|
| if (rep.IsDouble()) {
|
| - UNREACHABLE();
|
| + X87Register input = ToX87Register(instr->value());
|
| + X87LoadForUsage(input);
|
| + __ FXamMinusZero();
|
| + EmitBranch(instr, equal);
|
| } else {
|
| Register value = ToRegister(instr->value());
|
| Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
|
| @@ -3062,6 +3230,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
| offset,
|
| value,
|
| temp,
|
| + kSaveFPRegs,
|
| EMIT_REMEMBERED_SET,
|
| check_needed);
|
| }
|
| @@ -3732,7 +3901,9 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) {
|
| Representation r = instr->hydrogen()->value()->representation();
|
|
|
| if (r.IsDouble()) {
|
| - UNIMPLEMENTED();
|
| + X87Register value = ToX87Register(instr->value());
|
| + X87Fxch(value);
|
| + __ fabs();
|
| } else if (r.IsSmiOrInteger32()) {
|
| EmitIntegerMathAbs(instr);
|
| } else { // Tagged case.
|
| @@ -3748,47 +3919,351 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) {
|
|
|
|
|
| void LCodeGen::DoMathFloor(LMathFloor* instr) {
|
| - UNIMPLEMENTED();
|
| + Register output_reg = ToRegister(instr->result());
|
| + X87Register input_reg = ToX87Register(instr->value());
|
| + X87Fxch(input_reg);
|
| +
|
| + Label not_minus_zero, done;
|
| + // Deoptimize on unordered.
|
| + __ fldz();
|
| + __ fld(1);
|
| + __ FCmp();
|
| + DeoptimizeIf(parity_even, instr);
|
| + __ j(below, ¬_minus_zero, Label::kNear);
|
| +
|
| + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + // Check for negative zero.
|
| + __ j(not_equal, ¬_minus_zero, Label::kNear);
|
| + // +- 0.0.
|
| + __ fld(0);
|
| + __ FXamSign();
|
| + DeoptimizeIf(not_zero, instr);
|
| + __ Move(output_reg, Immediate(0));
|
| + __ jmp(&done, Label::kFar);
|
| + }
|
| +
|
| + // Positive input.
|
| + // rc=01B, round down.
|
| + __ bind(¬_minus_zero);
|
| + __ fnclex();
|
| + __ X87SetRC(0x0400);
|
| + __ sub(esp, Immediate(kPointerSize));
|
| + __ fist_s(Operand(esp, 0));
|
| + __ pop(output_reg);
|
| + __ X87CheckIA();
|
| + DeoptimizeIf(equal, instr);
|
| + __ fnclex();
|
| + __ X87SetRC(0x0000);
|
| + __ bind(&done);
|
| }
|
|
|
|
|
| void LCodeGen::DoMathRound(LMathRound* instr) {
|
| - UNIMPLEMENTED();
|
| + X87Register input_reg = ToX87Register(instr->value());
|
| + Register result = ToRegister(instr->result());
|
| + X87Fxch(input_reg);
|
| + Label below_one_half, below_minus_one_half, done;
|
| +
|
| + ExternalReference one_half = ExternalReference::address_of_one_half();
|
| + ExternalReference minus_one_half =
|
| + ExternalReference::address_of_minus_one_half();
|
| +
|
| + __ fld_d(Operand::StaticVariable(one_half));
|
| + __ fld(1);
|
| + __ FCmp();
|
| + __ j(carry, &below_one_half);
|
| +
|
| + // Use rounds towards zero, since 0.5 <= x, we use floor(0.5 + x)
|
| + __ fld(0);
|
| + __ fadd_d(Operand::StaticVariable(one_half));
|
| + // rc=11B, round toward zero.
|
| + __ X87SetRC(0x0c00);
|
| + __ sub(esp, Immediate(kPointerSize));
|
| + // Clear exception bits.
|
| + __ fnclex();
|
| + __ fistp_s(MemOperand(esp, 0));
|
| + // Check overflow.
|
| + __ X87CheckIA();
|
| + __ RecordComment("D2I conversion overflow");
|
| + __ pop(result);
|
| + DeoptimizeIf(equal, instr);
|
| + __ fnclex();
|
| + // Restore round mode.
|
| + __ X87SetRC(0x0000);
|
| + __ jmp(&done);
|
| +
|
| + __ bind(&below_one_half);
|
| + __ fld_d(Operand::StaticVariable(minus_one_half));
|
| + __ fld(1);
|
| + __ FCmp();
|
| + __ j(carry, &below_minus_one_half);
|
| + // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
|
| + // we can ignore the difference between a result of -0 and +0.
|
| + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + // If the sign is positive, we return +0.
|
| + __ fld(0);
|
| + __ FXamSign();
|
| + __ RecordComment("Minus zero");
|
| + DeoptimizeIf(not_zero, instr);
|
| + }
|
| + __ Move(result, Immediate(0));
|
| + __ jmp(&done);
|
| +
|
| + __ bind(&below_minus_one_half);
|
| + __ fld(0);
|
| + __ fadd_d(Operand::StaticVariable(one_half));
|
| + // rc=01B, round down.
|
| + __ X87SetRC(0x0400);
|
| + __ sub(esp, Immediate(kPointerSize));
|
| + // Clear exception bits.
|
| + __ fnclex();
|
| + __ fistp_s(MemOperand(esp, 0));
|
| + // Check overflow.
|
| + __ X87CheckIA();
|
| + __ RecordComment("D2I conversion overflow");
|
| + __ pop(result);
|
| + DeoptimizeIf(equal, instr);
|
| + __ fnclex();
|
| + // Restore round mode.
|
| + __ X87SetRC(0x0000);
|
| +
|
| + __ bind(&done);
|
| }
|
|
|
|
|
| void LCodeGen::DoMathFround(LMathFround* instr) {
|
| - UNIMPLEMENTED();
|
| + X87Register input_reg = ToX87Register(instr->value());
|
| + X87Fxch(input_reg);
|
| + __ sub(esp, Immediate(kPointerSize));
|
| + __ fstp_s(MemOperand(esp, 0));
|
| + X87Fld(MemOperand(esp, 0), kX87FloatOperand);
|
| + __ add(esp, Immediate(kPointerSize));
|
| }
|
|
|
|
|
| void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
|
| - UNIMPLEMENTED();
|
| + X87Register input_reg = ToX87Register(instr->value());
|
| + X87Register output_reg = ToX87Register(instr->result());
|
| + DCHECK(output_reg.is(input_reg));
|
| + USE(output_reg);
|
| + X87Fxch(input_reg);
|
| + __ fsqrt();
|
| }
|
|
|
|
|
| void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
|
| - UNIMPLEMENTED();
|
| + X87Register input_reg = ToX87Register(instr->value());
|
| + DCHECK(ToX87Register(instr->result()).is(input_reg));
|
| + X87Fxch(input_reg);
|
| + // Note that according to ECMA-262 15.8.2.13:
|
| + // Math.pow(-Infinity, 0.5) == Infinity
|
| + // Math.sqrt(-Infinity) == NaN
|
| + Label done, sqrt;
|
| + // Check base for -Infinity. C3 == 0, C2 == 1, C1 == 1 and C0 == 1
|
| + __ fxam();
|
| + __ push(eax);
|
| + __ fnstsw_ax();
|
| + __ and_(eax, Immediate(0x4700));
|
| + __ cmp(eax, Immediate(0x0700));
|
| + __ j(not_equal, &sqrt, Label::kNear);
|
| + // If input is -Infinity, return Infinity.
|
| + __ fchs();
|
| + __ jmp(&done, Label::kNear);
|
| +
|
| + // Square root.
|
| + __ bind(&sqrt);
|
| + __ fldz();
|
| + __ faddp(); // Convert -0 to +0.
|
| + __ fsqrt();
|
| + __ bind(&done);
|
| + __ pop(eax);
|
| }
|
|
|
|
|
| void LCodeGen::DoPower(LPower* instr) {
|
| - UNIMPLEMENTED();
|
| + Representation exponent_type = instr->hydrogen()->right()->representation();
|
| + X87Register result = ToX87Register(instr->result());
|
| + // Having marked this as a call, we can use any registers.
|
| + X87Register base = ToX87Register(instr->left());
|
| + ExternalReference one_half = ExternalReference::address_of_one_half();
|
| +
|
| + if (exponent_type.IsSmi()) {
|
| + Register exponent = ToRegister(instr->right());
|
| + X87LoadForUsage(base);
|
| + __ SmiUntag(exponent);
|
| + __ push(exponent);
|
| + __ fild_s(MemOperand(esp, 0));
|
| + __ pop(exponent);
|
| + } else if (exponent_type.IsTagged()) {
|
| + Register exponent = ToRegister(instr->right());
|
| + Register temp = exponent.is(ecx) ? eax : ecx;
|
| + Label no_deopt, done;
|
| + X87LoadForUsage(base);
|
| + __ JumpIfSmi(exponent, &no_deopt);
|
| + __ CmpObjectType(exponent, HEAP_NUMBER_TYPE, temp);
|
| + DeoptimizeIf(not_equal, instr);
|
| + // Heap number(double)
|
| + __ fld_d(FieldOperand(exponent, HeapNumber::kValueOffset));
|
| + __ jmp(&done);
|
| + // SMI
|
| + __ bind(&no_deopt);
|
| + __ SmiUntag(exponent);
|
| + __ push(exponent);
|
| + __ fild_s(MemOperand(esp, 0));
|
| + __ pop(exponent);
|
| + __ bind(&done);
|
| + } else if (exponent_type.IsInteger32()) {
|
| + Register exponent = ToRegister(instr->right());
|
| + X87LoadForUsage(base);
|
| + __ push(exponent);
|
| + __ fild_s(MemOperand(esp, 0));
|
| + __ pop(exponent);
|
| + } else {
|
| + DCHECK(exponent_type.IsDouble());
|
| + X87Register exponent_double = ToX87Register(instr->right());
|
| + X87LoadForUsage(base, exponent_double);
|
| + }
|
| +
|
| + // FP data stack {base, exponent(TOS)}.
|
| + // Handle (exponent==+-0.5 && base == -0).
|
| + Label not_plus_0;
|
| + __ fld(0);
|
| + __ fabs();
|
| + X87Fld(Operand::StaticVariable(one_half), kX87DoubleOperand);
|
| + __ FCmp();
|
| + __ j(parity_even, ¬_plus_0, Label::kNear); // NaN.
|
| + __ j(not_equal, ¬_plus_0, Label::kNear);
|
| + __ fldz();
|
| + // FP data stack {base, exponent(TOS), zero}.
|
| + __ faddp(2);
|
| + __ bind(¬_plus_0);
|
| +
|
| + {
|
| + __ PrepareCallCFunction(4, eax);
|
| + __ fstp_d(MemOperand(esp, kDoubleSize)); // Exponent value.
|
| + __ fstp_d(MemOperand(esp, 0)); // Base value.
|
| + X87PrepareToWrite(result);
|
| + __ CallCFunction(
|
| + ExternalReference::power_double_double_function(isolate()), 4);
|
| + // Return value is in st(0) on ia32.
|
| + X87CommitWrite(result);
|
| + }
|
| }
|
|
|
|
|
| void LCodeGen::DoMathLog(LMathLog* instr) {
|
| - UNIMPLEMENTED();
|
| + DCHECK(instr->value()->Equals(instr->result()));
|
| + X87Register input_reg = ToX87Register(instr->value());
|
| + X87Fxch(input_reg);
|
| +
|
| + Label positive, done, zero, nan_result;
|
| + __ fldz();
|
| + __ fld(1);
|
| + __ FCmp();
|
| + __ j(below, &nan_result, Label::kNear);
|
| + __ j(equal, &zero, Label::kNear);
|
| + // Positive input.
|
| + // {input, ln2}.
|
| + __ fldln2();
|
| + // {ln2, input}.
|
| + __ fxch();
|
| + // {result}.
|
| + __ fyl2x();
|
| + __ jmp(&done, Label::kNear);
|
| +
|
| + __ bind(&nan_result);
|
| + ExternalReference nan =
|
| + ExternalReference::address_of_canonical_non_hole_nan();
|
| + X87PrepareToWrite(input_reg);
|
| + __ fld_d(Operand::StaticVariable(nan));
|
| + X87CommitWrite(input_reg);
|
| + __ jmp(&done, Label::kNear);
|
| +
|
| + __ bind(&zero);
|
| + ExternalReference ninf =
|
| + ExternalReference::address_of_negative_infinity();
|
| + X87PrepareToWrite(input_reg);
|
| + __ fld_d(Operand::StaticVariable(ninf));
|
| + X87CommitWrite(input_reg);
|
| +
|
| + __ bind(&done);
|
| }
|
|
|
|
|
| void LCodeGen::DoMathClz32(LMathClz32* instr) {
|
| - UNIMPLEMENTED();
|
| + Register input = ToRegister(instr->value());
|
| + Register result = ToRegister(instr->result());
|
| + Label not_zero_input;
|
| + __ bsr(result, input);
|
| +
|
| + __ j(not_zero, ¬_zero_input);
|
| + __ Move(result, Immediate(63)); // 63^31 == 32
|
| +
|
| + __ bind(¬_zero_input);
|
| + __ xor_(result, Immediate(31)); // for x in [0..31], 31^x == 31-x.
|
| }
|
|
|
|
|
| void LCodeGen::DoMathExp(LMathExp* instr) {
|
| - UNIMPLEMENTED();
|
| + X87Register input = ToX87Register(instr->value());
|
| + X87Register result_reg = ToX87Register(instr->result());
|
| + Register temp_result = ToRegister(instr->temp1());
|
| + Register temp = ToRegister(instr->temp2());
|
| + Label slow, done, smi, finish;
|
| + DCHECK(result_reg.is(input));
|
| +
|
| + // Store input into Heap number and call runtime function kMathExpRT.
|
| + if (FLAG_inline_new) {
|
| + __ AllocateHeapNumber(temp_result, temp, no_reg, &slow);
|
| + __ jmp(&done, Label::kNear);
|
| + }
|
| +
|
| + // Slow case: Call the runtime system to do the number allocation.
|
| + __ bind(&slow);
|
| + {
|
| + // TODO(3095996): Put a valid pointer value in the stack slot where the
|
| + // result register is stored, as this register is in the pointer map, but
|
| + // contains an integer value.
|
| + __ Move(temp_result, Immediate(0));
|
| +
|
| + // Preserve the value of all registers.
|
| + PushSafepointRegistersScope scope(this);
|
| +
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| + __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| + RecordSafepointWithRegisters(
|
| + instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
|
| + __ StoreToSafepointRegisterSlot(temp_result, eax);
|
| + }
|
| + __ bind(&done);
|
| + X87LoadForUsage(input);
|
| + __ fstp_d(FieldOperand(temp_result, HeapNumber::kValueOffset));
|
| +
|
| + {
|
| + // Preserve the value of all registers.
|
| + PushSafepointRegistersScope scope(this);
|
| +
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| + __ push(temp_result);
|
| + __ CallRuntimeSaveDoubles(Runtime::kMathExpRT);
|
| + RecordSafepointWithRegisters(
|
| + instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
|
| + __ StoreToSafepointRegisterSlot(temp_result, eax);
|
| + }
|
| + X87PrepareToWrite(result_reg);
|
| + // return value of MathExpRT is Smi or Heap Number.
|
| + __ JumpIfSmi(temp_result, &smi);
|
| + // Heap number(double)
|
| + __ fld_d(FieldOperand(temp_result, HeapNumber::kValueOffset));
|
| + __ jmp(&finish);
|
| + // SMI
|
| + __ bind(&smi);
|
| + __ SmiUntag(temp_result);
|
| + __ push(temp_result);
|
| + __ fild_s(MemOperand(esp, 0));
|
| + __ pop(temp_result);
|
| + __ bind(&finish);
|
| + X87CommitWrite(result_reg);
|
| }
|
|
|
|
|
| @@ -3885,7 +4360,7 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
|
|
|
| void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
|
| DCHECK(ToRegister(instr->context()).is(esi));
|
| - CallRuntime(instr->function(), instr->arity(), instr);
|
| + CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles());
|
| }
|
|
|
|
|
| @@ -3956,7 +4431,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
| __ mov(temp_map, transition);
|
| __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
|
| // Update the write barrier for the map field.
|
| - __ RecordWriteForMap(object, transition, temp_map, temp);
|
| + __ RecordWriteForMap(object, transition, temp_map, temp, kSaveFPRegs);
|
| }
|
| }
|
|
|
| @@ -3995,6 +4470,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
| offset,
|
| value,
|
| temp,
|
| + kSaveFPRegs,
|
| EMIT_REMEMBERED_SET,
|
| instr->hydrogen()->SmiCheckForWriteBarrier(),
|
| instr->hydrogen()->PointersToHereCheckForValue());
|
| @@ -4054,8 +4530,7 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
|
| instr->base_offset()));
|
| if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
|
| elements_kind == FLOAT32_ELEMENTS) {
|
| - __ fld(0);
|
| - __ fstp_s(operand);
|
| + X87Mov(operand, ToX87Register(instr->value()), kX87FloatOperand);
|
| } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
|
| elements_kind == FLOAT64_ELEMENTS) {
|
| X87Mov(operand, ToX87Register(instr->value()));
|
| @@ -4194,6 +4669,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
|
| __ RecordWrite(elements,
|
| key,
|
| value,
|
| + kSaveFPRegs,
|
| EMIT_REMEMBERED_SET,
|
| check_needed,
|
| instr->hydrogen()->PointersToHereCheckForValue());
|
| @@ -4257,7 +4733,8 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
|
| // Write barrier.
|
| DCHECK_NE(instr->temp(), NULL);
|
| __ RecordWriteForMap(object_reg, to_map, new_map_reg,
|
| - ToRegister(instr->temp()));
|
| + ToRegister(instr->temp()),
|
| + kDontSaveFPRegs);
|
| } else {
|
| DCHECK(ToRegister(instr->context()).is(esi));
|
| DCHECK(object_reg.is(eax));
|
| @@ -4527,7 +5004,7 @@ void LCodeGen::DoDeferredNumberTagIU(LInstruction* instr,
|
| // The corresponding HChange instructions are added in a phase that does
|
| // not have easy access to the local context.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| - __ CallRuntime(Runtime::kAllocateHeapNumber);
|
| + __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
|
| __ StoreToSafepointRegisterSlot(reg, eax);
|
| @@ -4557,7 +5034,9 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
|
|
|
| // Put the value to the top of stack
|
| X87Register src = ToX87Register(instr->value());
|
| - X87LoadForUsage(src);
|
| + // Don't use X87LoadForUsage here, which is only used by Instruction which
|
| + // clobbers fp registers.
|
| + x87_stack_.Fxch(src);
|
|
|
| DeferredNumberTagD* deferred =
|
| new(zone()) DeferredNumberTagD(this, instr, x87_stack_);
|
| @@ -4568,7 +5047,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
|
| __ jmp(deferred->entry());
|
| }
|
| __ bind(deferred->exit());
|
| - __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
|
| + __ fst_d(FieldOperand(reg, HeapNumber::kValueOffset));
|
| }
|
|
|
|
|
| @@ -4586,7 +5065,7 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
|
| // The corresponding HChange instructions are added in a phase that does
|
| // not have easy access to the local context.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| - __ CallRuntime(Runtime::kAllocateHeapNumber);
|
| + __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
|
| __ StoreToSafepointRegisterSlot(reg, eax);
|
| @@ -4635,7 +5114,7 @@ void LCodeGen::EmitNumberUntagDNoSSE2(LNumberUntagD* instr, Register input_reg,
|
| X87PrepareToWrite(res_reg);
|
| if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
|
| // Smi check.
|
| - __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
|
| + __ JumpIfSmi(input_reg, &load_smi);
|
|
|
| // Heap number map check.
|
| __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
|
| @@ -4644,7 +5123,7 @@ void LCodeGen::EmitNumberUntagDNoSSE2(LNumberUntagD* instr, Register input_reg,
|
| DeoptimizeIf(not_equal, instr);
|
| } else {
|
| Label heap_number, convert;
|
| - __ j(equal, &heap_number, Label::kNear);
|
| + __ j(equal, &heap_number);
|
|
|
| // Convert undefined (or hole) to NaN.
|
| __ cmp(input_reg, factory()->undefined_value());
|
| @@ -4973,7 +5452,7 @@ void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
|
| PushSafepointRegistersScope scope(this);
|
| __ push(object);
|
| __ xor_(esi, esi);
|
| - __ CallRuntime(Runtime::kTryMigrateInstance);
|
| + __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
|
|
|
| @@ -5043,7 +5522,10 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
|
|
|
|
|
| void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
|
| - UNREACHABLE();
|
| + X87Register value_reg = ToX87Register(instr->unclamped());
|
| + Register result_reg = ToRegister(instr->result());
|
| + X87Fxch(value_reg);
|
| + __ ClampTOSToUint8(result_reg);
|
| }
|
|
|
|
|
| @@ -5177,12 +5659,32 @@ void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) {
|
|
|
|
|
| void LCodeGen::DoDoubleBits(LDoubleBits* instr) {
|
| - UNREACHABLE();
|
| + X87Register value_reg = ToX87Register(instr->value());
|
| + Register result_reg = ToRegister(instr->result());
|
| + X87Fxch(value_reg);
|
| + __ sub(esp, Immediate(kDoubleSize));
|
| + __ fst_d(Operand(esp, 0));
|
| + if (instr->hydrogen()->bits() == HDoubleBits::HIGH) {
|
| + __ mov(result_reg, Operand(esp, kPointerSize));
|
| + } else {
|
| + __ mov(result_reg, Operand(esp, 0));
|
| + }
|
| + __ add(esp, Immediate(kDoubleSize));
|
| }
|
|
|
|
|
| void LCodeGen::DoConstructDouble(LConstructDouble* instr) {
|
| - UNREACHABLE();
|
| + Register hi_reg = ToRegister(instr->hi());
|
| + Register lo_reg = ToRegister(instr->lo());
|
| + X87Register result_reg = ToX87Register(instr->result());
|
| + // Follow below pattern to write a x87 fp register.
|
| + X87PrepareToWrite(result_reg);
|
| + __ sub(esp, Immediate(kDoubleSize));
|
| + __ mov(Operand(esp, 0), lo_reg);
|
| + __ mov(Operand(esp, kPointerSize), hi_reg);
|
| + __ fld_d(Operand(esp, 0));
|
| + __ add(esp, Immediate(kDoubleSize));
|
| + X87CommitWrite(result_reg);
|
| }
|
|
|
|
|
| @@ -5546,7 +6048,7 @@ void LCodeGen::DoDummyUse(LDummyUse* instr) {
|
| void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
|
| PushSafepointRegistersScope scope(this);
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| - __ CallRuntime(Runtime::kStackGuard);
|
| + __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
|
| RecordSafepointWithLazyDeopt(
|
| instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
|
| DCHECK(instr->HasEnvironment());
|
| @@ -5693,7 +6195,7 @@ void LCodeGen::DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr,
|
| __ push(object);
|
| __ push(index);
|
| __ xor_(esi, esi);
|
| - __ CallRuntime(Runtime::kLoadMutableDouble);
|
| + __ CallRuntimeSaveDoubles(Runtime::kLoadMutableDouble);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 2, Safepoint::kNoLazyDeopt);
|
| __ StoreToSafepointRegisterSlot(object, eax);
|
|
|