| Index: src/compiler/x87/code-generator-x87.cc
|
| diff --git a/src/compiler/ia32/code-generator-ia32.cc b/src/compiler/x87/code-generator-x87.cc
|
| similarity index 65%
|
| copy from src/compiler/ia32/code-generator-ia32.cc
|
| copy to src/compiler/x87/code-generator-x87.cc
|
| index 53b4ebe7cecff7819022b4335a017525559b6121..a1ce22fc012422283d88db751c4cd5040ccc7b99 100644
|
| --- a/src/compiler/ia32/code-generator-ia32.cc
|
| +++ b/src/compiler/x87/code-generator-x87.cc
|
| @@ -7,9 +7,9 @@
|
| #include "src/compiler/code-generator-impl.h"
|
| #include "src/compiler/gap-resolver.h"
|
| #include "src/compiler/node-matchers.h"
|
| -#include "src/ia32/assembler-ia32.h"
|
| -#include "src/ia32/macro-assembler-ia32.h"
|
| #include "src/scopes.h"
|
| +#include "src/x87/assembler-x87.h"
|
| +#include "src/x87/macro-assembler-x87.h"
|
|
|
| namespace v8 {
|
| namespace internal {
|
| @@ -18,13 +18,10 @@ namespace compiler {
|
| #define __ masm()->
|
|
|
|
|
| -#define kScratchDoubleReg xmm0
|
| -
|
| -
|
| -// Adds IA-32 specific methods for decoding operands.
|
| -class IA32OperandConverter : public InstructionOperandConverter {
|
| +// Adds X87 specific methods for decoding operands.
|
| +class X87OperandConverter : public InstructionOperandConverter {
|
| public:
|
| - IA32OperandConverter(CodeGenerator* gen, Instruction* instr)
|
| + X87OperandConverter(CodeGenerator* gen, Instruction* instr)
|
| : InstructionOperandConverter(gen, instr) {}
|
|
|
| Operand InputOperand(size_t index, int extra = 0) {
|
| @@ -43,7 +40,7 @@ class IA32OperandConverter : public InstructionOperandConverter {
|
| return Operand(ToRegister(op));
|
| } else if (op->IsDoubleRegister()) {
|
| DCHECK(extra == 0);
|
| - return Operand(ToDoubleRegister(op));
|
| + UNIMPLEMENTED();
|
| }
|
| DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
| // The linkage computes where all spill slots are located.
|
| @@ -187,32 +184,39 @@ class OutOfLineLoadInteger final : public OutOfLineCode {
|
|
|
| class OutOfLineLoadFloat final : public OutOfLineCode {
|
| public:
|
| - OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result)
|
| + OutOfLineLoadFloat(CodeGenerator* gen, X87Register result)
|
| : OutOfLineCode(gen), result_(result) {}
|
|
|
| - void Generate() final { __ pcmpeqd(result_, result_); }
|
| + void Generate() final {
|
| + DCHECK(result_.code() == 0);
|
| + USE(result_);
|
| + __ fstp(0);
|
| + __ push(Immediate(0xffffffff));
|
| + __ push(Immediate(0x7fffffff));
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ lea(esp, Operand(esp, kDoubleSize));
|
| + }
|
|
|
| private:
|
| - XMMRegister const result_;
|
| + X87Register const result_;
|
| };
|
|
|
|
|
| class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
|
| public:
|
| OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
|
| - XMMRegister input)
|
| + X87Register input)
|
| : OutOfLineCode(gen), result_(result), input_(input) {}
|
|
|
| void Generate() final {
|
| - __ sub(esp, Immediate(kDoubleSize));
|
| - __ movsd(MemOperand(esp, 0), input_);
|
| - __ SlowTruncateToI(result_, esp, 0);
|
| - __ add(esp, Immediate(kDoubleSize));
|
| + UNIMPLEMENTED();
|
| + USE(result_);
|
| + USE(input_);
|
| }
|
|
|
| private:
|
| Register const result_;
|
| - XMMRegister const input_;
|
| + X87Register const input_;
|
| };
|
|
|
| } // namespace
|
| @@ -222,6 +226,7 @@ class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
|
| do { \
|
| auto result = i.OutputDoubleRegister(); \
|
| auto offset = i.InputRegister(0); \
|
| + DCHECK(result.code() == 0); \
|
| if (instr->InputAt(1)->IsRegister()) { \
|
| __ cmp(offset, i.InputRegister(1)); \
|
| } else { \
|
| @@ -229,7 +234,8 @@ class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
|
| } \
|
| OutOfLineCode* ool = new (zone()) OutOfLineLoadFloat(this, result); \
|
| __ j(above_equal, ool->entry()); \
|
| - __ asm_instr(result, i.MemoryOperand(2)); \
|
| + __ fstp(0); \
|
| + __ asm_instr(i.MemoryOperand(2)); \
|
| __ bind(ool->exit()); \
|
| } while (false)
|
|
|
| @@ -250,18 +256,19 @@ class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
|
| } while (false)
|
|
|
|
|
| -#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \
|
| - do { \
|
| - auto offset = i.InputRegister(0); \
|
| - if (instr->InputAt(1)->IsRegister()) { \
|
| - __ cmp(offset, i.InputRegister(1)); \
|
| - } else { \
|
| - __ cmp(offset, i.InputImmediate(1)); \
|
| - } \
|
| - Label done; \
|
| - __ j(above_equal, &done, Label::kNear); \
|
| - __ asm_instr(i.MemoryOperand(3), i.InputDoubleRegister(2)); \
|
| - __ bind(&done); \
|
| +#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \
|
| + do { \
|
| + auto offset = i.InputRegister(0); \
|
| + if (instr->InputAt(1)->IsRegister()) { \
|
| + __ cmp(offset, i.InputRegister(1)); \
|
| + } else { \
|
| + __ cmp(offset, i.InputImmediate(1)); \
|
| + } \
|
| + Label done; \
|
| + DCHECK(i.InputDoubleRegister(2).code() == 0); \
|
| + __ j(above_equal, &done, Label::kNear); \
|
| + __ asm_instr(i.MemoryOperand(3)); \
|
| + __ bind(&done); \
|
| } while (false)
|
|
|
|
|
| @@ -303,7 +310,7 @@ void CodeGenerator::AssembleDeconstructActivationRecord() {
|
|
|
| // Assembles an instruction after register allocation, producing machine code.
|
| void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
| - IA32OperandConverter i(this, instr);
|
| + X87OperandConverter i(this, instr);
|
|
|
| switch (ArchOpcodeField::decode(instr->opcode())) {
|
| case kArchCallCodeObject: {
|
| @@ -316,6 +323,19 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
| __ call(Operand(reg, Code::kHeaderSize - kHeapObjectTag));
|
| }
|
| RecordCallPosition(instr);
|
| + bool double_result =
|
| + instr->HasOutput() && instr->Output()->IsDoubleRegister();
|
| + 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));
|
| + } else {
|
| + __ fld1();
|
| + }
|
| break;
|
| }
|
| case kArchTailCallCodeObject: {
|
| @@ -339,6 +359,19 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
| }
|
| __ call(FieldOperand(func, JSFunction::kCodeEntryOffset));
|
| RecordCallPosition(instr);
|
| + bool double_result =
|
| + instr->HasOutput() && instr->Output()->IsDoubleRegister();
|
| + 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));
|
| + } else {
|
| + __ fld1();
|
| + }
|
| break;
|
| }
|
| case kArchTailCallJSFunction: {
|
| @@ -373,405 +406,621 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
| case kArchRet:
|
| AssembleReturn();
|
| break;
|
| - case kArchStackPointer:
|
| - __ mov(i.OutputRegister(), esp);
|
| - break;
|
| case kArchFramePointer:
|
| __ mov(i.OutputRegister(), ebp);
|
| break;
|
| + case kArchStackPointer:
|
| + __ mov(i.OutputRegister(), esp);
|
| + break;
|
| case kArchTruncateDoubleToI: {
|
| - auto result = i.OutputRegister();
|
| auto input = i.InputDoubleRegister(0);
|
| - auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input);
|
| - __ cvttsd2si(result, Operand(input));
|
| - __ cmp(result, 1);
|
| - __ j(overflow, ool->entry());
|
| - __ bind(ool->exit());
|
| + USE(input);
|
| + DCHECK(input.code() == 0);
|
| + auto result_reg = i.OutputRegister();
|
| + __ TruncateX87TOSToI(result_reg);
|
| break;
|
| }
|
| - case kIA32Add:
|
| + case kX87Add:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ add(i.InputOperand(0), i.InputImmediate(1));
|
| } else {
|
| __ add(i.InputRegister(0), i.InputOperand(1));
|
| }
|
| break;
|
| - case kIA32And:
|
| + case kX87And:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ and_(i.InputOperand(0), i.InputImmediate(1));
|
| } else {
|
| __ and_(i.InputRegister(0), i.InputOperand(1));
|
| }
|
| break;
|
| - case kIA32Cmp:
|
| + case kX87Cmp:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ cmp(i.InputOperand(0), i.InputImmediate(1));
|
| } else {
|
| __ cmp(i.InputRegister(0), i.InputOperand(1));
|
| }
|
| break;
|
| - case kIA32Test:
|
| + case kX87Test:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ test(i.InputOperand(0), i.InputImmediate(1));
|
| } else {
|
| __ test(i.InputRegister(0), i.InputOperand(1));
|
| }
|
| break;
|
| - case kIA32Imul:
|
| + case kX87Imul:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1));
|
| } else {
|
| __ imul(i.OutputRegister(), i.InputOperand(1));
|
| }
|
| break;
|
| - case kIA32ImulHigh:
|
| + case kX87ImulHigh:
|
| __ imul(i.InputRegister(1));
|
| break;
|
| - case kIA32UmulHigh:
|
| + case kX87UmulHigh:
|
| __ mul(i.InputRegister(1));
|
| break;
|
| - case kIA32Idiv:
|
| + case kX87Idiv:
|
| __ cdq();
|
| __ idiv(i.InputOperand(1));
|
| break;
|
| - case kIA32Udiv:
|
| + case kX87Udiv:
|
| __ Move(edx, Immediate(0));
|
| __ div(i.InputOperand(1));
|
| break;
|
| - case kIA32Not:
|
| + case kX87Not:
|
| __ not_(i.OutputOperand());
|
| break;
|
| - case kIA32Neg:
|
| + case kX87Neg:
|
| __ neg(i.OutputOperand());
|
| break;
|
| - case kIA32Or:
|
| + case kX87Or:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ or_(i.InputOperand(0), i.InputImmediate(1));
|
| } else {
|
| __ or_(i.InputRegister(0), i.InputOperand(1));
|
| }
|
| break;
|
| - case kIA32Xor:
|
| + case kX87Xor:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ xor_(i.InputOperand(0), i.InputImmediate(1));
|
| } else {
|
| __ xor_(i.InputRegister(0), i.InputOperand(1));
|
| }
|
| break;
|
| - case kIA32Sub:
|
| + case kX87Sub:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ sub(i.InputOperand(0), i.InputImmediate(1));
|
| } else {
|
| __ sub(i.InputRegister(0), i.InputOperand(1));
|
| }
|
| break;
|
| - case kIA32Shl:
|
| + case kX87Shl:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ shl(i.OutputOperand(), i.InputInt5(1));
|
| } else {
|
| __ shl_cl(i.OutputOperand());
|
| }
|
| break;
|
| - case kIA32Shr:
|
| + case kX87Shr:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ shr(i.OutputOperand(), i.InputInt5(1));
|
| } else {
|
| __ shr_cl(i.OutputOperand());
|
| }
|
| break;
|
| - case kIA32Sar:
|
| + case kX87Sar:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ sar(i.OutputOperand(), i.InputInt5(1));
|
| } else {
|
| __ sar_cl(i.OutputOperand());
|
| }
|
| break;
|
| - case kIA32Ror:
|
| + case kX87Ror:
|
| if (HasImmediateInput(instr, 1)) {
|
| __ ror(i.OutputOperand(), i.InputInt5(1));
|
| } else {
|
| __ ror_cl(i.OutputOperand());
|
| }
|
| break;
|
| - case kIA32Lzcnt:
|
| + case kX87Lzcnt:
|
| __ Lzcnt(i.OutputRegister(), i.InputOperand(0));
|
| break;
|
| - case kSSEFloat32Cmp:
|
| - __ ucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat32Add:
|
| - __ addss(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat32Sub:
|
| - __ subss(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat32Mul:
|
| - __ mulss(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat32Div:
|
| - __ divss(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - // Don't delete this mov. It may improve performance on some CPUs,
|
| - // when there is a (v)mulss depending on the result.
|
| - __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
|
| - break;
|
| - case kSSEFloat32Max:
|
| - __ maxss(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat32Min:
|
| - __ minss(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat32Sqrt:
|
| - __ sqrtss(i.OutputDoubleRegister(), i.InputOperand(0));
|
| - break;
|
| - case kSSEFloat32Abs: {
|
| - // TODO(bmeurer): Use 128-bit constants.
|
| - __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
|
| - __ psrlq(kScratchDoubleReg, 33);
|
| - __ andps(i.OutputDoubleRegister(), kScratchDoubleReg);
|
| + case kX87LoadFloat64Constant: {
|
| + InstructionOperand* source = instr->InputAt(0);
|
| + InstructionOperand* destination = instr->Output();
|
| + DCHECK(source->IsConstant());
|
| + X87OperandConverter g(this, NULL);
|
| + Constant src_constant = g.ToConstant(source);
|
| +
|
| + DCHECK_EQ(Constant::kFloat64, src_constant.type());
|
| + uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64());
|
| + uint32_t lower = static_cast<uint32_t>(src);
|
| + uint32_t upper = static_cast<uint32_t>(src >> 32);
|
| + if (destination->IsDoubleRegister()) {
|
| + __ sub(esp, Immediate(kDoubleSize));
|
| + __ mov(MemOperand(esp, 0), Immediate(lower));
|
| + __ mov(MemOperand(esp, kInt32Size), Immediate(upper));
|
| + __ fstp(0);
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ add(esp, Immediate(kDoubleSize));
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| break;
|
| }
|
| - case kSSEFloat32Neg: {
|
| - // TODO(bmeurer): Use 128-bit constants.
|
| - __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
|
| - __ psllq(kScratchDoubleReg, 31);
|
| - __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg);
|
| + case kX87Float32Cmp: {
|
| + __ fld_s(MemOperand(esp, kFloatSize));
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ FCmp();
|
| + __ lea(esp, Operand(esp, 2 * kFloatSize));
|
| break;
|
| }
|
| - case kSSEFloat64Cmp:
|
| - __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat64Add:
|
| - __ addsd(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat64Sub:
|
| - __ subsd(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat64Mul:
|
| - __ mulsd(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat64Div:
|
| - __ divsd(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - // Don't delete this mov. It may improve performance on some CPUs,
|
| - // when there is a (v)mulsd depending on the result.
|
| - __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
|
| - break;
|
| - case kSSEFloat64Max:
|
| - __ maxsd(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat64Min:
|
| - __ minsd(i.InputDoubleRegister(0), i.InputOperand(1));
|
| - break;
|
| - case kSSEFloat64Mod: {
|
| - // TODO(dcarney): alignment is wrong.
|
| - __ sub(esp, Immediate(kDoubleSize));
|
| - // Move values to st(0) and st(1).
|
| - __ movsd(Operand(esp, 0), i.InputDoubleRegister(1));
|
| - __ fld_d(Operand(esp, 0));
|
| - __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
|
| - __ fld_d(Operand(esp, 0));
|
| - // Loop while fprem isn't done.
|
| - Label mod_loop;
|
| - __ bind(&mod_loop);
|
| - // This instructions traps on all kinds inputs, but we are assuming the
|
| - // floating point control word is set to ignore them all.
|
| - __ fprem();
|
| - // The following 2 instruction implicitly use eax.
|
| - __ fnstsw_ax();
|
| - __ sahf();
|
| - __ j(parity_even, &mod_loop);
|
| - // Move output to stack and clean up.
|
| - __ fstp(1);
|
| - __ fstp_d(Operand(esp, 0));
|
| - __ movsd(i.OutputDoubleRegister(), Operand(esp, 0));
|
| - __ add(esp, Immediate(kDoubleSize));
|
| + case kX87Float32Add: {
|
| + __ X87SetFPUCW(0x027F);
|
| + __ fstp(0);
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ fld_s(MemOperand(esp, kFloatSize));
|
| + __ faddp();
|
| + // Clear stack.
|
| + __ lea(esp, Operand(esp, 2 * kFloatSize));
|
| + // Restore the default value of control word.
|
| + __ X87SetFPUCW(0x037F);
|
| break;
|
| }
|
| - case kSSEFloat64Abs: {
|
| - // TODO(bmeurer): Use 128-bit constants.
|
| - __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
|
| - __ psrlq(kScratchDoubleReg, 1);
|
| - __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
|
| + case kX87Float32Sub: {
|
| + __ X87SetFPUCW(0x027F);
|
| + __ fstp(0);
|
| + __ fld_s(MemOperand(esp, kFloatSize));
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ fsubp();
|
| + // Clear stack.
|
| + __ lea(esp, Operand(esp, 2 * kFloatSize));
|
| + // Restore the default value of control word.
|
| + __ X87SetFPUCW(0x037F);
|
| break;
|
| }
|
| - case kSSEFloat64Neg: {
|
| - // TODO(bmeurer): Use 128-bit constants.
|
| - __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
|
| - __ psllq(kScratchDoubleReg, 63);
|
| - __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg);
|
| + case kX87Float32Mul: {
|
| + __ X87SetFPUCW(0x027F);
|
| + __ fstp(0);
|
| + __ fld_s(MemOperand(esp, kFloatSize));
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ fmulp();
|
| + // Clear stack.
|
| + __ lea(esp, Operand(esp, 2 * kFloatSize));
|
| + // Restore the default value of control word.
|
| + __ X87SetFPUCW(0x037F);
|
| break;
|
| }
|
| - case kSSEFloat64Sqrt:
|
| - __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
|
| - break;
|
| - case kSSEFloat64Round: {
|
| - CpuFeatureScope sse_scope(masm(), SSE4_1);
|
| - RoundingMode const mode =
|
| - static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
|
| - __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
|
| + case kX87Float32Div: {
|
| + __ X87SetFPUCW(0x027F);
|
| + __ fstp(0);
|
| + __ fld_s(MemOperand(esp, kFloatSize));
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ fdivp();
|
| + // Clear stack.
|
| + __ lea(esp, Operand(esp, 2 * kFloatSize));
|
| + // Restore the default value of control word.
|
| + __ X87SetFPUCW(0x037F);
|
| break;
|
| }
|
| - case kSSEFloat32ToFloat64:
|
| - __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
|
| - break;
|
| - case kSSEFloat64ToFloat32:
|
| - __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
|
| + case kX87Float32Max: {
|
| + Label check_nan_left, check_zero, return_left, return_right;
|
| + Condition condition = below;
|
| + __ fstp(0);
|
| + __ fld_s(MemOperand(esp, kFloatSize));
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ 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.
|
| +
|
| + __ 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);
|
| + __ fxch();
|
| +
|
| + __ bind(&return_left);
|
| + __ fstp(0);
|
| + __ lea(esp, Operand(esp, 2 * kFloatSize));
|
| break;
|
| - case kSSEFloat64ToInt32:
|
| - __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
|
| - break;
|
| - case kSSEFloat64ToUint32: {
|
| - __ Move(kScratchDoubleReg, -2147483648.0);
|
| - __ addsd(kScratchDoubleReg, i.InputOperand(0));
|
| - __ cvttsd2si(i.OutputRegister(), kScratchDoubleReg);
|
| - __ add(i.OutputRegister(), Immediate(0x80000000));
|
| + }
|
| + case kX87Float32Min: {
|
| + Label check_nan_left, check_zero, return_left, return_right;
|
| + Condition condition = above;
|
| + __ fstp(0);
|
| + __ fld_s(MemOperand(esp, kFloatSize));
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ 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.
|
| + // Push st0 and st1 to stack, then pop them to temp registers and OR them,
|
| + // load it to left.
|
| + __ push(eax);
|
| + __ fld(1);
|
| + __ fld(1);
|
| + __ sub(esp, Immediate(2 * kPointerSize));
|
| + __ fstp_s(MemOperand(esp, 0));
|
| + __ fstp_s(MemOperand(esp, kPointerSize));
|
| + __ pop(eax);
|
| + __ xor_(MemOperand(esp, 0), eax);
|
| + __ fstp(0);
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ pop(eax); // restore esp
|
| + __ pop(eax); // restore esp
|
| + __ 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);
|
| + __ fxch();
|
| +
|
| + __ bind(&return_left);
|
| + __ fstp(0);
|
| + __ lea(esp, Operand(esp, 2 * kFloatSize));
|
| break;
|
| }
|
| - case kSSEInt32ToFloat64:
|
| - __ cvtsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
|
| + case kX87Float32Sqrt: {
|
| + __ fstp(0);
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ fsqrt();
|
| + __ lea(esp, Operand(esp, kFloatSize));
|
| break;
|
| - case kSSEUint32ToFloat64:
|
| - __ LoadUint32(i.OutputDoubleRegister(), i.InputOperand(0));
|
| + }
|
| + case kX87Float32Abs: {
|
| + __ fstp(0);
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ fabs();
|
| + __ lea(esp, Operand(esp, kFloatSize));
|
| break;
|
| - case kSSEFloat64ExtractLowWord32:
|
| - if (instr->InputAt(0)->IsDoubleStackSlot()) {
|
| - __ mov(i.OutputRegister(), i.InputOperand(0));
|
| - } else {
|
| - __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
|
| - }
|
| + }
|
| + case kX87Float64Add: {
|
| + __ X87SetFPUCW(0x027F);
|
| + __ fstp(0);
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ fld_d(MemOperand(esp, kDoubleSize));
|
| + __ faddp();
|
| + // Clear stack.
|
| + __ lea(esp, Operand(esp, 2 * kDoubleSize));
|
| + // Restore the default value of control word.
|
| + __ X87SetFPUCW(0x037F);
|
| break;
|
| - case kSSEFloat64ExtractHighWord32:
|
| - if (instr->InputAt(0)->IsDoubleStackSlot()) {
|
| - __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
|
| - } else {
|
| - __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
|
| - }
|
| + }
|
| + case kX87Float64Sub: {
|
| + __ X87SetFPUCW(0x027F);
|
| + __ fstp(0);
|
| + __ fld_d(MemOperand(esp, kDoubleSize));
|
| + __ fsub_d(MemOperand(esp, 0));
|
| + // Clear stack.
|
| + __ lea(esp, Operand(esp, 2 * kDoubleSize));
|
| + // Restore the default value of control word.
|
| + __ X87SetFPUCW(0x037F);
|
| break;
|
| - case kSSEFloat64InsertLowWord32:
|
| - __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
|
| + }
|
| + case kX87Float64Mul: {
|
| + __ X87SetFPUCW(0x027F);
|
| + __ fstp(0);
|
| + __ fld_d(MemOperand(esp, kDoubleSize));
|
| + __ fmul_d(MemOperand(esp, 0));
|
| + // Clear stack.
|
| + __ lea(esp, Operand(esp, 2 * kDoubleSize));
|
| + // Restore the default value of control word.
|
| + __ X87SetFPUCW(0x037F);
|
| break;
|
| - case kSSEFloat64InsertHighWord32:
|
| - __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
|
| + }
|
| + case kX87Float64Div: {
|
| + __ X87SetFPUCW(0x027F);
|
| + __ fstp(0);
|
| + __ fld_d(MemOperand(esp, kDoubleSize));
|
| + __ fdiv_d(MemOperand(esp, 0));
|
| + // Clear stack.
|
| + __ lea(esp, Operand(esp, 2 * kDoubleSize));
|
| + // Restore the default value of control word.
|
| + __ X87SetFPUCW(0x037F);
|
| break;
|
| - case kSSEFloat64LoadLowWord32:
|
| - __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
|
| + }
|
| + case kX87Float64Mod: {
|
| + FrameScope frame_scope(&masm_, StackFrame::MANUAL);
|
| + __ mov(eax, esp);
|
| + __ PrepareCallCFunction(4, eax);
|
| + __ fstp(0);
|
| + __ fld_d(MemOperand(eax, 0));
|
| + __ fstp_d(Operand(esp, 1 * kDoubleSize));
|
| + __ fld_d(MemOperand(eax, kDoubleSize));
|
| + __ fstp_d(Operand(esp, 0));
|
| + __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
|
| + 4);
|
| + __ lea(esp, Operand(esp, 2 * kDoubleSize));
|
| break;
|
| - case kAVXFloat32Add: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vaddss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| + }
|
| + case kX87Float64Max: {
|
| + Label check_nan_left, check_zero, return_left, return_right;
|
| + Condition condition = below;
|
| + __ fstp(0);
|
| + __ fld_d(MemOperand(esp, kDoubleSize));
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ 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.
|
| +
|
| + __ 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);
|
| + __ fxch();
|
| +
|
| + __ bind(&return_left);
|
| + __ fstp(0);
|
| + __ lea(esp, Operand(esp, 2 * kDoubleSize));
|
| break;
|
| }
|
| - case kAVXFloat32Sub: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vsubss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| + case kX87Float64Min: {
|
| + Label check_nan_left, check_zero, return_left, return_right;
|
| + Condition condition = above;
|
| + __ fstp(0);
|
| + __ fld_d(MemOperand(esp, kDoubleSize));
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ 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.
|
| + // Push st0 and st1 to stack, then pop them to temp registers and OR them,
|
| + // load it to left.
|
| + __ push(eax);
|
| + __ fld(1);
|
| + __ fld(1);
|
| + __ sub(esp, Immediate(2 * kPointerSize));
|
| + __ fstp_s(MemOperand(esp, 0));
|
| + __ fstp_s(MemOperand(esp, kPointerSize));
|
| + __ pop(eax);
|
| + __ xor_(MemOperand(esp, 0), eax);
|
| + __ fstp(0);
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ pop(eax); // restore esp
|
| + __ pop(eax); // restore esp
|
| + __ 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);
|
| + __ fxch();
|
| +
|
| + __ bind(&return_left);
|
| + __ fstp(0);
|
| + __ lea(esp, Operand(esp, 2 * kDoubleSize));
|
| break;
|
| }
|
| - case kAVXFloat32Mul: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vmulss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| + case kX87Float64Abs: {
|
| + __ fstp(0);
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ fabs();
|
| + __ lea(esp, Operand(esp, kDoubleSize));
|
| break;
|
| }
|
| - case kAVXFloat32Div: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vdivss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| - // Don't delete this mov. It may improve performance on some CPUs,
|
| - // when there is a (v)mulss depending on the result.
|
| - __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
|
| + case kX87Int32ToFloat64: {
|
| + InstructionOperand* input = instr->InputAt(0);
|
| + DCHECK(input->IsRegister() || input->IsStackSlot());
|
| + __ fstp(0);
|
| + if (input->IsRegister()) {
|
| + Register input_reg = i.InputRegister(0);
|
| + __ push(input_reg);
|
| + __ fild_s(Operand(esp, 0));
|
| + __ pop(input_reg);
|
| + } else {
|
| + __ fild_s(i.InputOperand(0));
|
| + }
|
| break;
|
| }
|
| - case kAVXFloat32Max: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vmaxss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| + case kX87Float32ToFloat64: {
|
| + InstructionOperand* input = instr->InputAt(0);
|
| + if (input->IsDoubleRegister()) {
|
| + __ sub(esp, Immediate(kDoubleSize));
|
| + __ fstp_d(MemOperand(esp, 0));
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ add(esp, Immediate(kDoubleSize));
|
| + } else {
|
| + DCHECK(input->IsDoubleStackSlot());
|
| + __ fstp(0);
|
| + __ fld_s(i.InputOperand(0));
|
| + }
|
| break;
|
| }
|
| - case kAVXFloat32Min: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vminss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| + case kX87Uint32ToFloat64: {
|
| + __ fstp(0);
|
| + __ LoadUint32NoSSE2(i.InputRegister(0));
|
| break;
|
| }
|
| - case kAVXFloat64Add: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| + case kX87Float64ToInt32: {
|
| + if (!instr->InputAt(0)->IsDoubleRegister()) {
|
| + __ fld_d(i.InputOperand(0));
|
| + }
|
| + __ TruncateX87TOSToI(i.OutputRegister(0));
|
| + if (!instr->InputAt(0)->IsDoubleRegister()) {
|
| + __ fstp(0);
|
| + }
|
| break;
|
| }
|
| - case kAVXFloat64Sub: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vsubsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| + case kX87Float64ToFloat32: {
|
| + InstructionOperand* input = instr->InputAt(0);
|
| + if (input->IsDoubleRegister()) {
|
| + __ sub(esp, Immediate(kDoubleSize));
|
| + __ fstp_s(MemOperand(esp, 0));
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ add(esp, Immediate(kDoubleSize));
|
| + } else {
|
| + DCHECK(input->IsDoubleStackSlot());
|
| + __ fstp(0);
|
| + __ fld_d(i.InputOperand(0));
|
| + __ sub(esp, Immediate(kDoubleSize));
|
| + __ fstp_s(MemOperand(esp, 0));
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ add(esp, Immediate(kDoubleSize));
|
| + }
|
| break;
|
| }
|
| - case kAVXFloat64Mul: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vmulsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| + case kX87Float64ToUint32: {
|
| + __ push_imm32(-2147483648);
|
| + if (!instr->InputAt(0)->IsDoubleRegister()) {
|
| + __ fld_d(i.InputOperand(0));
|
| + }
|
| + __ fild_s(Operand(esp, 0));
|
| + __ fadd(1);
|
| + __ fstp(0);
|
| + __ TruncateX87TOSToI(i.OutputRegister(0));
|
| + __ add(esp, Immediate(kInt32Size));
|
| + __ add(i.OutputRegister(), Immediate(0x80000000));
|
| + if (!instr->InputAt(0)->IsDoubleRegister()) {
|
| + __ fstp(0);
|
| + }
|
| break;
|
| }
|
| - case kAVXFloat64Div: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vdivsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| - // Don't delete this mov. It may improve performance on some CPUs,
|
| - // when there is a (v)mulsd depending on the result.
|
| - __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
|
| + case kX87Float64ExtractHighWord32: {
|
| + if (instr->InputAt(0)->IsDoubleRegister()) {
|
| + __ sub(esp, Immediate(kDoubleSize));
|
| + __ fst_d(MemOperand(esp, 0));
|
| + __ mov(i.OutputRegister(), MemOperand(esp, kDoubleSize / 2));
|
| + __ add(esp, Immediate(kDoubleSize));
|
| + } else {
|
| + InstructionOperand* input = instr->InputAt(0);
|
| + USE(input);
|
| + DCHECK(input->IsDoubleStackSlot());
|
| + __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
|
| + }
|
| break;
|
| }
|
| - case kAVXFloat64Max: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vmaxsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| + case kX87Float64ExtractLowWord32: {
|
| + if (instr->InputAt(0)->IsDoubleRegister()) {
|
| + __ sub(esp, Immediate(kDoubleSize));
|
| + __ fst_d(MemOperand(esp, 0));
|
| + __ mov(i.OutputRegister(), MemOperand(esp, 0));
|
| + __ add(esp, Immediate(kDoubleSize));
|
| + } else {
|
| + InstructionOperand* input = instr->InputAt(0);
|
| + USE(input);
|
| + DCHECK(input->IsDoubleStackSlot());
|
| + __ mov(i.OutputRegister(), i.InputOperand(0));
|
| + }
|
| break;
|
| }
|
| - case kAVXFloat64Min: {
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vminsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
|
| - i.InputOperand(1));
|
| + case kX87Float64InsertHighWord32: {
|
| + __ sub(esp, Immediate(kDoubleSize));
|
| + __ fstp_d(MemOperand(esp, 0));
|
| + __ mov(MemOperand(esp, kDoubleSize / 2), i.InputRegister(1));
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ add(esp, Immediate(kDoubleSize));
|
| break;
|
| }
|
| - case kAVXFloat32Abs: {
|
| - // TODO(bmeurer): Use RIP relative 128-bit constants.
|
| - __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
|
| - __ psrlq(kScratchDoubleReg, 33);
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
|
| + case kX87Float64InsertLowWord32: {
|
| + __ sub(esp, Immediate(kDoubleSize));
|
| + __ fstp_d(MemOperand(esp, 0));
|
| + __ mov(MemOperand(esp, 0), i.InputRegister(1));
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ add(esp, Immediate(kDoubleSize));
|
| break;
|
| }
|
| - case kAVXFloat32Neg: {
|
| - // TODO(bmeurer): Use RIP relative 128-bit constants.
|
| - __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
|
| - __ psllq(kScratchDoubleReg, 31);
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
|
| + case kX87Float64Sqrt: {
|
| + __ fstp(0);
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ fsqrt();
|
| + __ lea(esp, Operand(esp, kDoubleSize));
|
| break;
|
| }
|
| - case kAVXFloat64Abs: {
|
| - // TODO(bmeurer): Use RIP relative 128-bit constants.
|
| - __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
|
| - __ psrlq(kScratchDoubleReg, 1);
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
|
| + case kX87Float64Round: {
|
| + RoundingMode mode =
|
| + static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
|
| + if (mode == MiscField::encode(kRoundDown)) {
|
| + __ X87SetRC(0x0400);
|
| + } else {
|
| + __ X87SetRC(0x0c00);
|
| + }
|
| +
|
| + if (!instr->InputAt(0)->IsDoubleRegister()) {
|
| + InstructionOperand* input = instr->InputAt(0);
|
| + USE(input);
|
| + DCHECK(input->IsDoubleStackSlot());
|
| + __ fstp(0);
|
| + __ fld_d(i.InputOperand(0));
|
| + }
|
| + __ frndint();
|
| + __ X87SetRC(0x0000);
|
| break;
|
| }
|
| - case kAVXFloat64Neg: {
|
| - // TODO(bmeurer): Use RIP relative 128-bit constants.
|
| - __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
|
| - __ psllq(kScratchDoubleReg, 63);
|
| - CpuFeatureScope avx_scope(masm(), AVX);
|
| - __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
|
| + case kX87Float64Cmp: {
|
| + __ fld_d(MemOperand(esp, kDoubleSize));
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ FCmp();
|
| + __ lea(esp, Operand(esp, 2 * kDoubleSize));
|
| break;
|
| }
|
| - case kIA32Movsxbl:
|
| + case kX87Movsxbl:
|
| __ movsx_b(i.OutputRegister(), i.MemoryOperand());
|
| break;
|
| - case kIA32Movzxbl:
|
| + case kX87Movzxbl:
|
| __ movzx_b(i.OutputRegister(), i.MemoryOperand());
|
| break;
|
| - case kIA32Movb: {
|
| + case kX87Movb: {
|
| size_t index = 0;
|
| Operand operand = i.MemoryOperand(&index);
|
| if (HasImmediateInput(instr, index)) {
|
| @@ -781,13 +1030,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
| }
|
| break;
|
| }
|
| - case kIA32Movsxwl:
|
| + case kX87Movsxwl:
|
| __ movsx_w(i.OutputRegister(), i.MemoryOperand());
|
| break;
|
| - case kIA32Movzxwl:
|
| + case kX87Movzxwl:
|
| __ movzx_w(i.OutputRegister(), i.MemoryOperand());
|
| break;
|
| - case kIA32Movw: {
|
| + case kX87Movw: {
|
| size_t index = 0;
|
| Operand operand = i.MemoryOperand(&index);
|
| if (HasImmediateInput(instr, index)) {
|
| @@ -797,7 +1046,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
| }
|
| break;
|
| }
|
| - case kIA32Movl:
|
| + case kX87Movl:
|
| if (instr->HasOutput()) {
|
| __ mov(i.OutputRegister(), i.MemoryOperand());
|
| } else {
|
| @@ -810,25 +1059,35 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
| }
|
| }
|
| break;
|
| - case kIA32Movsd:
|
| + case kX87Movsd: {
|
| if (instr->HasOutput()) {
|
| - __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
|
| + X87Register output = i.OutputDoubleRegister();
|
| + USE(output);
|
| + DCHECK(output.code() == 0);
|
| + __ fstp(0);
|
| + __ fld_d(i.MemoryOperand());
|
| } else {
|
| size_t index = 0;
|
| Operand operand = i.MemoryOperand(&index);
|
| - __ movsd(operand, i.InputDoubleRegister(index));
|
| + __ fst_d(operand);
|
| }
|
| break;
|
| - case kIA32Movss:
|
| + }
|
| + case kX87Movss: {
|
| if (instr->HasOutput()) {
|
| - __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
|
| + X87Register output = i.OutputDoubleRegister();
|
| + USE(output);
|
| + DCHECK(output.code() == 0);
|
| + __ fstp(0);
|
| + __ fld_s(i.MemoryOperand());
|
| } else {
|
| size_t index = 0;
|
| Operand operand = i.MemoryOperand(&index);
|
| - __ movss(operand, i.InputDoubleRegister(index));
|
| + __ fst_s(operand);
|
| }
|
| break;
|
| - case kIA32Lea: {
|
| + }
|
| + case kX87Lea: {
|
| AddressingMode mode = AddressingModeField::decode(instr->opcode());
|
| // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
|
| // and addressing mode just happens to work out. The "addl"/"subl" forms
|
| @@ -863,14 +1122,36 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
| }
|
| break;
|
| }
|
| - case kIA32Push:
|
| + case kX87Push:
|
| if (HasImmediateInput(instr, 0)) {
|
| __ push(i.InputImmediate(0));
|
| } else {
|
| __ push(i.InputOperand(0));
|
| }
|
| break;
|
| - case kIA32StoreWriteBarrier: {
|
| + case kX87PushFloat32:
|
| + __ lea(esp, Operand(esp, -kFloatSize));
|
| + if (instr->InputAt(0)->IsDoubleStackSlot()) {
|
| + __ fld_s(i.InputOperand(0));
|
| + __ fstp_s(MemOperand(esp, 0));
|
| + } else if (instr->InputAt(0)->IsDoubleRegister()) {
|
| + __ fst_s(MemOperand(esp, 0));
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| + break;
|
| + case kX87PushFloat64:
|
| + __ lea(esp, Operand(esp, -kDoubleSize));
|
| + if (instr->InputAt(0)->IsDoubleStackSlot()) {
|
| + __ fld_d(i.InputOperand(0));
|
| + __ fstp_d(MemOperand(esp, 0));
|
| + } else if (instr->InputAt(0)->IsDoubleRegister()) {
|
| + __ fst_d(MemOperand(esp, 0));
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| + break;
|
| + case kX87StoreWriteBarrier: {
|
| Register object = i.InputRegister(0);
|
| Register value = i.InputRegister(2);
|
| SaveFPRegsMode mode =
|
| @@ -904,10 +1185,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
| ASSEMBLE_CHECKED_LOAD_INTEGER(mov);
|
| break;
|
| case kCheckedLoadFloat32:
|
| - ASSEMBLE_CHECKED_LOAD_FLOAT(movss);
|
| + ASSEMBLE_CHECKED_LOAD_FLOAT(fld_s);
|
| break;
|
| case kCheckedLoadFloat64:
|
| - ASSEMBLE_CHECKED_LOAD_FLOAT(movsd);
|
| + ASSEMBLE_CHECKED_LOAD_FLOAT(fld_d);
|
| break;
|
| case kCheckedStoreWord8:
|
| ASSEMBLE_CHECKED_STORE_INTEGER(mov_b);
|
| @@ -919,12 +1200,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
| ASSEMBLE_CHECKED_STORE_INTEGER(mov);
|
| break;
|
| case kCheckedStoreFloat32:
|
| - ASSEMBLE_CHECKED_STORE_FLOAT(movss);
|
| + ASSEMBLE_CHECKED_STORE_FLOAT(fst_s);
|
| break;
|
| case kCheckedStoreFloat64:
|
| - ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
|
| + ASSEMBLE_CHECKED_STORE_FLOAT(fst_d);
|
| break;
|
| - case kIA32StackCheck: {
|
| + case kX87StackCheck: {
|
| ExternalReference const stack_limit =
|
| ExternalReference::address_of_stack_limit(isolate());
|
| __ cmp(esp, Operand::StaticVariable(stack_limit));
|
| @@ -936,7 +1217,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|
|
| // Assembles a branch after an instruction.
|
| void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
|
| - IA32OperandConverter i(this, instr);
|
| + X87OperandConverter i(this, instr);
|
| Label::Distance flabel_distance =
|
| branch->fallthru ? Label::kNear : Label::kFar;
|
| Label* tlabel = branch->true_label;
|
| @@ -998,7 +1279,7 @@ void CodeGenerator::AssembleArchJump(RpoNumber target) {
|
| // Assembles boolean materializations after an instruction.
|
| void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
| FlagsCondition condition) {
|
| - IA32OperandConverter i(this, instr);
|
| + X87OperandConverter i(this, instr);
|
| Label done;
|
|
|
| // Materialize a full 32-bit 1 or 0 value. The result register is always the
|
| @@ -1074,7 +1355,7 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
|
|
|
|
| void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
|
| - IA32OperandConverter i(this, instr);
|
| + X87OperandConverter i(this, instr);
|
| Register input = i.InputRegister(0);
|
| for (size_t index = 2; index < instr->InputCount(); index += 2) {
|
| __ cmp(input, Immediate(i.InputInt32(index + 0)));
|
| @@ -1085,7 +1366,7 @@ void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
|
|
|
|
|
| void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
|
| - IA32OperandConverter i(this, instr);
|
| + X87OperandConverter i(this, instr);
|
| Register input = i.InputRegister(0);
|
| size_t const case_count = instr->InputCount() - 2;
|
| Label** cases = zone()->NewArray<Label*>(case_count);
|
| @@ -1107,7 +1388,7 @@ void CodeGenerator::AssembleDeoptimizerCall(
|
| }
|
|
|
|
|
| -// The calling convention for JSFunctions on IA32 passes arguments on the
|
| +// The calling convention for JSFunctions on X87 passes arguments on the
|
| // stack and the JSFunction and context in EDI and ESI, respectively, thus
|
| // the steps of the call look as follows:
|
|
|
| @@ -1162,7 +1443,7 @@ void CodeGenerator::AssembleDeoptimizerCall(
|
|
|
|
|
| // Runtime function calls are accomplished by doing a stub call to the
|
| -// CEntryStub (a real code object). On IA32 passes arguments on the
|
| +// CEntryStub (a real code object). On X87 passes arguments on the
|
| // stack, the number of arguments in EAX, the address of the runtime function
|
| // in EBX, and the context in ESI.
|
|
|
| @@ -1285,6 +1566,10 @@ void CodeGenerator::AssemblePrologue() {
|
| // Allocate the stack slots used by this frame.
|
| __ sub(esp, Immediate(stack_slots * kPointerSize));
|
| }
|
| +
|
| + // Initailize FPU state.
|
| + __ fninit();
|
| + __ fld1();
|
| }
|
|
|
|
|
| @@ -1328,7 +1613,7 @@ void CodeGenerator::AssembleReturn() {
|
|
|
| void CodeGenerator::AssembleMove(InstructionOperand* source,
|
| InstructionOperand* destination) {
|
| - IA32OperandConverter g(this, NULL);
|
| + X87OperandConverter g(this, NULL);
|
| // Dispatch on the source and destination operand kinds. Not all
|
| // combinations are possible.
|
| if (source->IsRegister()) {
|
| @@ -1386,8 +1671,12 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
| // TODO(turbofan): Can we do better here?
|
| uint32_t src = bit_cast<uint32_t>(src_constant.ToFloat32());
|
| if (destination->IsDoubleRegister()) {
|
| - XMMRegister dst = g.ToDoubleRegister(destination);
|
| - __ Move(dst, src);
|
| + __ sub(esp, Immediate(kInt32Size));
|
| + __ mov(MemOperand(esp, 0), Immediate(src));
|
| + // always only push one value into the x87 stack.
|
| + __ fstp(0);
|
| + __ fld_s(MemOperand(esp, 0));
|
| + __ add(esp, Immediate(kInt32Size));
|
| } else {
|
| DCHECK(destination->IsDoubleStackSlot());
|
| Operand dst = g.ToOperand(destination);
|
| @@ -1399,8 +1688,13 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
| uint32_t lower = static_cast<uint32_t>(src);
|
| uint32_t upper = static_cast<uint32_t>(src >> 32);
|
| if (destination->IsDoubleRegister()) {
|
| - XMMRegister dst = g.ToDoubleRegister(destination);
|
| - __ Move(dst, src);
|
| + __ sub(esp, Immediate(kDoubleSize));
|
| + __ mov(MemOperand(esp, 0), Immediate(lower));
|
| + __ mov(MemOperand(esp, kInt32Size), Immediate(upper));
|
| + // always only push one value into the x87 stack.
|
| + __ fstp(0);
|
| + __ fld_d(MemOperand(esp, 0));
|
| + __ add(esp, Immediate(kDoubleSize));
|
| } else {
|
| DCHECK(destination->IsDoubleStackSlot());
|
| Operand dst0 = g.ToOperand(destination);
|
| @@ -1410,25 +1704,50 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
| }
|
| }
|
| } else if (source->IsDoubleRegister()) {
|
| - XMMRegister src = g.ToDoubleRegister(source);
|
| - if (destination->IsDoubleRegister()) {
|
| - XMMRegister dst = g.ToDoubleRegister(destination);
|
| - __ movaps(dst, src);
|
| - } else {
|
| - DCHECK(destination->IsDoubleStackSlot());
|
| - Operand dst = g.ToOperand(destination);
|
| - __ movsd(dst, src);
|
| + DCHECK(destination->IsDoubleStackSlot());
|
| + Operand dst = g.ToOperand(destination);
|
| + auto allocated = AllocatedOperand::cast(*source);
|
| + switch (allocated.machine_type()) {
|
| + case kRepFloat32:
|
| + __ fst_s(dst);
|
| + break;
|
| + case kRepFloat64:
|
| + __ fst_d(dst);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| }
|
| } else if (source->IsDoubleStackSlot()) {
|
| DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
|
| Operand src = g.ToOperand(source);
|
| + auto allocated = AllocatedOperand::cast(*source);
|
| if (destination->IsDoubleRegister()) {
|
| - XMMRegister dst = g.ToDoubleRegister(destination);
|
| - __ movsd(dst, src);
|
| + // always only push one value into the x87 stack.
|
| + __ fstp(0);
|
| + switch (allocated.machine_type()) {
|
| + case kRepFloat32:
|
| + __ fld_s(src);
|
| + break;
|
| + case kRepFloat64:
|
| + __ fld_d(src);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| } else {
|
| Operand dst = g.ToOperand(destination);
|
| - __ movsd(kScratchDoubleReg, src);
|
| - __ movsd(dst, kScratchDoubleReg);
|
| + switch (allocated.machine_type()) {
|
| + case kRepFloat32:
|
| + __ fld_s(src);
|
| + __ fstp_s(dst);
|
| + break;
|
| + case kRepFloat64:
|
| + __ fld_d(src);
|
| + __ fstp_d(dst);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| }
|
| } else {
|
| UNREACHABLE();
|
| @@ -1438,7 +1757,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
|
|
| void CodeGenerator::AssembleSwap(InstructionOperand* source,
|
| InstructionOperand* destination) {
|
| - IA32OperandConverter g(this, NULL);
|
| + X87OperandConverter g(this, NULL);
|
| // Dispatch on the source and destination operand kinds. Not all
|
| // combinations are possible.
|
| if (source->IsRegister() && destination->IsRegister()) {
|
| @@ -1458,31 +1777,41 @@ void CodeGenerator::AssembleSwap(InstructionOperand* source,
|
| __ pop(dst);
|
| __ pop(src);
|
| } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
|
| - // XMM register-register swap.
|
| - XMMRegister src = g.ToDoubleRegister(source);
|
| - XMMRegister dst = g.ToDoubleRegister(destination);
|
| - __ movaps(kScratchDoubleReg, src);
|
| - __ movaps(src, dst);
|
| - __ movaps(dst, kScratchDoubleReg);
|
| + UNREACHABLE();
|
| } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) {
|
| - // XMM register-memory swap.
|
| - XMMRegister reg = g.ToDoubleRegister(source);
|
| - Operand other = g.ToOperand(destination);
|
| - __ movsd(kScratchDoubleReg, other);
|
| - __ movsd(other, reg);
|
| - __ movaps(reg, kScratchDoubleReg);
|
| + auto allocated = AllocatedOperand::cast(*source);
|
| + switch (allocated.machine_type()) {
|
| + case kRepFloat32:
|
| + __ fld_s(g.ToOperand(destination));
|
| + __ fxch();
|
| + __ fstp_s(g.ToOperand(destination));
|
| + break;
|
| + case kRepFloat64:
|
| + __ fld_d(g.ToOperand(destination));
|
| + __ fxch();
|
| + __ fstp_d(g.ToOperand(destination));
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| } else if (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot()) {
|
| - // Double-width memory-to-memory.
|
| - Operand src0 = g.ToOperand(source);
|
| - Operand src1 = g.HighOperand(source);
|
| - Operand dst0 = g.ToOperand(destination);
|
| - Operand dst1 = g.HighOperand(destination);
|
| - __ movsd(kScratchDoubleReg, dst0); // Save destination in scratch register.
|
| - __ push(src0); // Then use stack to copy source to destination.
|
| - __ pop(dst0);
|
| - __ push(src1);
|
| - __ pop(dst1);
|
| - __ movsd(src0, kScratchDoubleReg);
|
| + auto allocated = AllocatedOperand::cast(*source);
|
| + switch (allocated.machine_type()) {
|
| + case kRepFloat32:
|
| + __ fld_s(g.ToOperand(source));
|
| + __ fld_s(g.ToOperand(destination));
|
| + __ fstp_s(g.ToOperand(source));
|
| + __ fstp_s(g.ToOperand(destination));
|
| + break;
|
| + case kRepFloat64:
|
| + __ fld_d(g.ToOperand(source));
|
| + __ fld_d(g.ToOperand(destination));
|
| + __ fstp_d(g.ToOperand(source));
|
| + __ fstp_d(g.ToOperand(destination));
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| } else {
|
| // No other combinations are possible.
|
| UNREACHABLE();
|
|
|