MIPS: Add FPXX support to MIPS32R2
The JIT code generated by V8 is FPXX compliant when v8 compiled with FPXX flag. This allows the code to run in both FP=1 and FP=0 mode. It also alows v8 to be used as a library by both FP32 and FP64 binaries. BUG= Review URL: https://codereview.chromium.org/1586223004 Cr-Commit-Position: refs/heads/master@{#33576}
This commit is contained in:
parent
1547136c4e
commit
95110dde66
@ -2099,7 +2099,7 @@ void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
|
|||||||
GenInstrImmediate(LW, at, at, Register::kExponentOffset);
|
GenInstrImmediate(LW, at, at, Register::kExponentOffset);
|
||||||
mthc1(at, fd);
|
mthc1(at, fd);
|
||||||
}
|
}
|
||||||
} else { // fp32 mode.
|
} else if (IsFp32Mode()) { // fp32 mode.
|
||||||
if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
|
if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
|
||||||
GenInstrImmediate(LWC1, src.rm(), fd,
|
GenInstrImmediate(LWC1, src.rm(), fd,
|
||||||
src.offset_ + Register::kMantissaOffset);
|
src.offset_ + Register::kMantissaOffset);
|
||||||
@ -2114,6 +2114,22 @@ void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
|
|||||||
nextfpreg.setcode(fd.code() + 1);
|
nextfpreg.setcode(fd.code() + 1);
|
||||||
GenInstrImmediate(LWC1, at, nextfpreg, Register::kExponentOffset);
|
GenInstrImmediate(LWC1, at, nextfpreg, Register::kExponentOffset);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
DCHECK(IsFpxxMode());
|
||||||
|
// Currently we support FPXX on Mips32r2 and Mips32r6
|
||||||
|
DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
|
||||||
|
if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
|
||||||
|
GenInstrImmediate(LWC1, src.rm(), fd,
|
||||||
|
src.offset_ + Register::kMantissaOffset);
|
||||||
|
GenInstrImmediate(LW, src.rm(), at,
|
||||||
|
src.offset_ + Register::kExponentOffset);
|
||||||
|
mthc1(at, fd);
|
||||||
|
} else { // Offset > 16 bits, use multiple instructions to load.
|
||||||
|
LoadRegPlusOffsetToAt(src);
|
||||||
|
GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
|
||||||
|
GenInstrImmediate(LW, at, at, Register::kExponentOffset);
|
||||||
|
mthc1(at, fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2146,7 +2162,7 @@ void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
|
|||||||
mfhc1(t8, fd);
|
mfhc1(t8, fd);
|
||||||
GenInstrImmediate(SW, at, t8, Register::kExponentOffset);
|
GenInstrImmediate(SW, at, t8, Register::kExponentOffset);
|
||||||
}
|
}
|
||||||
} else { // fp32 mode.
|
} else if (IsFp32Mode()) { // fp32 mode.
|
||||||
if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
|
if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
|
||||||
GenInstrImmediate(SWC1, src.rm(), fd,
|
GenInstrImmediate(SWC1, src.rm(), fd,
|
||||||
src.offset_ + Register::kMantissaOffset);
|
src.offset_ + Register::kMantissaOffset);
|
||||||
@ -2161,6 +2177,22 @@ void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
|
|||||||
nextfpreg.setcode(fd.code() + 1);
|
nextfpreg.setcode(fd.code() + 1);
|
||||||
GenInstrImmediate(SWC1, at, nextfpreg, Register::kExponentOffset);
|
GenInstrImmediate(SWC1, at, nextfpreg, Register::kExponentOffset);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
DCHECK(IsFpxxMode());
|
||||||
|
// Currently we support FPXX on Mips32r2 and Mips32r6
|
||||||
|
DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
|
||||||
|
if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
|
||||||
|
GenInstrImmediate(SWC1, src.rm(), fd,
|
||||||
|
src.offset_ + Register::kMantissaOffset);
|
||||||
|
mfhc1(at, fd);
|
||||||
|
GenInstrImmediate(SW, src.rm(), at,
|
||||||
|
src.offset_ + Register::kExponentOffset);
|
||||||
|
} else { // Offset > 16 bits, use multiple instructions to load.
|
||||||
|
LoadRegPlusOffsetToAt(src);
|
||||||
|
GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
|
||||||
|
mfhc1(t8, fd);
|
||||||
|
GenInstrImmediate(SW, at, t8, Register::kExponentOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,9 +64,13 @@ enum FpuMode {
|
|||||||
#elif defined(FPU_MODE_FP64)
|
#elif defined(FPU_MODE_FP64)
|
||||||
static const FpuMode kFpuMode = kFP64;
|
static const FpuMode kFpuMode = kFP64;
|
||||||
#elif defined(FPU_MODE_FPXX)
|
#elif defined(FPU_MODE_FPXX)
|
||||||
static const FpuMode kFpuMode = kFPXX;
|
#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS32R6)
|
||||||
|
static const FpuMode kFpuMode = kFPXX;
|
||||||
#else
|
#else
|
||||||
static const FpuMode kFpuMode = kFP32;
|
#error "FPXX is supported only on Mips32R2 and Mips32R6"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
static const FpuMode kFpuMode = kFP32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if(defined(__mips_hard_float) && __mips_hard_float != 0)
|
#if(defined(__mips_hard_float) && __mips_hard_float != 0)
|
||||||
@ -92,13 +96,9 @@ const uint32_t kHoleNanLower32Offset = 4;
|
|||||||
#error Unknown endianness
|
#error Unknown endianness
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FPU_MODE_FPXX
|
#define IsFp64Mode() (kFpuMode == kFP64)
|
||||||
#define IsFp64Mode() \
|
#define IsFp32Mode() (kFpuMode == kFP32)
|
||||||
(kFpuMode == kFP64)
|
#define IsFpxxMode() (kFpuMode == kFPXX)
|
||||||
#else
|
|
||||||
#define IsFp64Mode() \
|
|
||||||
(CpuFeatures::IsSupported(FP64FPU))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _MIPS_ARCH_MIPS32RX
|
#ifndef _MIPS_ARCH_MIPS32RX
|
||||||
#define IsMipsArchVariant(check) \
|
#define IsMipsArchVariant(check) \
|
||||||
|
@ -1396,7 +1396,7 @@ void MacroAssembler::Trunc_uw_d(FPURegister fd,
|
|||||||
|
|
||||||
|
|
||||||
void MacroAssembler::Mthc1(Register rt, FPURegister fs) {
|
void MacroAssembler::Mthc1(Register rt, FPURegister fs) {
|
||||||
if (IsFp64Mode()) {
|
if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
|
||||||
mthc1(rt, fs);
|
mthc1(rt, fs);
|
||||||
} else {
|
} else {
|
||||||
mtc1(rt, fs.high());
|
mtc1(rt, fs.high());
|
||||||
@ -1405,7 +1405,7 @@ void MacroAssembler::Mthc1(Register rt, FPURegister fs) {
|
|||||||
|
|
||||||
|
|
||||||
void MacroAssembler::Mfhc1(Register rt, FPURegister fs) {
|
void MacroAssembler::Mfhc1(Register rt, FPURegister fs) {
|
||||||
if (IsFp64Mode()) {
|
if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
|
||||||
mfhc1(rt, fs);
|
mfhc1(rt, fs);
|
||||||
} else {
|
} else {
|
||||||
mfc1(rt, fs.high());
|
mfc1(rt, fs.high());
|
||||||
|
@ -384,6 +384,14 @@ TEST(MIPS3) {
|
|||||||
|
|
||||||
|
|
||||||
TEST(MIPS4) {
|
TEST(MIPS4) {
|
||||||
|
// Exchange between GP anf FP registers is done through memory
|
||||||
|
// on FPXX compiled binaries and architectures that do not support
|
||||||
|
// MTHC1 and MTFC1. If this is the case, skipping this test.
|
||||||
|
if (IsFpxxMode() &&
|
||||||
|
(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kLoongson))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Test moves between floating point and integer registers.
|
// Test moves between floating point and integer registers.
|
||||||
CcTest::InitializeVM();
|
CcTest::InitializeVM();
|
||||||
Isolate* isolate = CcTest::i_isolate();
|
Isolate* isolate = CcTest::i_isolate();
|
||||||
@ -403,7 +411,7 @@ TEST(MIPS4) {
|
|||||||
__ ldc1(f6, MemOperand(a0, offsetof(T, b)) );
|
__ ldc1(f6, MemOperand(a0, offsetof(T, b)) );
|
||||||
|
|
||||||
// Swap f4 and f6, by using four integer registers, t0-t3.
|
// Swap f4 and f6, by using four integer registers, t0-t3.
|
||||||
if (!IsFp64Mode()) {
|
if (IsFp32Mode()) {
|
||||||
__ mfc1(t0, f4);
|
__ mfc1(t0, f4);
|
||||||
__ mfc1(t1, f5);
|
__ mfc1(t1, f5);
|
||||||
__ mfc1(t2, f6);
|
__ mfc1(t2, f6);
|
||||||
@ -415,6 +423,7 @@ TEST(MIPS4) {
|
|||||||
__ mtc1(t3, f5);
|
__ mtc1(t3, f5);
|
||||||
} else {
|
} else {
|
||||||
CHECK(!IsMipsArchVariant(kMips32r1) && !IsMipsArchVariant(kLoongson));
|
CHECK(!IsMipsArchVariant(kMips32r1) && !IsMipsArchVariant(kLoongson));
|
||||||
|
DCHECK(IsFp64Mode() || IsFpxxMode());
|
||||||
__ mfc1(t0, f4);
|
__ mfc1(t0, f4);
|
||||||
__ mfhc1(t1, f4);
|
__ mfhc1(t1, f4);
|
||||||
__ mfc1(t2, f6);
|
__ mfc1(t2, f6);
|
||||||
@ -425,6 +434,7 @@ TEST(MIPS4) {
|
|||||||
__ mtc1(t2, f4);
|
__ mtc1(t2, f4);
|
||||||
__ mthc1(t3, f4);
|
__ mthc1(t3, f4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the swapped f4 and f5 back to memory.
|
// Store the swapped f4 and f5 back to memory.
|
||||||
__ sdc1(f4, MemOperand(a0, offsetof(T, a)) );
|
__ sdc1(f4, MemOperand(a0, offsetof(T, a)) );
|
||||||
__ sdc1(f6, MemOperand(a0, offsetof(T, c)) );
|
__ sdc1(f6, MemOperand(a0, offsetof(T, c)) );
|
||||||
@ -811,8 +821,6 @@ TEST(MIPS9) {
|
|||||||
|
|
||||||
TEST(MIPS10) {
|
TEST(MIPS10) {
|
||||||
// Test conversions between doubles and words.
|
// Test conversions between doubles and words.
|
||||||
// Test maps double to FP reg pairs in fp32 mode
|
|
||||||
// and into FP reg in fp64 mode.
|
|
||||||
CcTest::InitializeVM();
|
CcTest::InitializeVM();
|
||||||
Isolate* isolate = CcTest::i_isolate();
|
Isolate* isolate = CcTest::i_isolate();
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
@ -830,24 +838,16 @@ TEST(MIPS10) {
|
|||||||
Assembler assm(isolate, NULL, 0);
|
Assembler assm(isolate, NULL, 0);
|
||||||
Label L, C;
|
Label L, C;
|
||||||
|
|
||||||
if (!IsMipsArchVariant(kMips32r2)) return;
|
if (IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kLoongson)) return;
|
||||||
|
|
||||||
// Load all structure elements to registers.
|
// Load all structure elements to registers.
|
||||||
// (f0, f1) = a (fp32), f0 = a (fp64)
|
// (f0, f1) = a (fp32), f0 = a (fp64)
|
||||||
__ ldc1(f0, MemOperand(a0, offsetof(T, a)));
|
__ ldc1(f0, MemOperand(a0, offsetof(T, a)));
|
||||||
|
|
||||||
if (IsFp64Mode()) {
|
__ mfc1(t0, f0); // t0 = f0(31..0)
|
||||||
__ mfc1(t0, f0); // t0 = f0(31..0)
|
__ mfhc1(t1, f0); // t1 = sign_extend(f0(63..32))
|
||||||
__ mfhc1(t1, f0); // t1 = sign_extend(f0(63..32))
|
__ sw(t0, MemOperand(a0, offsetof(T, dbl_mant))); // dbl_mant = t0
|
||||||
__ sw(t0, MemOperand(a0, offsetof(T, dbl_mant))); // dbl_mant = t0
|
__ sw(t1, MemOperand(a0, offsetof(T, dbl_exp))); // dbl_exp = t1
|
||||||
__ sw(t1, MemOperand(a0, offsetof(T, dbl_exp))); // dbl_exp = t1
|
|
||||||
} else {
|
|
||||||
// Save the raw bits of the double.
|
|
||||||
__ mfc1(t0, f0); // t0 = a1
|
|
||||||
__ mfc1(t1, f1); // t1 = a2
|
|
||||||
__ sw(t0, MemOperand(a0, offsetof(T, dbl_mant))); // dbl_mant = t0
|
|
||||||
__ sw(t1, MemOperand(a0, offsetof(T, dbl_exp))); // dbl_exp = t1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert double in f0 to word, save hi/lo parts.
|
// Convert double in f0 to word, save hi/lo parts.
|
||||||
__ cvt_w_d(f0, f0); // a_word = (word)a
|
__ cvt_w_d(f0, f0); // a_word = (word)a
|
||||||
|
Loading…
Reference in New Issue
Block a user