Commit ecfa9675 authored by palfia@homejinni.com's avatar palfia@homejinni.com

MIPS: Remove soft-float support.

Port r14159 (0c64645)

Original commit message:
Remove ARM support for VFP2

BUG=

TEST=

Review URL: https://codereview.chromium.org/14113011
Patch from Dusan Milosavljevic <Dusan.Milosavljevic@rt-rk.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14275 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 102c5170
......@@ -321,8 +321,6 @@ DEFINE_bool(enable_unaligned_accesses, true,
"enable unaligned accesses for ARMv7 (ARM only)")
DEFINE_bool(enable_32dregs, true,
"enable use of d16-d31 registers on ARM - this requires VFP3")
DEFINE_bool(enable_fpu, true,
"enable use of MIPS FPU instructions if available (MIPS only)")
DEFINE_bool(enable_vldr_imm, false,
"enable use of constant pools for double immediate (ARM only)")
......
......@@ -81,29 +81,17 @@ bool Operand::is_reg() const {
int Register::NumAllocatableRegisters() {
if (CpuFeatures::IsSupported(FPU)) {
return kMaxNumAllocatableRegisters;
} else {
return kMaxNumAllocatableRegisters - kGPRsPerNonFPUDouble;
}
}
int DoubleRegister::NumRegisters() {
if (CpuFeatures::IsSupported(FPU)) {
return FPURegister::kMaxNumRegisters;
} else {
return 1;
}
}
int DoubleRegister::NumAllocatableRegisters() {
if (CpuFeatures::IsSupported(FPU)) {
return FPURegister::kMaxNumAllocatableRegisters;
} else {
return 1;
}
}
......
......@@ -80,29 +80,24 @@ static uint64_t CpuFeaturesImpliedByCompiler() {
const char* DoubleRegister::AllocationIndexToString(int index) {
if (CpuFeatures::IsSupported(FPU)) {
ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
const char* const names[] = {
"f0",
"f2",
"f4",
"f6",
"f8",
"f10",
"f12",
"f14",
"f16",
"f18",
"f20",
"f22",
"f24",
"f26"
};
return names[index];
} else {
ASSERT(index == 0);
return "sfpd0";
}
ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
const char* const names[] = {
"f0",
"f2",
"f4",
"f6",
"f8",
"f10",
"f12",
"f14",
"f16",
"f18",
"f20",
"f22",
"f24",
"f26"
};
return names[index];
}
......@@ -127,10 +122,8 @@ void CpuFeatures::Probe() {
// If the compiler is allowed to use fpu then we can use fpu too in our
// code generation.
#if !defined(__mips__)
// For the simulator=mips build, use FPU when FLAG_enable_fpu is enabled.
if (FLAG_enable_fpu) {
supported_ |= static_cast<uint64_t>(1) << FPU;
}
// For the simulator build, use FPU.
supported_ |= static_cast<uint64_t>(1) << FPU;
#else
// Probe for additional features not already known to be available.
if (OS::MipsCpuHasFeature(FPU)) {
......@@ -876,7 +869,6 @@ void Assembler::GenInstrRegister(Opcode opcode,
FPURegister fd,
SecondaryField func) {
ASSERT(fd.is_valid() && fs.is_valid() && ft.is_valid());
ASSERT(IsEnabled(FPU));
Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
| (fd.code() << kFdShift) | func;
emit(instr);
......@@ -890,7 +882,6 @@ void Assembler::GenInstrRegister(Opcode opcode,
FPURegister fd,
SecondaryField func) {
ASSERT(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
ASSERT(IsEnabled(FPU));
Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
| (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
emit(instr);
......@@ -904,7 +895,6 @@ void Assembler::GenInstrRegister(Opcode opcode,
FPURegister fd,
SecondaryField func) {
ASSERT(fd.is_valid() && fs.is_valid() && rt.is_valid());
ASSERT(IsEnabled(FPU));
Instr instr = opcode | fmt | (rt.code() << kRtShift)
| (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
emit(instr);
......@@ -917,7 +907,6 @@ void Assembler::GenInstrRegister(Opcode opcode,
FPUControlRegister fs,
SecondaryField func) {
ASSERT(fs.is_valid() && rt.is_valid());
ASSERT(IsEnabled(FPU));
Instr instr =
opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
emit(instr);
......@@ -952,7 +941,6 @@ void Assembler::GenInstrImmediate(Opcode opcode,
FPURegister ft,
int32_t j) {
ASSERT(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
ASSERT(IsEnabled(FPU));
Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
| (j & kImm16Mask);
emit(instr);
......@@ -1874,7 +1862,6 @@ void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
// Conditions.
void Assembler::c(FPUCondition cond, SecondaryField fmt,
FPURegister fs, FPURegister ft, uint16_t cc) {
ASSERT(IsEnabled(FPU));
ASSERT(is_uint3(cc));
ASSERT((fmt & ~(31 << kRsShift)) == 0);
Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
......@@ -1885,7 +1872,6 @@ void Assembler::c(FPUCondition cond, SecondaryField fmt,
void Assembler::fcmp(FPURegister src1, const double src2,
FPUCondition cond) {
ASSERT(IsEnabled(FPU));
ASSERT(src2 == 0.0);
mtc1(zero_reg, f14);
cvt_d_w(f14, f14);
......@@ -1894,7 +1880,6 @@ void Assembler::fcmp(FPURegister src1, const double src2,
void Assembler::bc1f(int16_t offset, uint16_t cc) {
ASSERT(IsEnabled(FPU));
ASSERT(is_uint3(cc));
Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
emit(instr);
......@@ -1902,7 +1887,6 @@ void Assembler::bc1f(int16_t offset, uint16_t cc) {
void Assembler::bc1t(int16_t offset, uint16_t cc) {
ASSERT(IsEnabled(FPU));
ASSERT(is_uint3(cc));
Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
emit(instr);
......
......@@ -74,7 +74,6 @@ struct Register {
static const int kNumRegisters = v8::internal::kNumRegisters;
static const int kMaxNumAllocatableRegisters = 14; // v0 through t7.
static const int kSizeInBytes = 4;
static const int kGPRsPerNonFPUDouble = 2;
inline static int NumAllocatableRegisters();
......@@ -300,9 +299,6 @@ const FPURegister f29 = { 29 };
const FPURegister f30 = { 30 };
const FPURegister f31 = { 31 };
const Register sfpd_lo = { kRegister_t6_Code };
const Register sfpd_hi = { kRegister_t7_Code };
// Register aliases.
// cp is assumed to be a callee saved register.
// Defined using #define instead of "static const Register&" because Clang
......@@ -403,7 +399,6 @@ class CpuFeatures : public AllStatic {
// Check whether a feature is supported by the target CPU.
static bool IsSupported(CpuFeature f) {
ASSERT(initialized_);
if (f == FPU && !FLAG_enable_fpu) return false;
return (supported_ & (1u << f)) != 0;
}
......
......@@ -147,7 +147,6 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
Label* rhs_not_nan,
Label* slow,
bool strict);
static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc);
static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
Register lhs,
Register rhs);
......@@ -516,30 +515,15 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
FloatingPointHelper::Destination destination,
Register scratch1,
Register scratch2) {
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
__ sra(scratch1, a0, kSmiTagSize);
__ mtc1(scratch1, f14);
__ cvt_d_w(f14, f14);
__ sra(scratch1, a1, kSmiTagSize);
__ mtc1(scratch1, f12);
__ cvt_d_w(f12, f12);
if (destination == kCoreRegisters) {
__ Move(a2, a3, f14);
__ Move(a0, a1, f12);
}
} else {
ASSERT(destination == kCoreRegisters);
// Write Smi from a0 to a3 and a2 in double format.
__ mov(scratch1, a0);
ConvertToDoubleStub stub1(a3, a2, scratch1, scratch2);
__ push(ra);
__ Call(stub1.GetCode(masm->isolate()));
// Write Smi from a1 to a1 and a0 in double format.
__ mov(scratch1, a1);
ConvertToDoubleStub stub2(a1, a0, scratch1, scratch2);
__ Call(stub2.GetCode(masm->isolate()));
__ pop(ra);
__ sra(scratch1, a0, kSmiTagSize);
__ mtc1(scratch1, f14);
__ cvt_d_w(f14, f14);
__ sra(scratch1, a1, kSmiTagSize);
__ mtc1(scratch1, f12);
__ cvt_d_w(f12, f12);
if (destination == kCoreRegisters) {
__ Move(a2, a3, f14);
__ Move(a0, a1, f12);
}
}
......@@ -566,9 +550,7 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
__ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
// Handle loading a double from a heap number.
if (CpuFeatures::IsSupported(FPU) &&
destination == kFPURegisters) {
CpuFeatureScope scope(masm, FPU);
if (destination == kFPURegisters) {
// Load the double from tagged HeapNumber to double register.
// ARM uses a workaround here because of the unaligned HeapNumber
......@@ -586,25 +568,13 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
// Handle loading a double from a smi.
__ bind(&is_smi);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
// Convert smi to double using FPU instructions.
__ mtc1(scratch1, dst);
__ cvt_d_w(dst, dst);
if (destination == kCoreRegisters) {
// Load the converted smi to dst1 and dst2 in double format.
__ Move(dst1, dst2, dst);
}
} else {
ASSERT(destination == kCoreRegisters);
// Write smi to dst1 and dst2 double format.
__ mov(scratch1, object);
ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2);
__ push(ra);
__ Call(stub.GetCode(masm->isolate()));
__ pop(ra);
// Convert smi to double using FPU instructions.
__ mtc1(scratch1, dst);
__ cvt_d_w(dst, dst);
if (destination == kCoreRegisters) {
// Load the converted smi to dst1 and dst2 in double format.
__ Move(dst1, dst2, dst);
}
__ bind(&done);
}
......@@ -660,74 +630,11 @@ void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm,
ASSERT(!int_scratch.is(dst_mantissa));
ASSERT(!int_scratch.is(dst_exponent));
Label done;
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
__ mtc1(int_scratch, single_scratch);
__ cvt_d_w(double_dst, single_scratch);
if (destination == kCoreRegisters) {
__ Move(dst_mantissa, dst_exponent, double_dst);
}
} else {
Label fewer_than_20_useful_bits;
// Expected output:
// | dst_exponent | dst_mantissa |
// | s | exp | mantissa |
// Check for zero.
__ mov(dst_exponent, int_scratch);
__ mov(dst_mantissa, int_scratch);
__ Branch(&done, eq, int_scratch, Operand(zero_reg));
// Preload the sign of the value.
__ And(dst_exponent, int_scratch, Operand(HeapNumber::kSignMask));
// Get the absolute value of the object (as an unsigned integer).
Label skip_sub;
__ Branch(&skip_sub, ge, dst_exponent, Operand(zero_reg));
__ Subu(int_scratch, zero_reg, int_scratch);
__ bind(&skip_sub);
// Get mantissa[51:20].
// Get the position of the first set bit.
__ Clz(dst_mantissa, int_scratch);
__ li(scratch2, 31);
__ Subu(dst_mantissa, scratch2, dst_mantissa);
// Set the exponent.
__ Addu(scratch2, dst_mantissa, Operand(HeapNumber::kExponentBias));
__ Ins(dst_exponent, scratch2,
HeapNumber::kExponentShift, HeapNumber::kExponentBits);
// Clear the first non null bit.
__ li(scratch2, Operand(1));
__ sllv(scratch2, scratch2, dst_mantissa);
__ li(at, -1);
__ Xor(scratch2, scratch2, at);
__ And(int_scratch, int_scratch, scratch2);
// Get the number of bits to set in the lower part of the mantissa.
__ Subu(scratch2, dst_mantissa,
Operand(HeapNumber::kMantissaBitsInTopWord));
__ Branch(&fewer_than_20_useful_bits, le, scratch2, Operand(zero_reg));
// Set the higher 20 bits of the mantissa.
__ srlv(at, int_scratch, scratch2);
__ or_(dst_exponent, dst_exponent, at);
__ li(at, 32);
__ subu(scratch2, at, scratch2);
__ sllv(dst_mantissa, int_scratch, scratch2);
__ Branch(&done);
__ bind(&fewer_than_20_useful_bits);
__ li(at, HeapNumber::kMantissaBitsInTopWord);
__ subu(scratch2, at, dst_mantissa);
__ sllv(scratch2, int_scratch, scratch2);
__ Or(dst_exponent, dst_exponent, scratch2);
// Set dst_mantissa to 0.
__ mov(dst_mantissa, zero_reg);
__ mtc1(int_scratch, single_scratch);
__ cvt_d_w(double_dst, single_scratch);
if (destination == kCoreRegisters) {
__ Move(dst_mantissa, dst_exponent, double_dst);
}
__ bind(&done);
}
......@@ -764,82 +671,23 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
__ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
// Load the number.
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
// Load the double value.
__ ldc1(double_dst, FieldMemOperand(object, HeapNumber::kValueOffset));
Register except_flag = scratch2;
__ EmitFPUTruncate(kRoundToZero,
scratch1,
double_dst,
at,
double_scratch,
except_flag,
kCheckForInexactConversion);
// Jump to not_int32 if the operation did not succeed.
__ Branch(not_int32, ne, except_flag, Operand(zero_reg));
if (destination == kCoreRegisters) {
__ Move(dst_mantissa, dst_exponent, double_dst);
}
} else {
ASSERT(!scratch1.is(object) && !scratch2.is(object));
// Load the double value in the destination registers.
bool save_registers = object.is(dst_mantissa) || object.is(dst_exponent);
if (save_registers) {
// Save both output registers, because the other one probably holds
// an important value too.
__ Push(dst_exponent, dst_mantissa);
}
if (object.is(dst_mantissa)) {
__ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
__ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
} else {
__ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
__ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
}
// Check for 0 and -0.
Label zero;
__ And(scratch1, dst_exponent, Operand(~HeapNumber::kSignMask));
__ Or(scratch1, scratch1, Operand(dst_mantissa));
__ Branch(&zero, eq, scratch1, Operand(zero_reg));
// Check that the value can be exactly represented by a 32-bit integer.
// Jump to not_int32 if that's not the case.
Label restore_input_and_miss;
DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2,
&restore_input_and_miss);
// dst_* were trashed. Reload the double value.
if (save_registers) {
__ Pop(dst_exponent, dst_mantissa);
}
if (object.is(dst_mantissa)) {
__ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
__ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
} else {
__ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
__ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
}
__ Branch(&done);
__ bind(&restore_input_and_miss);
if (save_registers) {
__ Pop(dst_exponent, dst_mantissa);
}
__ Branch(not_int32);
__ bind(&zero);
if (save_registers) {
__ Drop(2);
}
// Load the double value.
__ ldc1(double_dst, FieldMemOperand(object, HeapNumber::kValueOffset));
Register except_flag = scratch2;
__ EmitFPUTruncate(kRoundToZero,
scratch1,
double_dst,
at,
double_scratch,
except_flag,
kCheckForInexactConversion);
// Jump to not_int32 if the operation did not succeed.
__ Branch(not_int32, ne, except_flag, Operand(zero_reg));
if (destination == kCoreRegisters) {
__ Move(dst_mantissa, dst_exponent, double_dst);
}
__ bind(&done);
}
......@@ -872,53 +720,20 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
// Object is a heap number.
// Convert the floating point value to a 32-bit integer.
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
// Load the double value.
__ ldc1(double_scratch0, FieldMemOperand(object, HeapNumber::kValueOffset));
Register except_flag = scratch2;
__ EmitFPUTruncate(kRoundToZero,
dst,
double_scratch0,
scratch1,
double_scratch1,
except_flag,
kCheckForInexactConversion);
// Jump to not_int32 if the operation did not succeed.
__ Branch(not_int32, ne, except_flag, Operand(zero_reg));
} else {
// Load the double value in the destination registers.
__ lw(scratch2, FieldMemOperand(object, HeapNumber::kExponentOffset));
__ lw(scratch1, FieldMemOperand(object, HeapNumber::kMantissaOffset));
// Check for 0 and -0.
__ And(dst, scratch1, Operand(~HeapNumber::kSignMask));
__ Or(dst, scratch2, Operand(dst));
__ Branch(&done, eq, dst, Operand(zero_reg));
DoubleIs32BitInteger(masm, scratch1, scratch2, dst, scratch3, not_int32);
// Registers state after DoubleIs32BitInteger.
// dst: mantissa[51:20].
// scratch2: 1
// Shift back the higher bits of the mantissa.
__ srlv(dst, dst, scratch3);
// Set the implicit first bit.
__ li(at, 32);
__ subu(scratch3, at, scratch3);
__ sllv(scratch2, scratch2, scratch3);
__ Or(dst, dst, scratch2);
// Set the sign.
__ lw(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
__ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
Label skip_sub;
__ Branch(&skip_sub, ge, scratch1, Operand(zero_reg));
__ Subu(dst, zero_reg, dst);
__ bind(&skip_sub);
}
// Load the double value.
__ ldc1(double_scratch0, FieldMemOperand(object, HeapNumber::kValueOffset));
Register except_flag = scratch2;
__ EmitFPUTruncate(kRoundToZero,
dst,
double_scratch0,
scratch1,
double_scratch1,
except_flag,
kCheckForInexactConversion);
// Jump to not_int32 if the operation did not succeed.
__ Branch(not_int32, ne, except_flag, Operand(zero_reg));
__ Branch(&done);
__ bind(&maybe_undefined);
......@@ -932,66 +747,6 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
}
void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm,
Register src_exponent,
Register src_mantissa,
Register dst,
Register scratch,
Label* not_int32) {
// Get exponent alone in scratch.
__ Ext(scratch,
src_exponent,
HeapNumber::kExponentShift,
HeapNumber::kExponentBits);
// Substract the bias from the exponent.
__ Subu(scratch, scratch, Operand(HeapNumber::kExponentBias));
// src1: higher (exponent) part of the double value.
// src2: lower (mantissa) part of the double value.
// scratch: unbiased exponent.
// Fast cases. Check for obvious non 32-bit integer values.
// Negative exponent cannot yield 32-bit integers.
__ Branch(not_int32, lt, scratch, Operand(zero_reg));
// Exponent greater than 31 cannot yield 32-bit integers.
// Also, a positive value with an exponent equal to 31 is outside of the
// signed 32-bit integer range.
// Another way to put it is that if (exponent - signbit) > 30 then the
// number cannot be represented as an int32.
Register tmp = dst;
__ srl(at, src_exponent, 31);
__ subu(tmp, scratch, at);
__ Branch(not_int32, gt, tmp, Operand(30));
// - Bits [21:0] in the mantissa are not null.
__ And(tmp, src_mantissa, 0x3fffff);
__ Branch(not_int32, ne, tmp, Operand(zero_reg));
// Otherwise the exponent needs to be big enough to shift left all the
// non zero bits left. So we need the (30 - exponent) last bits of the
// 31 higher bits of the mantissa to be null.
// Because bits [21:0] are null, we can check instead that the
// (32 - exponent) last bits of the 32 higher bits of the mantissa are null.
// Get the 32 higher bits of the mantissa in dst.
__ Ext(dst,
src_mantissa,
HeapNumber::kMantissaBitsInTopWord,
32 - HeapNumber::kMantissaBitsInTopWord);
__ sll(at, src_exponent, HeapNumber::kNonMantissaBitsInTopWord);
__ or_(dst, dst, at);
// Create the mask and test the lower bits (of the higher bits).
__ li(at, 32);
__ subu(scratch, at, scratch);
__ li(src_mantissa, 1);
__ sllv(src_exponent, src_mantissa, scratch);
__ Subu(src_exponent, src_exponent, Operand(1));
__ And(src_exponent, dst, src_exponent);
__ Branch(not_int32, ne, src_exponent, Operand(zero_reg));
}
void FloatingPointHelper::CallCCodeForDoubleOperation(
MacroAssembler* masm,
Token::Value op,
......@@ -1011,7 +766,6 @@ void FloatingPointHelper::CallCCodeForDoubleOperation(
__ push(ra);
__ PrepareCallCFunction(4, scratch); // Two doubles are 4 arguments.
if (!IsMipsSoftFloatABI) {
CpuFeatureScope scope(masm, FPU);
// We are not using MIPS FPU instructions, and parameters for the runtime
// function call are prepaired in a0-a3 registers, but function we are
// calling is compiled with hard-float flag and expecting hard float ABI
......@@ -1027,7 +781,6 @@ void FloatingPointHelper::CallCCodeForDoubleOperation(
}
// Store answer in the overwritable heap number.
if (!IsMipsSoftFloatABI) {
CpuFeatureScope scope(masm, FPU);
// Double returned in register f0.
__ sdc1(f0, FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
} else {
......@@ -1250,25 +1003,10 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
// Rhs is a smi, lhs is a number.
// Convert smi rhs to double.
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
__ sra(at, rhs, kSmiTagSize);
__ mtc1(at, f14);
__ cvt_d_w(f14, f14);
__ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
} else {
// Load lhs to a double in a2, a3.
__ lw(a3, FieldMemOperand(lhs, HeapNumber::kValueOffset + 4));
__ lw(a2, FieldMemOperand(lhs, HeapNumber::kValueOffset));
// Write Smi from rhs to a1 and a0 in double format. t5 is scratch.
__ mov(t6, rhs);
ConvertToDoubleStub stub1(a1, a0, t6, t5);
__ push(ra);
__ Call(stub1.GetCode(masm->isolate()));
__ pop(ra);
}
__ sra(at, rhs, kSmiTagSize);
__ mtc1(at, f14);
__ cvt_d_w(f14, f14);
__ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
// We now have both loaded as doubles.
__ jmp(both_loaded_as_doubles);
......@@ -1289,179 +1027,14 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
// Lhs is a smi, rhs is a number.
// Convert smi lhs to double.
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
__ sra(at, lhs, kSmiTagSize);
__ mtc1(at, f12);
__ cvt_d_w(f12, f12);
__ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
} else {
// Convert lhs to a double format. t5 is scratch.
__ mov(t6, lhs);
ConvertToDoubleStub stub2(a3, a2, t6, t5);
__ push(ra);
__ Call(stub2.GetCode(masm->isolate()));
__ pop(ra);
// Load rhs to a double in a1, a0.
if (rhs.is(a0)) {
__ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
__ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
} else {
__ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
__ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
}
}
__ sra(at, lhs, kSmiTagSize);
__ mtc1(at, f12);
__ cvt_d_w(f12, f12);
__ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
// Fall through to both_loaded_as_doubles.
}
void EmitNanCheck(MacroAssembler* masm, Condition cc) {
bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
// Lhs and rhs are already loaded to f12 and f14 register pairs.
__ Move(t0, t1, f14);
__ Move(t2, t3, f12);
} else {
// Lhs and rhs are already loaded to GP registers.
__ mov(t0, a0); // a0 has LS 32 bits of rhs.
__ mov(t1, a1); // a1 has MS 32 bits of rhs.
__ mov(t2, a2); // a2 has LS 32 bits of lhs.
__ mov(t3, a3); // a3 has MS 32 bits of lhs.
}
Register rhs_exponent = exp_first ? t0 : t1;
Register lhs_exponent = exp_first ? t2 : t3;
Register rhs_mantissa = exp_first ? t1 : t0;
Register lhs_mantissa = exp_first ? t3 : t2;
Label one_is_nan, neither_is_nan;
Label lhs_not_nan_exp_mask_is_loaded;
Register exp_mask_reg = t4;
__ li(exp_mask_reg, HeapNumber::kExponentMask);
__ and_(t5, lhs_exponent, exp_mask_reg);
__ Branch(&lhs_not_nan_exp_mask_is_loaded, ne, t5, Operand(exp_mask_reg));
__ sll(t5, lhs_exponent, HeapNumber::kNonMantissaBitsInTopWord);
__ Branch(&one_is_nan, ne, t5, Operand(zero_reg));
__ Branch(&one_is_nan, ne, lhs_mantissa, Operand(zero_reg));
__ li(exp_mask_reg, HeapNumber::kExponentMask);
__ bind(&lhs_not_nan_exp_mask_is_loaded);
__ and_(t5, rhs_exponent, exp_mask_reg);
__ Branch(&neither_is_nan, ne, t5, Operand(exp_mask_reg));
__ sll(t5, rhs_exponent, HeapNumber::kNonMantissaBitsInTopWord);
__ Branch(&one_is_nan, ne, t5, Operand(zero_reg));
__ Branch(&neither_is_nan, eq, rhs_mantissa, Operand(zero_reg));
__ bind(&one_is_nan);
// NaN comparisons always fail.
// Load whatever we need in v0 to make the comparison fail.
if (cc == lt || cc == le) {
__ li(v0, Operand(GREATER));
} else {
__ li(v0, Operand(LESS));
}
__ Ret();
__ bind(&neither_is_nan);
}
static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) {
// f12 and f14 have the two doubles. Neither is a NaN.
// Call a native function to do a comparison between two non-NaNs.
// Call C routine that may not cause GC or other trouble.
// We use a call_was and return manually because we need arguments slots to
// be freed.
Label return_result_not_equal, return_result_equal;
if (cc == eq) {
// Doubles are not equal unless they have the same bit pattern.
// Exception: 0 and -0.
bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
// Lhs and rhs are already loaded to f12 and f14 register pairs.
__ Move(t0, t1, f14);
__ Move(t2, t3, f12);
} else {
// Lhs and rhs are already loaded to GP registers.
__ mov(t0, a0); // a0 has LS 32 bits of rhs.
__ mov(t1, a1); // a1 has MS 32 bits of rhs.
__ mov(t2, a2); // a2 has LS 32 bits of lhs.
__ mov(t3, a3); // a3 has MS 32 bits of lhs.
}
Register rhs_exponent = exp_first ? t0 : t1;
Register lhs_exponent = exp_first ? t2 : t3;
Register rhs_mantissa = exp_first ? t1 : t0;
Register lhs_mantissa = exp_first ? t3 : t2;
__ xor_(v0, rhs_mantissa, lhs_mantissa);
__ Branch(&return_result_not_equal, ne, v0, Operand(zero_reg));
__ subu(v0, rhs_exponent, lhs_exponent);
__ Branch(&return_result_equal, eq, v0, Operand(zero_reg));
// 0, -0 case.
__ sll(rhs_exponent, rhs_exponent, kSmiTagSize);
__ sll(lhs_exponent, lhs_exponent, kSmiTagSize);
__ or_(t4, rhs_exponent, lhs_exponent);
__ or_(t4, t4, rhs_mantissa);
__ Branch(&return_result_not_equal, ne, t4, Operand(zero_reg));
__ bind(&return_result_equal);
__ li(v0, Operand(EQUAL));
__ Ret();
}
__ bind(&return_result_not_equal);
if (!CpuFeatures::IsSupported(FPU)) {
__ push(ra);
__ PrepareCallCFunction(0, 2, t4);
if (!IsMipsSoftFloatABI) {
// We are not using MIPS FPU instructions, and parameters for the runtime
// function call are prepaired in a0-a3 registers, but function we are
// calling is compiled with hard-float flag and expecting hard float ABI
// (parameters in f12/f14 registers). We need to copy parameters from
// a0-a3 registers to f12/f14 register pairs.
__ Move(f12, a0, a1);
__ Move(f14, a2, a3);
}
AllowExternalCallThatCantCauseGC scope(masm);
__ CallCFunction(ExternalReference::compare_doubles(masm->isolate()),
0, 2);
__ pop(ra); // Because this function returns int, result is in v0.
__ Ret();
} else {
CpuFeatureScope scope(masm, FPU);
Label equal, less_than;
__ BranchF(&equal, NULL, eq, f12, f14);
__ BranchF(&less_than, NULL, lt, f12, f14);
// Not equal, not less, not NaN, must be greater.
__ li(v0, Operand(GREATER));
__ Ret();
__ bind(&equal);
__ li(v0, Operand(EQUAL));
__ Ret();
__ bind(&less_than);
__ li(v0, Operand(LESS));
__ Ret();
}
}
static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
Register lhs,
Register rhs) {
......@@ -1516,21 +1089,9 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
// Both are heap numbers. Load them up then jump to the code we have
// for that.
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
__ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
__ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
} else {
__ lw(a2, FieldMemOperand(lhs, HeapNumber::kValueOffset));
__ lw(a3, FieldMemOperand(lhs, HeapNumber::kValueOffset + 4));
if (rhs.is(a0)) {
__ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
__ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
} else {
__ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
__ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
}
}
__ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
__ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
__ jmp(both_loaded_as_doubles);
}
......@@ -1611,42 +1172,34 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
Label load_result_from_cache;
if (!object_is_smi) {
__ JumpIfSmi(object, &is_smi);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
__ CheckMap(object,
scratch1,
Heap::kHeapNumberMapRootIndex,
not_found,
DONT_DO_SMI_CHECK);
STATIC_ASSERT(8 == kDoubleSize);
__ Addu(scratch1,
object,
Operand(HeapNumber::kValueOffset - kHeapObjectTag));
__ lw(scratch2, MemOperand(scratch1, kPointerSize));
__ lw(scratch1, MemOperand(scratch1, 0));
__ Xor(scratch1, scratch1, Operand(scratch2));
__ And(scratch1, scratch1, Operand(mask));
// Calculate address of entry in string cache: each entry consists
// of two pointer sized fields.
__ sll(scratch1, scratch1, kPointerSizeLog2 + 1);
__ Addu(scratch1, number_string_cache, scratch1);
Register probe = mask;
__ lw(probe,
FieldMemOperand(scratch1, FixedArray::kHeaderSize));
__ JumpIfSmi(probe, not_found);
__ ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset));
__ ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset));
__ BranchF(&load_result_from_cache, NULL, eq, f12, f14);
__ Branch(not_found);
} else {
// Note that there is no cache check for non-FPU case, even though
// it seems there could be. May be a tiny opimization for non-FPU
// cores.
__ Branch(not_found);
}
__ CheckMap(object,
scratch1,
Heap::kHeapNumberMapRootIndex,
not_found,
DONT_DO_SMI_CHECK);
STATIC_ASSERT(8 == kDoubleSize);
__ Addu(scratch1,
object,
Operand(HeapNumber::kValueOffset - kHeapObjectTag));
__ lw(scratch2, MemOperand(scratch1, kPointerSize));
__ lw(scratch1, MemOperand(scratch1, 0));
__ Xor(scratch1, scratch1, Operand(scratch2));
__ And(scratch1, scratch1, Operand(mask));
// Calculate address of entry in string cache: each entry consists
// of two pointer sized fields.
__ sll(scratch1, scratch1, kPointerSizeLog2 + 1);
__ Addu(scratch1, number_string_cache, scratch1);
Register probe = mask;
__ lw(probe,
FieldMemOperand(scratch1, FixedArray::kHeaderSize));
__ JumpIfSmi(probe, not_found);
__ ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset));
__ ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset));
__ BranchF(&load_result_from_cache, NULL, eq, f12, f14);
__ Branch(not_found);
}
__ bind(&is_smi);
......@@ -1764,49 +1317,38 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
// left hand side and a0, a1 represent right hand side.
Isolate* isolate = masm->isolate();
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
Label nan;
__ li(t0, Operand(LESS));
__ li(t1, Operand(GREATER));
__ li(t2, Operand(EQUAL));
// Check if either rhs or lhs is NaN.
__ BranchF(NULL, &nan, eq, f12, f14);
// Check if LESS condition is satisfied. If true, move conditionally
// result to v0.
__ c(OLT, D, f12, f14);
__ Movt(v0, t0);
// Use previous check to store conditionally to v0 oposite condition
// (GREATER). If rhs is equal to lhs, this will be corrected in next
// check.
__ Movf(v0, t1);
// Check if EQUAL condition is satisfied. If true, move conditionally
// result to v0.
__ c(EQ, D, f12, f14);
__ Movt(v0, t2);
Label nan;
__ li(t0, Operand(LESS));
__ li(t1, Operand(GREATER));
__ li(t2, Operand(EQUAL));
// Check if either rhs or lhs is NaN.
__ BranchF(NULL, &nan, eq, f12, f14);
// Check if LESS condition is satisfied. If true, move conditionally
// result to v0.
__ c(OLT, D, f12, f14);
__ Movt(v0, t0);
// Use previous check to store conditionally to v0 oposite condition
// (GREATER). If rhs is equal to lhs, this will be corrected in next
// check.
__ Movf(v0, t1);
// Check if EQUAL condition is satisfied. If true, move conditionally
// result to v0.
__ c(EQ, D, f12, f14);
__ Movt(v0, t2);
__ Ret();
__ Ret();
__ bind(&nan);
// NaN comparisons always fail.
// Load whatever we need in v0 to make the comparison fail.
if (cc == lt || cc == le) {
__ li(v0, Operand(GREATER));
} else {
__ li(v0, Operand(LESS));
}
__ Ret();
__ bind(&nan);
// NaN comparisons always fail.
// Load whatever we need in v0 to make the comparison fail.
if (cc == lt || cc == le) {
__ li(v0, Operand(GREATER));
} else {
// Checks for NaN in the doubles we have loaded. Can return the answer or
// fall through if neither is a NaN. Also binds rhs_not_nan.
EmitNanCheck(masm, cc);
// Compares two doubles that are not NaNs. Returns the answer.
// Never falls through.
EmitTwoNonNanDoubleComparison(masm, cc);
__ li(v0, Operand(LESS));
}
__ Ret();
__ bind(&not_smis);
// At this point we know we are dealing with two different objects,
......@@ -1899,9 +1441,6 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
// The stub expects its argument in the tos_ register and returns its result in
// it, too: zero for false, and a non-zero value for true.
void ToBooleanStub::Generate(MacroAssembler* masm) {
// This stub uses FPU instructions.
CpuFeatureScope scope(masm, FPU);
Label patch;
const Register map = t5.is(tos_) ? t3 : t5;
......@@ -2015,7 +1554,6 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
// restore them.
__ MultiPush(kJSCallerSaved | ra.bit());
if (save_doubles_ == kSaveFPRegs) {
CpuFeatureScope scope(masm, FPU);
__ MultiPushFPU(kCallerSavedFPU);
}
const int argument_count = 1;
......@@ -2029,7 +1567,6 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
ExternalReference::store_buffer_overflow_function(masm->isolate()),
argument_count);
if (save_doubles_ == kSaveFPRegs) {
CpuFeatureScope scope(masm, FPU);
__ MultiPopFPU(kCallerSavedFPU);
}
......@@ -2260,19 +1797,11 @@ void UnaryOpStub::GenerateHeapNumberCodeBitNot(
__ mov(v0, a2); // Move newly allocated heap number to v0.
}
if (CpuFeatures::IsSupported(FPU)) {
// Convert the int32 in a1 to the heap number in v0. a2 is corrupted.
CpuFeatureScope scope(masm, FPU);
__ mtc1(a1, f0);
__ cvt_d_w(f0, f0);
__ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
__ Ret();
} else {
// WriteInt32ToHeapNumberStub does not trigger GC, so we do not
// have to set up a frame.
WriteInt32ToHeapNumberStub stub(a1, v0, a2, a3);
__ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
}
// Convert the int32 in a1 to the heap number in v0. a2 is corrupted.
__ mtc1(a1, f0);
__ cvt_d_w(f0, f0);
__ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
__ Ret();
__ bind(&impossible);
if (FLAG_debug_code) {
......@@ -2334,7 +1863,7 @@ void UnaryOpStub::GenerateGenericCodeFallback(
void BinaryOpStub::Initialize() {
platform_specific_bit_ = CpuFeatures::IsSupported(FPU);
platform_specific_bit_ = true; // FPU is a base requirement for V8.
}
......@@ -2561,9 +2090,8 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
case Token::DIV:
case Token::MOD: {
// Load left and right operands into f12 and f14 or a0/a1 and a2/a3
// depending on whether FPU is available or not.
// depending on operation.
FloatingPointHelper::Destination destination =
CpuFeatures::IsSupported(FPU) &&
op != Token::MOD ?
FloatingPointHelper::kFPURegisters :
FloatingPointHelper::kCoreRegisters;
......@@ -2607,7 +2135,6 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
// Using FPU registers:
// f12: Left value.
// f14: Right value.
CpuFeatureScope scope(masm, FPU);
switch (op) {
case Token::ADD:
__ add_d(f10, f12, f14);
......@@ -2697,11 +2224,7 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
// The code below for writing into heap numbers isn't capable of
// writing the register as an unsigned int so we go to slow case if we
// hit this case.
if (CpuFeatures::IsSupported(FPU)) {
__ Branch(&result_not_a_smi, lt, a2, Operand(zero_reg));
} else {
__ Branch(not_numbers, lt, a2, Operand(zero_reg));
}
__ Branch(&result_not_a_smi, lt, a2, Operand(zero_reg));
break;
case Token::SHL:
// Use only the 5 least significant bits of the shift count.
......@@ -2735,28 +2258,19 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
// Nothing can go wrong now, so move the heap number to v0, which is the
// result.
__ mov(v0, t1);
if (CpuFeatures::IsSupported(FPU)) {
// Convert the int32 in a2 to the heap number in a0. As
// mentioned above SHR needs to always produce a positive result.
CpuFeatureScope scope(masm, FPU);
__ mtc1(a2, f0);
if (op == Token::SHR) {
__ Cvt_d_uw(f0, f0, f22);
} else {
__ cvt_d_w(f0, f0);
}
// ARM uses a workaround here because of the unaligned HeapNumber
// kValueOffset. On MIPS this workaround is built into sdc1 so
// there's no point in generating even more instructions.
__ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
__ Ret();
// Convert the int32 in a2 to the heap number in a0. As
// mentioned above SHR needs to always produce a positive result.
__ mtc1(a2, f0);
if (op == Token::SHR) {
__ Cvt_d_uw(f0, f0, f22);
} else {
// Tail call that writes the int32 in a2 to the heap number in v0, using
// a3 and a0 as scratch. v0 is preserved and returned.
WriteInt32ToHeapNumberStub stub(a2, v0, a3, a0);
__ TailCallStub(&stub);
__ cvt_d_w(f0, f0);
}
// ARM uses a workaround here because of the unaligned HeapNumber
// kValueOffset. On MIPS this workaround is built into sdc1 so
// there's no point in generating even more instructions.
__ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
__ Ret();
break;
}
default:
......@@ -2903,8 +2417,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
// Load both operands and check that they are 32-bit integer.
// Jump to type transition if they are not. The registers a0 and a1 (right
// and left) are preserved for the runtime call.
FloatingPointHelper::Destination destination =
(CpuFeatures::IsSupported(FPU) && op_ != Token::MOD)
FloatingPointHelper::Destination destination = (op_ != Token::MOD)
? FloatingPointHelper::kFPURegisters
: FloatingPointHelper::kCoreRegisters;
......@@ -2934,7 +2447,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
&transition);
if (destination == FloatingPointHelper::kFPURegisters) {
CpuFeatureScope scope(masm, FPU);
Label return_heap_number;
switch (op_) {
case Token::ADD:
......@@ -3103,23 +2615,12 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
// We only get a negative result if the shift value (a2) is 0.
// This result cannot be respresented as a signed 32-bit integer, try
// to return a heap number if we can.
// The non FPU code does not support this special case, so jump to
// runtime if we don't support it.
if (CpuFeatures::IsSupported(FPU)) {
__ Branch((result_type_ <= BinaryOpIC::INT32)
? &transition
: &return_heap_number,
lt,
a2,
Operand(zero_reg));
} else {
__ Branch((result_type_ <= BinaryOpIC::INT32)
? &transition
: &call_runtime,
lt,
a2,
Operand(zero_reg));
}
__ Branch((result_type_ <= BinaryOpIC::INT32)
? &transition
: &return_heap_number,
lt,
a2,
Operand(zero_reg));
break;
case Token::SHL:
__ And(a2, a2, Operand(0x1f));
......@@ -3147,31 +2648,21 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
&call_runtime,
mode_);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
if (op_ != Token::SHR) {
// Convert the result to a floating point value.
__ mtc1(a2, double_scratch);
__ cvt_d_w(double_scratch, double_scratch);
} else {
// The result must be interpreted as an unsigned 32-bit integer.
__ mtc1(a2, double_scratch);
__ Cvt_d_uw(double_scratch, double_scratch, single_scratch);
}
// Store the result.
__ mov(v0, heap_number_result);
__ sdc1(double_scratch, FieldMemOperand(v0, HeapNumber::kValueOffset));
__ Ret();
if (op_ != Token::SHR) {
// Convert the result to a floating point value.
__ mtc1(a2, double_scratch);
__ cvt_d_w(double_scratch, double_scratch);
} else {
// Tail call that writes the int32 in a2 to the heap number in v0, using
// a3 and a0 as scratch. v0 is preserved and returned.
__ mov(v0, t1);
WriteInt32ToHeapNumberStub stub(a2, v0, a3, a0);
__ TailCallStub(&stub);
// The result must be interpreted as an unsigned 32-bit integer.
__ mtc1(a2, double_scratch);
__ Cvt_d_uw(double_scratch, double_scratch, single_scratch);
}
// Store the result.
__ mov(v0, heap_number_result);
__ sdc1(double_scratch, FieldMemOperand(v0, HeapNumber::kValueOffset));
__ Ret();
break;
}
......@@ -3351,107 +2842,102 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
const Register cache_entry = a0;
const bool tagged = (argument_type_ == TAGGED);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
if (tagged) {
// Argument is a number and is on stack and in a0.
// Load argument and check if it is a smi.
__ JumpIfNotSmi(a0, &input_not_smi);
// Input is a smi. Convert to double and load the low and high words
// of the double into a2, a3.
__ sra(t0, a0, kSmiTagSize);
__ mtc1(t0, f4);
__ cvt_d_w(f4, f4);
__ Move(a2, a3, f4);
__ Branch(&loaded);
__ bind(&input_not_smi);
// Check if input is a HeapNumber.
__ CheckMap(a0,
a1,
Heap::kHeapNumberMapRootIndex,
&calculate,
DONT_DO_SMI_CHECK);
// Input is a HeapNumber. Store the
// low and high words into a2, a3.
__ lw(a2, FieldMemOperand(a0, HeapNumber::kValueOffset));
__ lw(a3, FieldMemOperand(a0, HeapNumber::kValueOffset + 4));
} else {
// Input is untagged double in f4. Output goes to f4.
__ Move(a2, a3, f4);
}
__ bind(&loaded);
// a2 = low 32 bits of double value.
// a3 = high 32 bits of double value.
// Compute hash (the shifts are arithmetic):
// h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
__ Xor(a1, a2, a3);
__ sra(t0, a1, 16);
__ Xor(a1, a1, t0);
__ sra(t0, a1, 8);
__ Xor(a1, a1, t0);
ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
__ And(a1, a1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
// a2 = low 32 bits of double value.
// a3 = high 32 bits of double value.
// a1 = TranscendentalCache::hash(double value).
__ li(cache_entry, Operand(
ExternalReference::transcendental_cache_array_address(
masm->isolate())));
// a0 points to cache array.
__ lw(cache_entry, MemOperand(cache_entry, type_ * sizeof(
Isolate::Current()->transcendental_cache()->caches_[0])));
// a0 points to the cache for the type type_.
// If NULL, the cache hasn't been initialized yet, so go through runtime.
__ Branch(&invalid_cache, eq, cache_entry, Operand(zero_reg));
if (tagged) {
// Argument is a number and is on stack and in a0.
// Load argument and check if it is a smi.
__ JumpIfNotSmi(a0, &input_not_smi);
// Input is a smi. Convert to double and load the low and high words
// of the double into a2, a3.
__ sra(t0, a0, kSmiTagSize);
__ mtc1(t0, f4);
__ cvt_d_w(f4, f4);
__ Move(a2, a3, f4);
__ Branch(&loaded);
__ bind(&input_not_smi);
// Check if input is a HeapNumber.
__ CheckMap(a0,
a1,
Heap::kHeapNumberMapRootIndex,
&calculate,
DONT_DO_SMI_CHECK);
// Input is a HeapNumber. Store the
// low and high words into a2, a3.
__ lw(a2, FieldMemOperand(a0, HeapNumber::kValueOffset));
__ lw(a3, FieldMemOperand(a0, HeapNumber::kValueOffset + 4));
} else {
// Input is untagged double in f4. Output goes to f4.
__ Move(a2, a3, f4);
}
__ bind(&loaded);
// a2 = low 32 bits of double value.
// a3 = high 32 bits of double value.
// Compute hash (the shifts are arithmetic):
// h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
__ Xor(a1, a2, a3);
__ sra(t0, a1, 16);
__ Xor(a1, a1, t0);
__ sra(t0, a1, 8);
__ Xor(a1, a1, t0);
ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
__ And(a1, a1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
// a2 = low 32 bits of double value.
// a3 = high 32 bits of double value.
// a1 = TranscendentalCache::hash(double value).
__ li(cache_entry, Operand(
ExternalReference::transcendental_cache_array_address(
masm->isolate())));
// a0 points to cache array.
__ lw(cache_entry, MemOperand(cache_entry, type_ * sizeof(
Isolate::Current()->transcendental_cache()->caches_[0])));
// a0 points to the cache for the type type_.
// If NULL, the cache hasn't been initialized yet, so go through runtime.
__ Branch(&invalid_cache, eq, cache_entry, Operand(zero_reg));
#ifdef DEBUG
// Check that the layout of cache elements match expectations.
{ TranscendentalCache::SubCache::Element test_elem[2];
char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
CHECK_EQ(0, elem_in0 - elem_start);
CHECK_EQ(kIntSize, elem_in1 - elem_start);
CHECK_EQ(2 * kIntSize, elem_out - elem_start);
}
// Check that the layout of cache elements match expectations.
{ TranscendentalCache::SubCache::Element test_elem[2];
char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
CHECK_EQ(0, elem_in0 - elem_start);
CHECK_EQ(kIntSize, elem_in1 - elem_start);
CHECK_EQ(2 * kIntSize, elem_out - elem_start);
}
#endif
// Find the address of the a1'st entry in the cache, i.e., &a0[a1*12].
__ sll(t0, a1, 1);
__ Addu(a1, a1, t0);
__ sll(t0, a1, 2);
__ Addu(cache_entry, cache_entry, t0);
// Check if cache matches: Double value is stored in uint32_t[2] array.
__ lw(t0, MemOperand(cache_entry, 0));
__ lw(t1, MemOperand(cache_entry, 4));
__ lw(t2, MemOperand(cache_entry, 8));
__ Branch(&calculate, ne, a2, Operand(t0));
__ Branch(&calculate, ne, a3, Operand(t1));
// Cache hit. Load result, cleanup and return.
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(
counters->transcendental_cache_hit(), 1, scratch0, scratch1);
if (tagged) {
// Pop input value from stack and load result into v0.
__ Drop(1);
__ mov(v0, t2);
} else {
// Load result into f4.
__ ldc1(f4, FieldMemOperand(t2, HeapNumber::kValueOffset));
}
__ Ret();
} // if (CpuFeatures::IsSupported(FPU))
// Find the address of the a1'st entry in the cache, i.e., &a0[a1*12].
__ sll(t0, a1, 1);
__ Addu(a1, a1, t0);
__ sll(t0, a1, 2);
__ Addu(cache_entry, cache_entry, t0);
// Check if cache matches: Double value is stored in uint32_t[2] array.
__ lw(t0, MemOperand(cache_entry, 0));
__ lw(t1, MemOperand(cache_entry, 4));
__ lw(t2, MemOperand(cache_entry, 8));
__ Branch(&calculate, ne, a2, Operand(t0));
__ Branch(&calculate, ne, a3, Operand(t1));
// Cache hit. Load result, cleanup and return.
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(
counters->transcendental_cache_hit(), 1, scratch0, scratch1);
if (tagged) {
// Pop input value from stack and load result into v0.
__ Drop(1);
__ mov(v0, t2);
} else {
// Load result into f4.
__ ldc1(f4, FieldMemOperand(t2, HeapNumber::kValueOffset));
}
__ Ret();
__ bind(&calculate);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(
counters->transcendental_cache_miss(), 1, scratch0, scratch1);
if (tagged) {
......@@ -3461,9 +2947,6 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
1,
1);
} else {
ASSERT(CpuFeatures::IsSupported(FPU));
CpuFeatureScope scope(masm, FPU);
Label no_update;
Label skip_cache;
......@@ -3590,7 +3073,6 @@ void InterruptStub::Generate(MacroAssembler* masm) {
void MathPowStub::Generate(MacroAssembler* masm) {
CpuFeatureScope fpu_scope(masm, FPU);
const Register base = a1;
const Register exponent = a2;
const Register heapnumbermap = t1;
......@@ -3826,9 +3308,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
void CodeStub::GenerateFPStubs(Isolate* isolate) {
SaveFPRegsMode mode = CpuFeatures::IsSupported(FPU)
? kSaveFPRegs
: kDontSaveFPRegs;
SaveFPRegsMode mode = kSaveFPRegs;
CEntryStub save_doubles(1, mode);
StoreBufferOverflowStub stub(mode);
// These stubs might already be in the snapshot, detect that and don't
......@@ -4099,20 +3579,15 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Save callee saved registers on the stack.
__ MultiPush(kCalleeSaved | ra.bit());
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
// Save callee-saved FPU registers.
__ MultiPushFPU(kCalleeSavedFPU);
// Set up the reserved register for 0.0.
__ Move(kDoubleRegZero, 0.0);
}
// Save callee-saved FPU registers.
__ MultiPushFPU(kCalleeSavedFPU);
// Set up the reserved register for 0.0.
__ Move(kDoubleRegZero, 0.0);
// Load argv in s0 register.
int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
if (CpuFeatures::IsSupported(FPU)) {
offset_to_argv += kNumCalleeSavedFPU * kDoubleSize;
}
offset_to_argv += kNumCalleeSavedFPU * kDoubleSize;
__ InitializeRootRegister();
__ lw(s0, MemOperand(sp, offset_to_argv + kCArgsSlotsSize));
......@@ -4248,11 +3723,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Reset the stack to the callee saved registers.
__ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
// Restore callee-saved fpu registers.
__ MultiPopFPU(kCalleeSavedFPU);
}
// Restore callee-saved fpu registers.
__ MultiPopFPU(kCalleeSavedFPU);
// Restore callee saved registers from the stack.
__ MultiPop(kCalleeSaved | ra.bit());
......@@ -6991,59 +6463,55 @@ void ICCompareStub::GenerateNumbers(MacroAssembler* masm) {
}
// Inlining the double comparison and falling back to the general compare
// stub if NaN is involved or FPU is unsupported.
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
// Load left and right operand.
Label done, left, left_smi, right_smi;
__ JumpIfSmi(a0, &right_smi);
__ CheckMap(a0, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
DONT_DO_SMI_CHECK);
__ Subu(a2, a0, Operand(kHeapObjectTag));
__ ldc1(f2, MemOperand(a2, HeapNumber::kValueOffset));
__ Branch(&left);
__ bind(&right_smi);
__ SmiUntag(a2, a0); // Can't clobber a0 yet.
FPURegister single_scratch = f6;
__ mtc1(a2, single_scratch);
__ cvt_d_w(f2, single_scratch);
__ bind(&left);
__ JumpIfSmi(a1, &left_smi);
__ CheckMap(a1, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
DONT_DO_SMI_CHECK);
__ Subu(a2, a1, Operand(kHeapObjectTag));
__ ldc1(f0, MemOperand(a2, HeapNumber::kValueOffset));
__ Branch(&done);
__ bind(&left_smi);
__ SmiUntag(a2, a1); // Can't clobber a1 yet.
single_scratch = f8;
__ mtc1(a2, single_scratch);
__ cvt_d_w(f0, single_scratch);
// stub if NaN is involved.
// Load left and right operand.
Label done, left, left_smi, right_smi;
__ JumpIfSmi(a0, &right_smi);
__ CheckMap(a0, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
DONT_DO_SMI_CHECK);
__ Subu(a2, a0, Operand(kHeapObjectTag));
__ ldc1(f2, MemOperand(a2, HeapNumber::kValueOffset));
__ Branch(&left);
__ bind(&right_smi);
__ SmiUntag(a2, a0); // Can't clobber a0 yet.
FPURegister single_scratch = f6;
__ mtc1(a2, single_scratch);
__ cvt_d_w(f2, single_scratch);
__ bind(&done);
__ bind(&left);
__ JumpIfSmi(a1, &left_smi);
__ CheckMap(a1, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
DONT_DO_SMI_CHECK);
__ Subu(a2, a1, Operand(kHeapObjectTag));
__ ldc1(f0, MemOperand(a2, HeapNumber::kValueOffset));
__ Branch(&done);
__ bind(&left_smi);
__ SmiUntag(a2, a1); // Can't clobber a1 yet.
single_scratch = f8;
__ mtc1(a2, single_scratch);
__ cvt_d_w(f0, single_scratch);
// Return a result of -1, 0, or 1, or use CompareStub for NaNs.
Label fpu_eq, fpu_lt;
// Test if equal, and also handle the unordered/NaN case.
__ BranchF(&fpu_eq, &unordered, eq, f0, f2);
__ bind(&done);
// Test if less (unordered case is already handled).
__ BranchF(&fpu_lt, NULL, lt, f0, f2);
// Return a result of -1, 0, or 1, or use CompareStub for NaNs.
Label fpu_eq, fpu_lt;
// Test if equal, and also handle the unordered/NaN case.
__ BranchF(&fpu_eq, &unordered, eq, f0, f2);
// Otherwise it's greater, so just fall thru, and return.
__ li(v0, Operand(GREATER));
__ Ret();
// Test if less (unordered case is already handled).
__ BranchF(&fpu_lt, NULL, lt, f0, f2);
__ bind(&fpu_eq);
__ li(v0, Operand(EQUAL));
__ Ret();
// Otherwise it's greater, so just fall thru, and return.
__ li(v0, Operand(GREATER));
__ Ret();
__ bind(&fpu_lt);
__ li(v0, Operand(LESS));
__ Ret();
}
__ bind(&fpu_eq);
__ li(v0, Operand(EQUAL));
__ Ret();
__ bind(&fpu_lt);
__ li(v0, Operand(LESS));
__ Ret();
__ bind(&unordered);
__ bind(&generic_stub);
......@@ -7706,7 +7174,7 @@ void RecordWriteStub::GenerateFixedRegStubsAheadOfTime(Isolate* isolate) {
bool CodeStub::CanUseFPRegisters() {
return CpuFeatures::IsSupported(FPU);
return true; // FPU is a base requirement for V8.
}
......
......@@ -62,9 +62,7 @@ class TranscendentalCacheStub: public PlatformCodeStub {
class StoreBufferOverflowStub: public PlatformCodeStub {
public:
explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
: save_doubles_(save_fp) {
ASSERT(CpuFeatures::IsSafeForSnapshot(FPU) || save_fp == kDontSaveFPRegs);
}
: save_doubles_(save_fp) {}
void Generate(MacroAssembler* masm);
......@@ -486,7 +484,6 @@ class RecordWriteStub: public PlatformCodeStub {
void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
if (mode == kSaveFPRegs) {
CpuFeatureScope scope(masm, FPU);
masm->MultiPushFPU(kCallerSavedFPU);
}
}
......@@ -494,7 +491,6 @@ class RecordWriteStub: public PlatformCodeStub {
inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
SaveFPRegsMode mode) {
if (mode == kSaveFPRegs) {
CpuFeatureScope scope(masm, FPU);
masm->MultiPopFPU(kCallerSavedFPU);
}
masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
......@@ -685,27 +681,6 @@ class FloatingPointHelper : public AllStatic {
FPURegister double_scratch1,
Label* not_int32);
// Generate non FPU code to check if a double can be exactly represented by a
// 32-bit integer. This does not check for 0 or -0, which need
// to be checked for separately.
// Control jumps to not_int32 if the value is not a 32-bit integer, and falls
// through otherwise.
// src1 and src2 will be cloberred.
//
// Expected input:
// - src1: higher (exponent) part of the double value.
// - src2: lower (mantissa) part of the double value.
// Output status:
// - dst: 32 higher bits of the mantissa. (mantissa[51:20])
// - src2: contains 1.
// - other registers are clobbered.
static void DoubleIs32BitInteger(MacroAssembler* masm,
Register src1,
Register src2,
Register dst,
Register scratch,
Label* not_int32);
// Generates code to call a C function to do a double operation using core
// registers. (Used when FPU is not supported.)
// This code never falls through, but returns with a heap number containing
......
......@@ -62,7 +62,6 @@ double fast_exp_simulator(double x) {
UnaryMathFunction CreateExpFunction() {
if (!CpuFeatures::IsSupported(FPU)) return &exp;
if (!FLAG_fast_math) return &exp;
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
......@@ -72,7 +71,6 @@ UnaryMathFunction CreateExpFunction() {
MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
{
CpuFeatureScope use_fpu(&masm, FPU);
DoubleRegister input = f12;
DoubleRegister result = f0;
DoubleRegister double_scratch1 = f4;
......@@ -184,7 +182,6 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
// -- t0 : scratch (elements)
// -----------------------------------
Label loop, entry, convert_hole, gc_required, only_change_map, done;
bool fpu_supported = CpuFeatures::IsSupported(FPU);
Register scratch = t6;
......@@ -249,8 +246,6 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
// t2: end of destination FixedDoubleArray, not tagged
// t3: begin of FixedDoubleArray element fields, not tagged
if (!fpu_supported) __ Push(a1, a0);
__ Branch(&entry);
__ bind(&only_change_map);
......@@ -278,25 +273,11 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
__ UntagAndJumpIfNotSmi(t5, t5, &convert_hole);
// Normal smi, convert to double and store.
if (fpu_supported) {
CpuFeatureScope scope(masm, FPU);
__ mtc1(t5, f0);
__ cvt_d_w(f0, f0);
__ sdc1(f0, MemOperand(t3));
__ Addu(t3, t3, kDoubleSize);
} else {
FloatingPointHelper::ConvertIntToDouble(masm,
t5,
FloatingPointHelper::kCoreRegisters,
f0,
a0,
a1,
t7,
f0);
__ sw(a0, MemOperand(t3)); // mantissa
__ sw(a1, MemOperand(t3, kIntSize)); // exponent
__ Addu(t3, t3, kDoubleSize);
}
__ mtc1(t5, f0);
__ cvt_d_w(f0, f0);
__ sdc1(f0, MemOperand(t3));
__ Addu(t3, t3, kDoubleSize);
__ Branch(&entry);
// Hole found, store the-hole NaN.
......@@ -315,7 +296,6 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
__ bind(&entry);
__ Branch(&loop, lt, t3, Operand(t2));
if (!fpu_supported) __ Pop(a1, a0);
__ pop(ra);
__ bind(&done);
}
......
......@@ -61,8 +61,9 @@ enum ArchVariants {
// -mhard-float is passed to the compiler.
const bool IsMipsSoftFloatABI = false;
#elif(defined(__mips_soft_float) && __mips_soft_float != 0)
// Not using floating-point coprocessor instructions. This flag is raised when
// -msoft-float is passed to the compiler.
// This flag is raised when -msoft-float is passed to the compiler.
// Although FPU is a base requirement for v8, soft-float ABI is used
// on soft-float systems with FPU kernel emulation.
const bool IsMipsSoftFloatABI = true;
#else
const bool IsMipsSoftFloatABI = true;
......
......@@ -603,17 +603,12 @@ void Deoptimizer::EntryGenerator::Generate() {
const int kDoubleRegsSize =
kDoubleSize * FPURegister::kMaxNumAllocatableRegisters;
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
// Save all FPU registers before messing with them.
__ Subu(sp, sp, Operand(kDoubleRegsSize));
for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
int offset = i * kDoubleSize;
__ sdc1(fpu_reg, MemOperand(sp, offset));
}
} else {
__ Subu(sp, sp, Operand(kDoubleRegsSize));
// Save all FPU registers before messing with them.
__ Subu(sp, sp, Operand(kDoubleRegsSize));
for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
int offset = i * kDoubleSize;
__ sdc1(fpu_reg, MemOperand(sp, offset));
}
// Push saved_regs (needed to populate FrameDescription::registers_).
......@@ -686,16 +681,13 @@ void Deoptimizer::EntryGenerator::Generate() {
}
int double_regs_offset = FrameDescription::double_registers_offset();
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
// Copy FPU registers to
// double_registers_[DoubleRegister::kNumAllocatableRegisters]
for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) {
int dst_offset = i * kDoubleSize + double_regs_offset;
int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
__ ldc1(f0, MemOperand(sp, src_offset));
__ sdc1(f0, MemOperand(a1, dst_offset));
}
// Copy FPU registers to
// double_registers_[DoubleRegister::kNumAllocatableRegisters]
for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) {
int dst_offset = i * kDoubleSize + double_regs_offset;
int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
__ ldc1(f0, MemOperand(sp, src_offset));
__ sdc1(f0, MemOperand(a1, dst_offset));
}
// Remove the bailout id, eventually return address, and the saved registers
......@@ -764,15 +756,11 @@ void Deoptimizer::EntryGenerator::Generate() {
__ bind(&outer_loop_header);
__ Branch(&outer_push_loop, lt, t0, Operand(a1));
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
__ lw(a1, MemOperand(a0, Deoptimizer::input_offset()));
for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
const FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
int src_offset = i * kDoubleSize + double_regs_offset;
__ ldc1(fpu_reg, MemOperand(a1, src_offset));
}
__ lw(a1, MemOperand(a0, Deoptimizer::input_offset()));
for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
const FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
int src_offset = i * kDoubleSize + double_regs_offset;
__ ldc1(fpu_reg, MemOperand(a1, src_offset));
}
// Push state, pc, and continuation from the last output frame.
......
......@@ -674,17 +674,9 @@ void FullCodeGenerator::DoTest(Expression* condition,
Label* if_true,
Label* if_false,
Label* fall_through) {
if (CpuFeatures::IsSupported(FPU)) {
ToBooleanStub stub(result_register());
__ CallStub(&stub, condition->test_id());
__ mov(at, zero_reg);
} else {
// Call the runtime to find the boolean value of the source and then
// translate it into control flow to the pair of labels.
__ push(result_register());
__ CallRuntime(Runtime::kToBool, 1);
__ LoadRoot(at, Heap::kFalseValueRootIndex);
}
ToBooleanStub stub(result_register());
__ CallStub(&stub, condition->test_id());
__ mov(at, zero_reg);
Split(ne, v0, Operand(at), if_true, if_false, fall_through);
}
......@@ -3045,31 +3037,21 @@ void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
// Convert 32 random bits in v0 to 0.(32 random bits) in a double
// by computing:
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
if (CpuFeatures::IsSupported(FPU)) {
__ PrepareCallCFunction(1, a0);
__ lw(a0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
__ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset));
__ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
CpuFeatureScope scope(masm(), FPU);
// 0x41300000 is the top half of 1.0 x 2^20 as a double.
__ li(a1, Operand(0x41300000));
// Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
__ Move(f12, v0, a1);
// Move 0x4130000000000000 to FPU.
__ Move(f14, zero_reg, a1);
// Subtract and store the result in the heap number.
__ sub_d(f0, f12, f14);
__ sdc1(f0, FieldMemOperand(s0, HeapNumber::kValueOffset));
__ mov(v0, s0);
} else {
__ PrepareCallCFunction(2, a0);
__ mov(a0, s0);
__ lw(a1, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
__ lw(a1, FieldMemOperand(a1, GlobalObject::kNativeContextOffset));
__ CallCFunction(
ExternalReference::fill_heap_number_with_random_function(isolate()), 2);
}
__ PrepareCallCFunction(1, a0);
__ lw(a0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
__ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset));
__ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
// 0x41300000 is the top half of 1.0 x 2^20 as a double.
__ li(a1, Operand(0x41300000));
// Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
__ Move(f12, v0, a1);
// Move 0x4130000000000000 to FPU.
__ Move(f14, zero_reg, a1);
// Subtract and store the result in the heap number.
__ sub_d(f0, f12, f14);
__ sdc1(f0, FieldMemOperand(s0, HeapNumber::kValueOffset));
__ mov(v0, s0);
context()->Plug(v0);
}
......@@ -3207,12 +3189,8 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
ASSERT(args->length() == 2);
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
if (CpuFeatures::IsSupported(FPU)) {
MathPowStub stub(MathPowStub::ON_STACK);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kMath_pow, 2);
}
MathPowStub stub(MathPowStub::ON_STACK);
__ CallStub(&stub);
context()->Plug(v0);
}
......
......@@ -192,8 +192,7 @@ bool LCodeGen::GeneratePrologue() {
}
}
if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
if (info()->saves_caller_doubles()) {
Comment(";;; Save clobbered callee double registers");
int count = 0;
BitVector* doubles = chunk()->allocated_double_registers();
......@@ -1214,7 +1213,6 @@ void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) {
// This is computed in-place.
ASSERT(addend.is(ToDoubleRegister(instr->result())));
CpuFeatureScope scope(masm(), FPU);
__ madd_d(addend, addend, multiplier, multiplicand);
}
......@@ -1477,7 +1475,6 @@ void LCodeGen::DoConstantI(LConstantI* instr) {
void LCodeGen::DoConstantD(LConstantD* instr) {
ASSERT(instr->result()->IsDoubleRegister());
DoubleRegister result = ToDoubleRegister(instr->result());
CpuFeatureScope scope(masm(), FPU);
double v = instr->value();
__ Move(result, v);
}
......@@ -1668,7 +1665,6 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
__ bind(&done);
} else {
ASSERT(instr->hydrogen()->representation().IsDouble());
CpuFeatureScope scope(masm(), FPU);
FPURegister left_reg = ToDoubleRegister(left);
FPURegister right_reg = ToDoubleRegister(right);
FPURegister result_reg = ToDoubleRegister(instr->result());
......@@ -1709,7 +1705,6 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
CpuFeatureScope scope(masm(), FPU);
DoubleRegister left = ToDoubleRegister(instr->left());
DoubleRegister right = ToDoubleRegister(instr->right());
DoubleRegister result = ToDoubleRegister(instr->result());
......@@ -1819,7 +1814,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
Register reg = ToRegister(instr->value());
EmitBranch(true_block, false_block, ne, reg, Operand(zero_reg));
} else if (r.IsDouble()) {
CpuFeatureScope scope(masm(), FPU);
DoubleRegister reg = ToDoubleRegister(instr->value());
// Test the double value. Zero and NaN are false.
EmitBranchF(true_block, false_block, nue, reg, kDoubleRegZero);
......@@ -1904,7 +1898,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
CpuFeatureScope scope(masm(), FPU);
// heap number -> false iff +0, -0, or NaN.
DoubleRegister dbl_scratch = double_scratch0();
Label not_heap_number;
......@@ -1984,7 +1977,6 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
EmitGoto(next_block);
} else {
if (instr->is_double()) {
CpuFeatureScope scope(masm(), FPU);
// Compare left and right as doubles and load the
// resulting flags into the normal status register.
FPURegister left_reg = ToDoubleRegister(left);
......@@ -2547,8 +2539,7 @@ void LCodeGen::DoReturn(LReturn* instr) {
__ push(v0);
__ CallRuntime(Runtime::kTraceExit, 1);
}
if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
if (info()->saves_caller_doubles()) {
ASSERT(NeedsEagerFrame());
BitVector* doubles = chunk()->allocated_double_registers();
BitVector::Iterator save_iterator(doubles);
......@@ -2935,61 +2926,11 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
__ sll(scratch0(), key, shift_size);
__ Addu(scratch0(), scratch0(), external_pointer);
}
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ lwc1(result, MemOperand(scratch0(), additional_offset));
__ cvt_d_s(result, result);
} else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
__ ldc1(result, MemOperand(scratch0(), additional_offset));
}
} else {
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
Register value = external_pointer;
__ lw(value, MemOperand(scratch0(), additional_offset));
__ And(sfpd_lo, value, Operand(kBinary32MantissaMask));
__ srl(scratch0(), value, kBinary32MantissaBits);
__ And(scratch0(), scratch0(),
Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
Label exponent_rebiased;
__ Xor(at, scratch0(), Operand(0x00));
__ Branch(&exponent_rebiased, eq, at, Operand(zero_reg));
__ Xor(at, scratch0(), Operand(0xff));
Label skip;
__ Branch(&skip, ne, at, Operand(zero_reg));
__ li(scratch0(), Operand(0x7ff));
__ bind(&skip);
__ Branch(&exponent_rebiased, eq, at, Operand(zero_reg));
// Rebias exponent.
__ Addu(scratch0(),
scratch0(),
Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
__ bind(&exponent_rebiased);
__ And(sfpd_hi, value, Operand(kBinary32SignMask));
__ sll(at, scratch0(), HeapNumber::kMantissaBitsInTopWord);
__ Or(sfpd_hi, sfpd_hi, at);
// Shift mantissa.
static const int kMantissaShiftForHiWord =
kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
static const int kMantissaShiftForLoWord =
kBitsPerInt - kMantissaShiftForHiWord;
__ srl(at, sfpd_lo, kMantissaShiftForHiWord);
__ Or(sfpd_hi, sfpd_hi, at);
__ sll(sfpd_lo, sfpd_lo, kMantissaShiftForLoWord);
} else {
__ lw(sfpd_lo, MemOperand(scratch0(), additional_offset));
__ lw(sfpd_hi, MemOperand(scratch0(),
additional_offset + kPointerSize));
}
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ lwc1(result, MemOperand(scratch0(), additional_offset));
__ cvt_d_s(result, result);
} else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
__ ldc1(result, MemOperand(scratch0(), additional_offset));
}
} else {
Register result = ToRegister(instr->result());
......@@ -3064,21 +3005,11 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
__ sll(scratch, key, shift_size);
__ Addu(elements, elements, scratch);
}
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
__ Addu(elements, elements, Operand(base_offset));
__ ldc1(result, MemOperand(elements));
if (instr->hydrogen()->RequiresHoleCheck()) {
__ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
}
} else {
__ lw(sfpd_hi, MemOperand(elements, base_offset + kPointerSize));
__ lw(sfpd_lo, MemOperand(elements, base_offset));
if (instr->hydrogen()->RequiresHoleCheck()) {
ASSERT(kPointerSize == sizeof(kHoleNanLower32));
DeoptimizeIf(eq, instr->environment(), sfpd_hi, Operand(kHoleNanUpper32));
}
__ Addu(elements, elements, Operand(base_offset));
__ ldc1(result, MemOperand(elements));
if (instr->hydrogen()->RequiresHoleCheck()) {
__ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
}
}
......@@ -3526,7 +3457,6 @@ void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
void LCodeGen::DoMathAbs(LMathAbs* instr) {
CpuFeatureScope scope(masm(), FPU);
// Class for deferred case.
class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
public:
......@@ -3562,7 +3492,6 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) {
void LCodeGen::DoMathFloor(LMathFloor* instr) {
CpuFeatureScope scope(masm(), FPU);
DoubleRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
Register scratch1 = scratch0();
......@@ -3591,7 +3520,6 @@ void LCodeGen::DoMathFloor(LMathFloor* instr) {
void LCodeGen::DoMathRound(LMathRound* instr) {
CpuFeatureScope scope(masm(), FPU);
DoubleRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp());
......@@ -3668,7 +3596,6 @@ void LCodeGen::DoMathRound(LMathRound* instr) {
void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
CpuFeatureScope scope(masm(), FPU);
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
__ sqrt_d(result, input);
......@@ -3676,7 +3603,6 @@ void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
CpuFeatureScope scope(masm(), FPU);
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
DoubleRegister temp = ToDoubleRegister(instr->temp());
......@@ -3701,7 +3627,6 @@ void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
void LCodeGen::DoPower(LPower* instr) {
CpuFeatureScope scope(masm(), FPU);
Representation exponent_type = instr->hydrogen()->right()->representation();
// Having marked this as a call, we can use any registers.
// Just make sure that the input/output registers are the expected ones.
......@@ -3732,7 +3657,6 @@ void LCodeGen::DoPower(LPower* instr) {
void LCodeGen::DoRandom(LRandom* instr) {
CpuFeatureScope scope(masm(), FPU);
class DeferredDoRandom: public LDeferredCode {
public:
DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
......@@ -3809,7 +3733,6 @@ void LCodeGen::DoDeferredRandom(LRandom* instr) {
void LCodeGen::DoMathExp(LMathExp* instr) {
CpuFeatureScope scope(masm(), FPU);
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
......@@ -4076,7 +3999,6 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
CpuFeatureScope scope(masm(), FPU);
Register external_pointer = ToRegister(instr->elements());
Register key = no_reg;
ElementsKind elements_kind = instr->elements_kind();
......@@ -4150,7 +4072,6 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
CpuFeatureScope scope(masm(), FPU);
DoubleRegister value = ToDoubleRegister(instr->value());
Register elements = ToRegister(instr->elements());
Register key = no_reg;
......@@ -4454,7 +4375,6 @@ void LCodeGen::DoStringLength(LStringLength* instr) {
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
CpuFeatureScope scope(masm(), FPU);
LOperand* input = instr->value();
ASSERT(input->IsRegister() || input->IsStackSlot());
LOperand* output = instr->result();
......@@ -4472,7 +4392,6 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
CpuFeatureScope scope(masm(), FPU);
LOperand* input = instr->value();
LOperand* output = instr->result();
......@@ -4534,45 +4453,6 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
}
// Convert unsigned integer with specified number of leading zeroes in binary
// representation to IEEE 754 double.
// Integer to convert is passed in register src.
// Resulting double is returned in registers hiword:loword.
// This functions does not work correctly for 0.
static void GenerateUInt2Double(MacroAssembler* masm,
Register src,
Register hiword,
Register loword,
Register scratch,
int leading_zeroes) {
const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
const int mantissa_shift_for_hi_word =
meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
const int mantissa_shift_for_lo_word =
kBitsPerInt - mantissa_shift_for_hi_word;
masm->li(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
if (mantissa_shift_for_hi_word > 0) {
masm->sll(loword, src, mantissa_shift_for_lo_word);
masm->srl(hiword, src, mantissa_shift_for_hi_word);
masm->Or(hiword, scratch, hiword);
} else {
masm->mov(loword, zero_reg);
masm->sll(hiword, src, mantissa_shift_for_hi_word);
masm->Or(hiword, scratch, hiword);
}
// If least significant bit of biased exponent was not 1 it was corrupted
// by most significant bit of mantissa so we should fix that.
if (!(biased_exponent & 1)) {
masm->li(scratch, 1 << HeapNumber::kExponentShift);
masm->nor(scratch, scratch, scratch);
masm->and_(hiword, hiword, scratch);
}
}
void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
LOperand* value,
IntegerSignedness signedness) {
......@@ -4593,35 +4473,11 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
__ SmiUntag(src, dst);
__ Xor(src, src, Operand(0x80000000));
}
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
__ mtc1(src, dbl_scratch);
__ cvt_d_w(dbl_scratch, dbl_scratch);
} else {
FloatingPointHelper::Destination dest =
FloatingPointHelper::kCoreRegisters;
FloatingPointHelper::ConvertIntToDouble(masm(), src, dest, f0,
sfpd_lo, sfpd_hi,
scratch0(), f2);
}
__ mtc1(src, dbl_scratch);
__ cvt_d_w(dbl_scratch, dbl_scratch);
} else {
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
__ mtc1(src, dbl_scratch);
__ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
} else {
Label no_leading_zero, convert_done;
__ And(at, src, Operand(0x80000000));
__ Branch(&no_leading_zero, ne, at, Operand(zero_reg));
// Integer has one leading zeros.
GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, t0, 1);
__ Branch(&convert_done);
__ bind(&no_leading_zero);
GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, t0, 0);
__ bind(&convert_done);
}
__ mtc1(src, dbl_scratch);
__ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
}
if (FLAG_inline_new) {
......@@ -4645,13 +4501,7 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
// Done. Put the value in dbl_scratch into the value of the allocated heap
// number.
__ bind(&done);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
__ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
} else {
__ sw(sfpd_lo, MemOperand(dst, HeapNumber::kMantissaOffset));
__ sw(sfpd_hi, MemOperand(dst, HeapNumber::kExponentOffset));
}
__ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
__ Addu(dst, dst, kHeapObjectTag);
__ StoreToSafepointRegisterSlot(dst, dst);
}
......@@ -4684,39 +4534,16 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
Label no_special_nan_handling;
Label done;
if (convert_hole) {
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
DoubleRegister input_reg = ToDoubleRegister(instr->value());
__ BranchF(&no_special_nan_handling, NULL, eq, input_reg, input_reg);
__ Move(reg, scratch0(), input_reg);
Label canonicalize;
__ Branch(&canonicalize, ne, scratch0(), Operand(kHoleNanUpper32));
__ li(reg, factory()->the_hole_value());
__ Branch(&done);
__ bind(&canonicalize);
__ Move(input_reg,
FixedDoubleArray::canonical_not_the_hole_nan_as_double());
} else {
Label not_hole;
__ Branch(&not_hole, ne, sfpd_hi, Operand(kHoleNanUpper32));
__ li(reg, factory()->the_hole_value());
__ Branch(&done);
__ bind(&not_hole);
__ And(scratch, sfpd_hi, Operand(0x7ff00000));
__ Branch(&no_special_nan_handling, ne, scratch, Operand(0x7ff00000));
Label special_nan_handling;
__ And(at, sfpd_hi, Operand(0x000FFFFF));
__ Branch(&special_nan_handling, ne, at, Operand(zero_reg));
__ Branch(&no_special_nan_handling, eq, sfpd_lo, Operand(zero_reg));
__ bind(&special_nan_handling);
double canonical_nan =
FixedDoubleArray::canonical_not_the_hole_nan_as_double();
uint64_t casted_nan = BitCast<uint64_t>(canonical_nan);
__ li(sfpd_lo,
Operand(static_cast<uint32_t>(casted_nan & 0xFFFFFFFF)));
__ li(sfpd_hi,
Operand(static_cast<uint32_t>(casted_nan >> 32)));
}
DoubleRegister input_reg = ToDoubleRegister(instr->value());
__ BranchF(&no_special_nan_handling, NULL, eq, input_reg, input_reg);
__ Move(reg, scratch0(), input_reg);
Label canonicalize;
__ Branch(&canonicalize, ne, scratch0(), Operand(kHoleNanUpper32));
__ li(reg, factory()->the_hole_value());
__ Branch(&done);
__ bind(&canonicalize);
__ Move(input_reg,
FixedDoubleArray::canonical_not_the_hole_nan_as_double());
}
__ bind(&no_special_nan_handling);
......@@ -4730,13 +4557,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
__ Branch(deferred->entry());
}
__ bind(deferred->exit());
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm(), FPU);
__ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
} else {
__ sw(sfpd_lo, MemOperand(reg, HeapNumber::kValueOffset));
__ sw(sfpd_hi, MemOperand(reg, HeapNumber::kValueOffset + kPointerSize));
}
__ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
// Now that we have finished with the object's real address tag it
__ Addu(reg, reg, kHeapObjectTag);
__ bind(&done);
......@@ -4786,7 +4607,6 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
LEnvironment* env,
NumberUntagDMode mode) {
Register scratch = scratch0();
CpuFeatureScope scope(masm(), FPU);
Label load_smi, heap_number, done;
......@@ -4863,7 +4683,6 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
// This 'at' value and scratch1 map value are used for tests in both clauses
// of the if.
CpuFeatureScope scope(masm(), FPU);
if (instr->truncating()) {
Register scratch3 = ToRegister(instr->temp2());
FPURegister single_scratch = double_scratch.low();
......@@ -5119,7 +4938,6 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
CpuFeatureScope vfp_scope(masm(), FPU);
DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
......@@ -5128,7 +4946,6 @@ void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
CpuFeatureScope vfp_scope(masm(), FPU);
Register unclamped_reg = ToRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
__ ClampUint8(result_reg, unclamped_reg);
......@@ -5136,7 +4953,6 @@ void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
CpuFeatureScope vfp_scope(masm(), FPU);
Register scratch = scratch0();
Register input_reg = ToRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
......
......@@ -172,10 +172,8 @@ void LGapResolver::BreakCycle(int index) {
} else if (source->IsStackSlot()) {
__ lw(kLithiumScratchReg, cgen_->ToMemOperand(source));
} else if (source->IsDoubleRegister()) {
CpuFeatureScope scope(cgen_->masm(), FPU);
__ mov_d(kLithiumScratchDouble, cgen_->ToDoubleRegister(source));
} else if (source->IsDoubleStackSlot()) {
CpuFeatureScope scope(cgen_->masm(), FPU);
__ ldc1(kLithiumScratchDouble, cgen_->ToMemOperand(source));
} else {
UNREACHABLE();
......@@ -195,11 +193,9 @@ void LGapResolver::RestoreValue() {
} else if (saved_destination_->IsStackSlot()) {
__ sw(kLithiumScratchReg, cgen_->ToMemOperand(saved_destination_));
} else if (saved_destination_->IsDoubleRegister()) {
CpuFeatureScope scope(cgen_->masm(), FPU);
__ mov_d(cgen_->ToDoubleRegister(saved_destination_),
kLithiumScratchDouble);
} else if (saved_destination_->IsDoubleStackSlot()) {
CpuFeatureScope scope(cgen_->masm(), FPU);
__ sdc1(kLithiumScratchDouble,
cgen_->ToMemOperand(saved_destination_));
} else {
......@@ -236,7 +232,6 @@ void LGapResolver::EmitMove(int index) {
MemOperand destination_operand = cgen_->ToMemOperand(destination);
if (in_cycle_) {
if (!destination_operand.OffsetIsInt16Encodable()) {
CpuFeatureScope scope(cgen_->masm(), FPU);
// 'at' is overwritten while saving the value to the destination.
// Therefore we can't use 'at'. It is OK if the read from the source
// destroys 'at', since that happens before the value is read.
......@@ -276,7 +271,6 @@ void LGapResolver::EmitMove(int index) {
}
} else if (source->IsDoubleRegister()) {
CpuFeatureScope scope(cgen_->masm(), FPU);
DoubleRegister source_register = cgen_->ToDoubleRegister(source);
if (destination->IsDoubleRegister()) {
__ mov_d(cgen_->ToDoubleRegister(destination), source_register);
......@@ -287,7 +281,6 @@ void LGapResolver::EmitMove(int index) {
}
} else if (source->IsDoubleStackSlot()) {
CpuFeatureScope scope(cgen_->masm(), FPU);
MemOperand source_operand = cgen_->ToMemOperand(source);
if (destination->IsDoubleRegister()) {
__ ldc1(cgen_->ToDoubleRegister(destination), source_operand);
......
......@@ -2050,16 +2050,7 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
(instr->representation().IsDouble() &&
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
// float->double conversion on soft float requires an extra scratch
// register. For convenience, just mark the elements register as "UseTemp"
// so that it can be used as a temp during the float->double conversion
// after it's no longer needed after the float load.
bool needs_temp =
!CpuFeatures::IsSupported(FPU) &&
(elements_kind == EXTERNAL_FLOAT_ELEMENTS);
LOperand* external_pointer = needs_temp
? UseTempRegister(instr->elements())
: UseRegister(instr->elements());
LOperand* external_pointer = UseRegister(instr->elements());
result = new(zone()) LLoadKeyed(external_pointer, key);
}
......
......@@ -851,7 +851,6 @@ void MacroAssembler::MultiPopReversed(RegList regs) {
void MacroAssembler::MultiPushFPU(RegList regs) {
CpuFeatureScope scope(this, FPU);
int16_t num_to_push = NumberOfBitsSet(regs);
int16_t stack_offset = num_to_push * kDoubleSize;
......@@ -866,7 +865,6 @@ void MacroAssembler::MultiPushFPU(RegList regs) {
void MacroAssembler::MultiPushReversedFPU(RegList regs) {
CpuFeatureScope scope(this, FPU);
int16_t num_to_push = NumberOfBitsSet(regs);
int16_t stack_offset = num_to_push * kDoubleSize;
......@@ -881,7 +879,6 @@ void MacroAssembler::MultiPushReversedFPU(RegList regs) {
void MacroAssembler::MultiPopFPU(RegList regs) {
CpuFeatureScope scope(this, FPU);
int16_t stack_offset = 0;
for (int16_t i = 0; i < kNumRegisters; i++) {
......@@ -895,7 +892,6 @@ void MacroAssembler::MultiPopFPU(RegList regs) {
void MacroAssembler::MultiPopReversedFPU(RegList regs) {
CpuFeatureScope scope(this, FPU);
int16_t stack_offset = 0;
for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
......@@ -1168,7 +1164,6 @@ void MacroAssembler::BranchF(Label* target,
void MacroAssembler::Move(FPURegister dst, double imm) {
ASSERT(IsEnabled(FPU));
static const DoubleRepresentation minus_zero(-0.0);
static const DoubleRepresentation zero(0.0);
DoubleRepresentation value(imm);
......@@ -1338,61 +1333,17 @@ void MacroAssembler::ConvertToInt32(Register source,
Subu(scratch2, scratch2, Operand(zero_exponent));
// Dest already has a Smi zero.
Branch(&done, lt, scratch2, Operand(zero_reg));
if (!CpuFeatures::IsSupported(FPU)) {
// We have a shifted exponent between 0 and 30 in scratch2.
srl(dest, scratch2, HeapNumber::kExponentShift);
// We now have the exponent in dest. Subtract from 30 to get
// how much to shift down.
li(at, Operand(30));
subu(dest, at, dest);
}
bind(&right_exponent);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(this, FPU);
// MIPS FPU instructions implementing double precision to integer
// conversion using round to zero. Since the FP value was qualified
// above, the resulting integer should be a legal int32.
// The original 'Exponent' word is still in scratch.
lwc1(double_scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
mtc1(scratch, FPURegister::from_code(double_scratch.code() + 1));
trunc_w_d(double_scratch, double_scratch);
mfc1(dest, double_scratch);
} else {
// On entry, dest has final downshift, scratch has original sign/exp/mant.
// Save sign bit in top bit of dest.
And(scratch2, scratch, Operand(0x80000000));
Or(dest, dest, Operand(scratch2));
// Put back the implicit 1, just above mantissa field.
Or(scratch, scratch, Operand(1 << HeapNumber::kExponentShift));
// Shift up the mantissa bits to take up the space the exponent used to
// take. We just orred in the implicit bit so that took care of one and
// we want to leave the sign bit 0 so we subtract 2 bits from the shift
// distance. But we want to clear the sign-bit so shift one more bit
// left, then shift right one bit.
const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
sll(scratch, scratch, shift_distance + 1);
srl(scratch, scratch, 1);
// Get the second half of the double. For some exponents we don't
// actually need this because the bits get shifted out again, but
// it's probably slower to test than just to do it.
lw(scratch2, FieldMemOperand(source, HeapNumber::kMantissaOffset));
// Extract the top 10 bits, and insert those bottom 10 bits of scratch.
// The width of the field here is the same as the shift amount above.
const int field_width = shift_distance;
Ext(scratch2, scratch2, 32-shift_distance, field_width);
Ins(scratch, scratch2, 0, field_width);
// Move down according to the exponent.
srlv(scratch, scratch, dest);
// Prepare the negative version of our integer.
subu(scratch2, zero_reg, scratch);
// Trick to check sign bit (msb) held in dest, count leading zero.
// 0 indicates negative, save negative version with conditional move.
Clz(dest, dest);
Movz(scratch, scratch2, dest);
mov(dest, scratch);
}
// MIPS FPU instructions implementing double precision to integer
// conversion using round to zero. Since the FP value was qualified
// above, the resulting integer should be a legal int32.
// The original 'Exponent' word is still in scratch.
lwc1(double_scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
mtc1(scratch, FPURegister::from_code(double_scratch.code() + 1));
trunc_w_d(double_scratch, double_scratch);
mfc1(dest, double_scratch);
bind(&done);
}
......@@ -1408,8 +1359,6 @@ void MacroAssembler::EmitFPUTruncate(FPURoundingMode rounding_mode,
ASSERT(!double_input.is(double_scratch));
ASSERT(!except_flag.is(scratch));
ASSERT(CpuFeatures::IsSupported(FPU));
CpuFeatureScope scope(this, FPU);
Label done;
// Clear the except flag (0 = no exception)
......@@ -1551,7 +1500,6 @@ void MacroAssembler::EmitECMATruncate(Register result,
Register scratch,
Register scratch2,
Register scratch3) {
CpuFeatureScope scope(this, FPU);
ASSERT(!scratch2.is(result));
ASSERT(!scratch3.is(result));
ASSERT(!scratch3.is(scratch2));
......@@ -3459,11 +3407,7 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
// scratch1 is now effective address of the double element
FloatingPointHelper::Destination destination;
if (CpuFeatures::IsSupported(FPU)) {
destination = FloatingPointHelper::kFPURegisters;
} else {
destination = FloatingPointHelper::kCoreRegisters;
}
destination = FloatingPointHelper::kFPURegisters;
Register untagged_value = elements_reg;
SmiUntag(untagged_value, value_reg);
......@@ -3476,7 +3420,6 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
scratch4,
f2);
if (destination == FloatingPointHelper::kFPURegisters) {
CpuFeatureScope scope(this, FPU);
sdc1(f0, MemOperand(scratch1, 0));
} else {
sw(mantissa_reg, MemOperand(scratch1, 0));
......@@ -3569,7 +3512,6 @@ void MacroAssembler::CheckMap(Register obj,
void MacroAssembler::GetCFunctionDoubleResult(const DoubleRegister dst) {
CpuFeatureScope scope(this, FPU);
if (IsMipsSoftFloatABI) {
Move(dst, v0, v1);
} else {
......@@ -3579,7 +3521,6 @@ void MacroAssembler::GetCFunctionDoubleResult(const DoubleRegister dst) {
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg) {
CpuFeatureScope scope(this, FPU);
if (!IsMipsSoftFloatABI) {
Move(f12, dreg);
} else {
......@@ -3590,7 +3531,6 @@ void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg) {
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg1,
DoubleRegister dreg2) {
CpuFeatureScope scope(this, FPU);
if (!IsMipsSoftFloatABI) {
if (dreg2.is(f12)) {
ASSERT(!dreg1.is(f14));
......@@ -3609,7 +3549,6 @@ void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg1,
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg,
Register reg) {
CpuFeatureScope scope(this, FPU);
if (!IsMipsSoftFloatABI) {
Move(f12, dreg);
Move(a2, reg);
......@@ -4252,10 +4191,7 @@ void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) {
const Runtime::Function* function = Runtime::FunctionForId(id);
PrepareCEntryArgs(function->nargs);
PrepareCEntryFunction(ExternalReference(function, isolate()));
SaveFPRegsMode mode = CpuFeatures::IsSupported(FPU)
? kSaveFPRegs
: kDontSaveFPRegs;
CEntryStub stub(1, mode);
CEntryStub stub(1, kSaveFPRegs);
CallStub(&stub);
}
......@@ -4647,7 +4583,6 @@ void MacroAssembler::EnterExitFrame(bool save_doubles,
const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
if (save_doubles) {
CpuFeatureScope scope(this, FPU);
// The stack must be allign to 0 modulo 8 for stores with sdc1.
ASSERT(kDoubleSize == frame_alignment);
if (frame_alignment > 0) {
......@@ -4685,7 +4620,6 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles,
bool do_return) {
// Optionally restore all double registers.
if (save_doubles) {
CpuFeatureScope scope(this, FPU);
// Remember: we only need to restore every 2nd double FPU value.
lw(t8, MemOperand(fp, ExitFrameConstants::kSPOffset));
for (int i = 0; i < FPURegister::kMaxNumRegisters; i+=2) {
......
......@@ -1059,72 +1059,12 @@ static void StoreIntAsFloat(MacroAssembler* masm,
Register dst,
Register wordoffset,
Register ival,
Register fval,
Register scratch1,
Register scratch2) {
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
__ mtc1(ival, f0);
__ cvt_s_w(f0, f0);
__ sll(scratch1, wordoffset, 2);
__ addu(scratch1, dst, scratch1);
__ swc1(f0, MemOperand(scratch1, 0));
} else {
// FPU is not available, do manual conversions.
Label not_special, done;
// Move sign bit from source to destination. This works because the sign
// bit in the exponent word of the double has the same position and polarity
// as the 2's complement sign bit in a Smi.
ASSERT(kBinary32SignMask == 0x80000000u);
__ And(fval, ival, Operand(kBinary32SignMask));
// Negate value if it is negative.
__ subu(scratch1, zero_reg, ival);
__ Movn(ival, scratch1, fval);
// We have -1, 0 or 1, which we treat specially. Register ival contains
// absolute value: it is either equal to 1 (special case of -1 and 1),
// greater than 1 (not a special case) or less than 1 (special case of 0).
__ Branch(&not_special, gt, ival, Operand(1));
// For 1 or -1 we need to or in the 0 exponent (biased).
static const uint32_t exponent_word_for_1 =
kBinary32ExponentBias << kBinary32ExponentShift;
__ Xor(scratch1, ival, Operand(1));
__ li(scratch2, exponent_word_for_1);
__ or_(scratch2, fval, scratch2);
__ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
__ Branch(&done);
__ bind(&not_special);
// Count leading zeros.
// Gets the wrong answer for 0, but we already checked for that case above.
Register zeros = scratch2;
__ Clz(zeros, ival);
// Compute exponent and or it into the exponent register.
__ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
__ subu(scratch1, scratch1, zeros);
__ sll(scratch1, scratch1, kBinary32ExponentShift);
__ or_(fval, fval, scratch1);
// Shift up the source chopping the top bit off.
__ Addu(zeros, zeros, Operand(1));
// This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
__ sllv(ival, ival, zeros);
// And the top (top 20 bits).
__ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
__ or_(fval, fval, scratch1);
__ bind(&done);
__ sll(scratch1, wordoffset, 2);
__ addu(scratch1, dst, scratch1);
__ sw(fval, MemOperand(scratch1, 0));
}
Register scratch1) {
__ mtc1(ival, f0);
__ cvt_s_w(f0, f0);
__ sll(scratch1, wordoffset, 2);
__ addu(scratch1, dst, scratch1);
__ swc1(f0, MemOperand(scratch1, 0));
}
......@@ -2177,11 +2117,7 @@ Handle<Code> CallStubCompiler::CompileMathFloorCall(
// -- sp[argc * 4] : receiver
// -----------------------------------
if (!CpuFeatures::IsSupported(FPU)) {
return Handle<Code>::null();
}
CpuFeatureScope scope_fpu(masm(), FPU);
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
......@@ -3247,36 +3183,6 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
}
static bool IsElementTypeSigned(ElementsKind elements_kind) {
switch (elements_kind) {
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
return true;
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS:
return false;
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
return false;
}
return false;
}
static void GenerateSmiKeyCheck(MacroAssembler* masm,
Register key,
Register scratch0,
......@@ -3284,36 +3190,30 @@ static void GenerateSmiKeyCheck(MacroAssembler* masm,
FPURegister double_scratch0,
FPURegister double_scratch1,
Label* fail) {
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
Label key_ok;
// Check for smi or a smi inside a heap number. We convert the heap
// number and check if the conversion is exact and fits into the smi
// range.
__ JumpIfSmi(key, &key_ok);
__ CheckMap(key,
scratch0,
Heap::kHeapNumberMapRootIndex,
fail,
DONT_DO_SMI_CHECK);
__ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
__ EmitFPUTruncate(kRoundToZero,
scratch0,
double_scratch0,
at,
double_scratch1,
scratch1,
kCheckForInexactConversion);
__ Branch(fail, ne, scratch1, Operand(zero_reg));
__ SmiTagCheckOverflow(key, scratch0, scratch1);
__ BranchOnOverflow(fail, scratch1);
__ bind(&key_ok);
} else {
// Check that the key is a smi.
__ JumpIfNotSmi(key, fail);
}
Label key_ok;
// Check for smi or a smi inside a heap number. We convert the heap
// number and check if the conversion is exact and fits into the smi
// range.
__ JumpIfSmi(key, &key_ok);
__ CheckMap(key,
scratch0,
Heap::kHeapNumberMapRootIndex,
fail,
DONT_DO_SMI_CHECK);
__ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
__ EmitFPUTruncate(kRoundToZero,
scratch0,
double_scratch0,
at,
double_scratch1,
scratch1,
kCheckForInexactConversion);
__ Branch(fail, ne, scratch1, Operand(zero_reg));
__ SmiTagCheckOverflow(key, scratch0, scratch1);
__ BranchOnOverflow(fail, scratch1);
__ bind(&key_ok);
}
......@@ -3404,29 +3304,19 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
case EXTERNAL_FLOAT_ELEMENTS:
// Perform int-to-float conversion and store to memory.
__ SmiUntag(t0, key);
StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
StoreIntAsFloat(masm, a3, t0, t1, t2);
break;
case EXTERNAL_DOUBLE_ELEMENTS:
__ sll(t8, key, 2);
__ addu(a3, a3, t8);
// a3: effective address of the double element
FloatingPointHelper::Destination destination;
if (CpuFeatures::IsSupported(FPU)) {
destination = FloatingPointHelper::kFPURegisters;
} else {
destination = FloatingPointHelper::kCoreRegisters;
}
destination = FloatingPointHelper::kFPURegisters;
FloatingPointHelper::ConvertIntToDouble(
masm, t1, destination,
f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
t0, f2); // These are: scratch2, single_scratch.
if (destination == FloatingPointHelper::kFPURegisters) {
CpuFeatureScope scope(masm, FPU);
__ sdc1(f0, MemOperand(a3, 0));
} else {
__ sw(t2, MemOperand(a3, 0));
__ sw(t3, MemOperand(a3, Register::kSizeInBytes));
}
__ sdc1(f0, MemOperand(a3, 0));
break;
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
......@@ -3458,232 +3348,59 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// +/-Infinity into integer arrays basically undefined. For more
// reproducible behavior, convert these to zero.
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(masm, FPU);
__ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
__ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ cvt_s_d(f0, f0);
__ sll(t8, key, 1);
__ addu(t8, a3, t8);
__ swc1(f0, MemOperand(t8, 0));
} else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ sll(t8, key, 2);
__ addu(t8, a3, t8);
__ sdc1(f0, MemOperand(t8, 0));
} else {
__ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
switch (elements_kind) {
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ srl(t8, key, 1);
__ addu(t8, a3, t8);
__ sb(t3, MemOperand(t8, 0));
break;
case EXTERNAL_SHORT_ELEMENTS:
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ addu(t8, a3, key);
__ sh(t3, MemOperand(t8, 0));
break;
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ sll(t8, key, 1);
__ addu(t8, a3, t8);
__ sw(t3, MemOperand(t8, 0));
break;
case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
}
// Entry registers are intact, a0 holds the value
// which is the return value.
__ mov(v0, a0);
__ Ret();
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ cvt_s_d(f0, f0);
__ sll(t8, key, 1);
__ addu(t8, a3, t8);
__ swc1(f0, MemOperand(t8, 0));
} else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ sll(t8, key, 2);
__ addu(t8, a3, t8);
__ sdc1(f0, MemOperand(t8, 0));
} else {
// FPU is not available, do manual conversions.
__ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
__ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
Label done, nan_or_infinity_or_zero;
static const int kMantissaInHiWordShift =
kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
static const int kMantissaInLoWordShift =
kBitsPerInt - kMantissaInHiWordShift;
// Test for all special exponent values: zeros, subnormal numbers, NaNs
// and infinities. All these should be converted to 0.
__ li(t5, HeapNumber::kExponentMask);
__ and_(t6, t3, t5);
__ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
__ xor_(t1, t6, t5);
__ li(t2, kBinary32ExponentMask);
__ Movz(t6, t2, t1); // Only if t6 is equal to t5.
__ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
// Rebias exponent.
__ srl(t6, t6, HeapNumber::kExponentShift);
__ Addu(t6,
t6,
Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
__ li(t1, Operand(kBinary32MaxExponent));
__ Slt(t1, t1, t6);
__ And(t2, t3, Operand(HeapNumber::kSignMask));
__ Or(t2, t2, Operand(kBinary32ExponentMask));
__ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
__ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
__ Slt(t1, t6, Operand(kBinary32MinExponent));
__ And(t2, t3, Operand(HeapNumber::kSignMask));
__ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
__ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
__ And(t7, t3, Operand(HeapNumber::kSignMask));
__ And(t3, t3, Operand(HeapNumber::kMantissaMask));
__ sll(t3, t3, kMantissaInHiWordShift);
__ or_(t7, t7, t3);
__ srl(t4, t4, kMantissaInLoWordShift);
__ or_(t7, t7, t4);
__ sll(t6, t6, kBinary32ExponentShift);
__ or_(t3, t7, t6);
__ bind(&done);
__ sll(t9, key, 1);
__ addu(t9, a3, t9);
__ sw(t3, MemOperand(t9, 0));
// Entry registers are intact, a0 holds the value which is the return
// value.
__ mov(v0, a0);
__ Ret();
__ bind(&nan_or_infinity_or_zero);
__ And(t7, t3, Operand(HeapNumber::kSignMask));
__ And(t3, t3, Operand(HeapNumber::kMantissaMask));
__ or_(t6, t6, t7);
__ sll(t3, t3, kMantissaInHiWordShift);
__ or_(t6, t6, t3);
__ srl(t4, t4, kMantissaInLoWordShift);
__ or_(t3, t6, t4);
__ Branch(&done);
} else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ sll(t8, key, 2);
__ addu(t8, a3, t8);
// t8: effective address of destination element.
__ sw(t4, MemOperand(t8, 0));
__ sw(t3, MemOperand(t8, Register::kSizeInBytes));
__ mov(v0, a0);
__ Ret();
} else {
bool is_signed_type = IsElementTypeSigned(elements_kind);
int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
Label done, sign;
// Test for all special exponent values: zeros, subnormal numbers, NaNs
// and infinities. All these should be converted to 0.
__ li(t5, HeapNumber::kExponentMask);
__ and_(t6, t3, t5);
__ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
__ Branch(&done, eq, t6, Operand(zero_reg));
__ xor_(t2, t6, t5);
__ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
__ Branch(&done, eq, t6, Operand(t5));
// Unbias exponent.
__ srl(t6, t6, HeapNumber::kExponentShift);
__ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
// If exponent is negative then result is 0.
__ slt(t2, t6, zero_reg);
__ Movn(t3, zero_reg, t2); // Only if exponent is negative.
__ Branch(&done, lt, t6, Operand(zero_reg));
// If exponent is too big then result is minimal value.
__ slti(t1, t6, meaningfull_bits - 1);
__ li(t2, min_value);
__ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
__ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
__ And(t5, t3, Operand(HeapNumber::kSignMask));
__ And(t3, t3, Operand(HeapNumber::kMantissaMask));
__ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
__ li(t9, HeapNumber::kMantissaBitsInTopWord);
__ subu(t6, t9, t6);
__ slt(t1, t6, zero_reg);
__ srlv(t2, t3, t6);
__ Movz(t3, t2, t1); // Only if t6 is positive.
__ Branch(&sign, ge, t6, Operand(zero_reg));
__ subu(t6, zero_reg, t6);
__ sllv(t3, t3, t6);
__ li(t9, meaningfull_bits);
__ subu(t6, t9, t6);
__ srlv(t4, t4, t6);
__ or_(t3, t3, t4);
__ bind(&sign);
__ subu(t2, t3, zero_reg);
__ Movz(t3, t2, t5); // Only if t5 is zero.
__ bind(&done);
// Result is in t3.
// This switch block should be exactly the same as above (FPU mode).
switch (elements_kind) {
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ srl(t8, key, 1);
__ addu(t8, a3, t8);
__ sb(t3, MemOperand(t8, 0));
break;
case EXTERNAL_SHORT_ELEMENTS:
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ addu(t8, a3, key);
__ sh(t3, MemOperand(t8, 0));
break;
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ sll(t8, key, 1);
__ addu(t8, a3, t8);
__ sw(t3, MemOperand(t8, 0));
break;
case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
__ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
switch (elements_kind) {
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ srl(t8, key, 1);
__ addu(t8, a3, t8);
__ sb(t3, MemOperand(t8, 0));
break;
case EXTERNAL_SHORT_ELEMENTS:
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ addu(t8, a3, key);
__ sh(t3, MemOperand(t8, 0));
break;
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ sll(t8, key, 1);
__ addu(t8, a3, t8);
__ sw(t3, MemOperand(t8, 0));
break;
case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
}
// Entry registers are intact, a0 holds the value
// which is the return value.
__ mov(v0, a0);
__ Ret();
}
// Slow case, key and receiver still in a0 and a1.
......
......@@ -277,33 +277,30 @@ TEST(MIPS3) {
MacroAssembler assm(isolate, NULL, 0);
Label L, C;
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(&assm, FPU);
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
__ add_d(f8, f4, f6);
__ sdc1(f8, MemOperand(a0, OFFSET_OF(T, c)) ); // c = a + b.
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
__ add_d(f8, f4, f6);
__ sdc1(f8, MemOperand(a0, OFFSET_OF(T, c)) ); // c = a + b.
__ mov_d(f10, f8); // c
__ neg_d(f12, f6); // -b
__ sub_d(f10, f10, f12);
__ sdc1(f10, MemOperand(a0, OFFSET_OF(T, d)) ); // d = c - (-b).
__ mov_d(f10, f8); // c
__ neg_d(f12, f6); // -b
__ sub_d(f10, f10, f12);
__ sdc1(f10, MemOperand(a0, OFFSET_OF(T, d)) ); // d = c - (-b).
__ sdc1(f4, MemOperand(a0, OFFSET_OF(T, b)) ); // b = a.
__ sdc1(f4, MemOperand(a0, OFFSET_OF(T, b)) ); // b = a.
__ li(t0, 120);
__ mtc1(t0, f14);
__ cvt_d_w(f14, f14); // f14 = 120.0.
__ mul_d(f10, f10, f14);
__ sdc1(f10, MemOperand(a0, OFFSET_OF(T, e)) ); // e = d * 120 = 1.8066e16.
__ li(t0, 120);
__ mtc1(t0, f14);
__ cvt_d_w(f14, f14); // f14 = 120.0.
__ mul_d(f10, f10, f14);
__ sdc1(f10, MemOperand(a0, OFFSET_OF(T, e)) ); // e = d * 120 = 1.8066e16.
__ div_d(f12, f10, f4);
__ sdc1(f12, MemOperand(a0, OFFSET_OF(T, f)) ); // f = e / a = 120.44.
__ div_d(f12, f10, f4);
__ sdc1(f12, MemOperand(a0, OFFSET_OF(T, f)) ); // f = e / a = 120.44.
__ sqrt_d(f14, f12);
__ sdc1(f14, MemOperand(a0, OFFSET_OF(T, g)) );
// g = sqrt(f) = 10.97451593465515908537
__ sqrt_d(f14, f12);
__ sdc1(f14, MemOperand(a0, OFFSET_OF(T, g)) );
// g = sqrt(f) = 10.97451593465515908537
if (kArchVariant == kMips32r2) {
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, h)) );
......@@ -312,36 +309,35 @@ TEST(MIPS3) {
__ sdc1(f14, MemOperand(a0, OFFSET_OF(T, h)) );
}
__ jr(ra);
__ nop();
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
t.a = 1.5e14;
t.b = 2.75e11;
t.c = 0.0;
t.d = 0.0;
t.e = 0.0;
t.f = 0.0;
t.h = 1.5;
t.i = 2.75;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
CHECK_EQ(1.5e14, t.a);
CHECK_EQ(1.5e14, t.b);
CHECK_EQ(1.50275e14, t.c);
CHECK_EQ(1.50550e14, t.d);
CHECK_EQ(1.8066e16, t.e);
CHECK_EQ(120.44, t.f);
CHECK_EQ(10.97451593465515908537, t.g);
CHECK_EQ(6.875, t.h);
}
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
t.a = 1.5e14;
t.b = 2.75e11;
t.c = 0.0;
t.d = 0.0;
t.e = 0.0;
t.f = 0.0;
t.h = 1.5;
t.i = 2.75;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
CHECK_EQ(1.5e14, t.a);
CHECK_EQ(1.5e14, t.b);
CHECK_EQ(1.50275e14, t.c);
CHECK_EQ(1.50550e14, t.d);
CHECK_EQ(1.8066e16, t.e);
CHECK_EQ(120.44, t.f);
CHECK_EQ(10.97451593465515908537, t.g);
CHECK_EQ(6.875, t.h);
}
......@@ -361,48 +357,44 @@ TEST(MIPS4) {
Assembler assm(isolate, NULL, 0);
Label L, C;
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(&assm, FPU);
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
// Swap f4 and f6, by using four integer registers, t0-t3.
__ mfc1(t0, f4);
__ mfc1(t1, f5);
__ mfc1(t2, f6);
__ mfc1(t3, f7);
// Swap f4 and f6, by using four integer registers, t0-t3.
__ mfc1(t0, f4);
__ mfc1(t1, f5);
__ mfc1(t2, f6);
__ mfc1(t3, f7);
__ mtc1(t0, f6);
__ mtc1(t1, f7);
__ mtc1(t2, f4);
__ mtc1(t3, f5);
__ mtc1(t0, f6);
__ mtc1(t1, f7);
__ mtc1(t2, f4);
__ mtc1(t3, f5);
// Store the swapped f4 and f5 back to memory.
__ sdc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ sdc1(f6, MemOperand(a0, OFFSET_OF(T, c)) );
// Store the swapped f4 and f5 back to memory.
__ sdc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ sdc1(f6, MemOperand(a0, OFFSET_OF(T, c)) );
__ jr(ra);
__ nop();
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
t.a = 1.5e22;
t.b = 2.75e11;
t.c = 17.17;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
t.a = 1.5e22;
t.b = 2.75e11;
t.c = 17.17;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
CHECK_EQ(2.75e11, t.a);
CHECK_EQ(2.75e11, t.b);
CHECK_EQ(1.5e22, t.c);
}
CHECK_EQ(2.75e11, t.a);
CHECK_EQ(2.75e11, t.b);
CHECK_EQ(1.5e22, t.c);
}
......@@ -423,58 +415,54 @@ TEST(MIPS5) {
Assembler assm(isolate, NULL, 0);
Label L, C;
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(&assm, FPU);
// Load all structure elements to registers.
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
__ lw(t0, MemOperand(a0, OFFSET_OF(T, i)) );
__ lw(t1, MemOperand(a0, OFFSET_OF(T, j)) );
// Load all structure elements to registers.
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
__ lw(t0, MemOperand(a0, OFFSET_OF(T, i)) );
__ lw(t1, MemOperand(a0, OFFSET_OF(T, j)) );
// Convert double in f4 to int in element i.
__ cvt_w_d(f8, f4);
__ mfc1(t2, f8);
__ sw(t2, MemOperand(a0, OFFSET_OF(T, i)) );
// Convert double in f6 to int in element j.
__ cvt_w_d(f10, f6);
__ mfc1(t3, f10);
__ sw(t3, MemOperand(a0, OFFSET_OF(T, j)) );
// Convert int in original i (t0) to double in a.
__ mtc1(t0, f12);
__ cvt_d_w(f0, f12);
__ sdc1(f0, MemOperand(a0, OFFSET_OF(T, a)) );
// Convert int in original j (t1) to double in b.
__ mtc1(t1, f14);
__ cvt_d_w(f2, f14);
__ sdc1(f2, MemOperand(a0, OFFSET_OF(T, b)) );
// Convert double in f4 to int in element i.
__ cvt_w_d(f8, f4);
__ mfc1(t2, f8);
__ sw(t2, MemOperand(a0, OFFSET_OF(T, i)) );
__ jr(ra);
__ nop();
// Convert double in f6 to int in element j.
__ cvt_w_d(f10, f6);
__ mfc1(t3, f10);
__ sw(t3, MemOperand(a0, OFFSET_OF(T, j)) );
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
t.a = 1.5e4;
t.b = 2.75e8;
t.i = 12345678;
t.j = -100000;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
// Convert int in original i (t0) to double in a.
__ mtc1(t0, f12);
__ cvt_d_w(f0, f12);
__ sdc1(f0, MemOperand(a0, OFFSET_OF(T, a)) );
CHECK_EQ(12345678.0, t.a);
CHECK_EQ(-100000.0, t.b);
CHECK_EQ(15000, t.i);
CHECK_EQ(275000000, t.j);
}
// Convert int in original j (t1) to double in b.
__ mtc1(t1, f14);
__ cvt_d_w(f2, f14);
__ sdc1(f2, MemOperand(a0, OFFSET_OF(T, b)) );
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
t.a = 1.5e4;
t.b = 2.75e8;
t.i = 12345678;
t.j = -100000;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
CHECK_EQ(12345678.0, t.a);
CHECK_EQ(-100000.0, t.b);
CHECK_EQ(15000, t.i);
CHECK_EQ(275000000, t.j);
}
......@@ -573,63 +561,59 @@ TEST(MIPS7) {
MacroAssembler assm(isolate, NULL, 0);
Label neither_is_nan, less_than, outa_here;
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(&assm, FPU);
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
__ c(UN, D, f4, f6);
__ bc1f(&neither_is_nan);
__ nop();
__ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
__ Branch(&outa_here);
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
__ c(UN, D, f4, f6);
__ bc1f(&neither_is_nan);
__ nop();
__ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
__ Branch(&outa_here);
__ bind(&neither_is_nan);
if (kArchVariant == kLoongson) {
__ c(OLT, D, f6, f4);
__ bc1t(&less_than);
} else {
__ c(OLT, D, f6, f4, 2);
__ bc1t(&less_than, 2);
}
__ nop();
__ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
__ Branch(&outa_here);
__ bind(&neither_is_nan);
__ bind(&less_than);
__ Addu(t0, zero_reg, Operand(1));
__ sw(t0, MemOperand(a0, OFFSET_OF(T, result)) ); // Set true.
if (kArchVariant == kLoongson) {
__ c(OLT, D, f6, f4);
__ bc1t(&less_than);
} else {
__ c(OLT, D, f6, f4, 2);
__ bc1t(&less_than, 2);
}
__ nop();
__ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
__ Branch(&outa_here);
__ bind(&less_than);
__ Addu(t0, zero_reg, Operand(1));
__ sw(t0, MemOperand(a0, OFFSET_OF(T, result)) ); // Set true.
// This test-case should have additional tests.
__ bind(&outa_here);
// This test-case should have additional tests.
__ jr(ra);
__ nop();
__ bind(&outa_here);
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
t.a = 1.5e14;
t.b = 2.75e11;
t.c = 2.0;
t.d = -4.0;
t.e = 0.0;
t.f = 0.0;
t.result = 0;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
CHECK_EQ(1.5e14, t.a);
CHECK_EQ(2.75e11, t.b);
CHECK_EQ(1, t.result);
}
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
t.a = 1.5e14;
t.b = 2.75e11;
t.c = 2.0;
t.d = -4.0;
t.e = 0.0;
t.f = 0.0;
t.result = 0;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
CHECK_EQ(1.5e14, t.a);
CHECK_EQ(2.75e11, t.b);
CHECK_EQ(1, t.result);
}
......@@ -789,9 +773,7 @@ TEST(MIPS10) {
Assembler assm(isolate, NULL, 0);
Label L, C;
if (CpuFeatures::IsSupported(FPU) && kArchVariant == kMips32r2) {
CpuFeatureScope scope(&assm, FPU);
if (kArchVariant == kMips32r2) {
// Load all structure elements to registers.
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, a)));
......@@ -1097,48 +1079,44 @@ TEST(MIPS13) {
MacroAssembler assm(isolate, NULL, 0);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(&assm, FPU);
__ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_small_in)));
__ Cvt_d_uw(f10, t0, f22);
__ sdc1(f10, MemOperand(a0, OFFSET_OF(T, cvt_small_out)));
__ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_small_in)));
__ Cvt_d_uw(f10, t0, f22);
__ sdc1(f10, MemOperand(a0, OFFSET_OF(T, cvt_small_out)));
__ Trunc_uw_d(f10, f10, f22);
__ swc1(f10, MemOperand(a0, OFFSET_OF(T, trunc_small_out)));
__ Trunc_uw_d(f10, f10, f22);
__ swc1(f10, MemOperand(a0, OFFSET_OF(T, trunc_small_out)));
__ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_big_in)));
__ Cvt_d_uw(f8, t0, f22);
__ sdc1(f8, MemOperand(a0, OFFSET_OF(T, cvt_big_out)));
__ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_big_in)));
__ Cvt_d_uw(f8, t0, f22);
__ sdc1(f8, MemOperand(a0, OFFSET_OF(T, cvt_big_out)));
__ Trunc_uw_d(f8, f8, f22);
__ swc1(f8, MemOperand(a0, OFFSET_OF(T, trunc_big_out)));
__ Trunc_uw_d(f8, f8, f22);
__ swc1(f8, MemOperand(a0, OFFSET_OF(T, trunc_big_out)));
__ jr(ra);
__ nop();
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
t.cvt_big_in = 0xFFFFFFFF;
t.cvt_small_in = 333;
t.cvt_big_in = 0xFFFFFFFF;
t.cvt_small_in = 333;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
CHECK_EQ(t.cvt_big_out, static_cast<double>(t.cvt_big_in));
CHECK_EQ(t.cvt_small_out, static_cast<double>(t.cvt_small_in));
CHECK_EQ(t.cvt_big_out, static_cast<double>(t.cvt_big_in));
CHECK_EQ(t.cvt_small_out, static_cast<double>(t.cvt_small_in));
CHECK_EQ(static_cast<int>(t.trunc_big_out), static_cast<int>(t.cvt_big_in));
CHECK_EQ(static_cast<int>(t.trunc_small_out),
static_cast<int>(t.cvt_small_in));
}
CHECK_EQ(static_cast<int>(t.trunc_big_out), static_cast<int>(t.cvt_big_in));
CHECK_EQ(static_cast<int>(t.trunc_small_out),
static_cast<int>(t.cvt_small_in));
}
......@@ -1181,87 +1159,84 @@ TEST(MIPS14) {
MacroAssembler assm(isolate, NULL, 0);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatureScope scope(&assm, FPU);
// Save FCSR.
__ cfc1(a1, FCSR);
// Disable FPU exceptions.
__ ctc1(zero_reg, FCSR);
// Save FCSR.
__ cfc1(a1, FCSR);
// Disable FPU exceptions.
__ ctc1(zero_reg, FCSR);
#define RUN_ROUND_TEST(x) \
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_up_in))); \
__ x##_w_d(f0, f0); \
__ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_up_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_down_in))); \
__ x##_w_d(f0, f0); \
__ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_down_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_up_in))); \
__ x##_w_d(f0, f0); \
__ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_up_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_down_in))); \
__ x##_w_d(f0, f0); \
__ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_down_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err1_in))); \
__ ctc1(zero_reg, FCSR); \
__ x##_w_d(f0, f0); \
__ cfc1(a2, FCSR); \
__ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err1_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err2_in))); \
__ ctc1(zero_reg, FCSR); \
__ x##_w_d(f0, f0); \
__ cfc1(a2, FCSR); \
__ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err2_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err3_in))); \
__ ctc1(zero_reg, FCSR); \
__ x##_w_d(f0, f0); \
__ cfc1(a2, FCSR); \
__ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err3_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err4_in))); \
__ ctc1(zero_reg, FCSR); \
__ x##_w_d(f0, f0); \
__ cfc1(a2, FCSR); \
__ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err4_out))); \
__ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_invalid_result)));
RUN_ROUND_TEST(round)
RUN_ROUND_TEST(floor)
RUN_ROUND_TEST(ceil)
RUN_ROUND_TEST(trunc)
RUN_ROUND_TEST(cvt)
// Restore FCSR.
__ ctc1(a1, FCSR);
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_up_in))); \
__ x##_w_d(f0, f0); \
__ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_up_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_down_in))); \
__ x##_w_d(f0, f0); \
__ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_down_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_up_in))); \
__ x##_w_d(f0, f0); \
__ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_up_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_down_in))); \
__ x##_w_d(f0, f0); \
__ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_down_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err1_in))); \
__ ctc1(zero_reg, FCSR); \
__ x##_w_d(f0, f0); \
__ cfc1(a2, FCSR); \
__ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err1_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err2_in))); \
__ ctc1(zero_reg, FCSR); \
__ x##_w_d(f0, f0); \
__ cfc1(a2, FCSR); \
__ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err2_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err3_in))); \
__ ctc1(zero_reg, FCSR); \
__ x##_w_d(f0, f0); \
__ cfc1(a2, FCSR); \
__ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err3_out))); \
\
__ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err4_in))); \
__ ctc1(zero_reg, FCSR); \
__ x##_w_d(f0, f0); \
__ cfc1(a2, FCSR); \
__ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err4_out))); \
__ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_invalid_result)));
RUN_ROUND_TEST(round)
RUN_ROUND_TEST(floor)
RUN_ROUND_TEST(ceil)
RUN_ROUND_TEST(trunc)
RUN_ROUND_TEST(cvt)
// Restore FCSR.
__ ctc1(a1, FCSR);
__ jr(ra);
__ nop();
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
CodeDesc desc;
assm.GetCode(&desc);
Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Code>())->ToObjectChecked();
CHECK(code->IsCode());
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
t.round_up_in = 123.51;
t.round_down_in = 123.49;
t.neg_round_up_in = -123.5;
t.neg_round_down_in = -123.49;
t.err1_in = 123.51;
t.err2_in = 1;
t.err3_in = static_cast<double>(1) + 0xFFFFFFFF;
t.err4_in = NAN;
t.round_up_in = 123.51;
t.round_down_in = 123.49;
t.neg_round_up_in = -123.5;
t.neg_round_down_in = -123.49;
t.err1_in = 123.51;
t.err2_in = 1;
t.err3_in = static_cast<double>(1) + 0xFFFFFFFF;
t.err4_in = NAN;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
#define GET_FPU_ERR(x) (static_cast<int>(x & kFCSRFlagMask))
#define CHECK_ROUND_RESULT(type) \
......@@ -1271,11 +1246,10 @@ TEST(MIPS14) {
CHECK(GET_FPU_ERR(t.type##_err4_out) & kFCSRInvalidOpFlagMask); \
CHECK_EQ(kFPUInvalidResult, t.type##_invalid_result);
CHECK_ROUND_RESULT(round);
CHECK_ROUND_RESULT(floor);
CHECK_ROUND_RESULT(ceil);
CHECK_ROUND_RESULT(cvt);
}
CHECK_ROUND_RESULT(round);
CHECK_ROUND_RESULT(floor);
CHECK_ROUND_RESULT(ceil);
CHECK_ROUND_RESULT(cvt);
}
......
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