mirror of
https://github.com/dart-lang/sdk
synced 2024-10-04 18:36:29 +00:00
Use TRUNC.W instead of CVT.W on mips to convert from double to int as to not
depend on the current rounding mode (fixes issue 25900). Add support for TRUNC.W in assembler, disassembler, and simulator. Fix disassembler to understand CVT.S. Remove unused instructions. Update co19 status file. R=rmacnak@google.com Review URL: https://codereview.chromium.org/1765623002 .
This commit is contained in:
parent
3b16570e07
commit
6219753e18
|
@ -585,6 +585,12 @@ class Assembler : public ValueObject {
|
|||
EmitRType(SPECIAL2, rs, rd, rd, 0, CLZ);
|
||||
}
|
||||
|
||||
// Convert a double in ds to a 32-bit signed int in fd rounding towards 0.
|
||||
void truncwd(FRegister fd, DRegister ds) {
|
||||
FRegister fs = static_cast<FRegister>(ds * 2);
|
||||
EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_TRUNC_W);
|
||||
}
|
||||
|
||||
// Convert a 32-bit float in fs to a 64-bit double in dd.
|
||||
void cvtds(DRegister dd, FRegister fs) {
|
||||
FRegister fd = static_cast<FRegister>(dd * 2);
|
||||
|
@ -597,23 +603,12 @@ class Assembler : public ValueObject {
|
|||
EmitFpuRType(COP1, FMT_W, F0, fs, fd, COP1_CVT_D);
|
||||
}
|
||||
|
||||
// Converts a 64-bit signed int in fs to a double in fd.
|
||||
void cvtdl(DRegister dd, DRegister ds) {
|
||||
FRegister fs = static_cast<FRegister>(ds * 2);
|
||||
FRegister fd = static_cast<FRegister>(dd * 2);
|
||||
EmitFpuRType(COP1, FMT_L, F0, fs, fd, COP1_CVT_D);
|
||||
}
|
||||
|
||||
// Convert a 64-bit double in ds to a 32-bit float in fd.
|
||||
void cvtsd(FRegister fd, DRegister ds) {
|
||||
FRegister fs = static_cast<FRegister>(ds * 2);
|
||||
EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_CVT_S);
|
||||
}
|
||||
|
||||
void cvtwd(FRegister fd, DRegister ds) {
|
||||
FRegister fs = static_cast<FRegister>(ds * 2);
|
||||
EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_CVT_W);
|
||||
}
|
||||
|
||||
void div(Register rs, Register rt) {
|
||||
EmitRType(SPECIAL, rs, rt, R0, 0, DIV);
|
||||
}
|
||||
|
|
|
@ -1976,6 +1976,101 @@ ASSEMBLER_TEST_RUN(Cop1COLE_not_taken, test) {
|
|||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1TruncWD, assembler) {
|
||||
__ LoadImmediate(D1, 42.9);
|
||||
__ truncwd(F0, D1);
|
||||
__ mfc1(V0, F0);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Cop1TruncWD, test) {
|
||||
typedef int (*SimpleCode)() DART_UNUSED;
|
||||
EXPECT(test != NULL);
|
||||
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1TruncWD_neg, assembler) {
|
||||
__ LoadImmediate(D1, -42.9);
|
||||
__ truncwd(F0, D1);
|
||||
__ mfc1(V0, F0);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Cop1TruncWD_neg, test) {
|
||||
typedef int (*SimpleCode)() DART_UNUSED;
|
||||
EXPECT(test != NULL);
|
||||
EXPECT_EQ(-42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1TruncWD_NaN, assembler) {
|
||||
// Double non-signaling NaN is 0x7FF8000000000000.
|
||||
__ LoadImmediate(T0, 0x7FF80000);
|
||||
__ mtc1(ZR, F2); // Load upper bits of NaN.
|
||||
__ mtc1(T0, F3); // Load lower bits of NaN.
|
||||
__ truncwd(F0, D1);
|
||||
__ mfc1(V0, F0);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Cop1TruncWD_NaN, test) {
|
||||
typedef double (*SimpleCode)() DART_UNUSED;
|
||||
EXPECT(test != NULL);
|
||||
EXPECT_EQ(kMaxInt32, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1TruncWD_Inf, assembler) {
|
||||
__ LoadImmediate(T0, 0x7FF00000); // +inf
|
||||
__ mtc1(ZR, F2);
|
||||
__ mtc1(T0, F3);
|
||||
__ truncwd(F0, D1);
|
||||
__ mfc1(V0, F0);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Cop1TruncWD_Inf, test) {
|
||||
typedef double (*SimpleCode)() DART_UNUSED;
|
||||
EXPECT(test != NULL);
|
||||
EXPECT_EQ(kMaxInt32, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1TruncWD_Overflow, assembler) {
|
||||
__ LoadImmediate(D1, 2.0*kMaxInt32);
|
||||
__ truncwd(F0, D1);
|
||||
__ mfc1(V0, F0);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Cop1TruncWD_Overflow, test) {
|
||||
typedef double (*SimpleCode)() DART_UNUSED;
|
||||
EXPECT(test != NULL);
|
||||
EXPECT_EQ(kMaxInt32, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1TruncWD_Underflow, assembler) {
|
||||
__ LoadImmediate(D1, 2.0*kMinInt32);
|
||||
__ truncwd(F0, D1);
|
||||
__ mfc1(V0, F0);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Cop1TruncWD_Underflow, test) {
|
||||
typedef double (*SimpleCode)() DART_UNUSED;
|
||||
EXPECT(test != NULL);
|
||||
EXPECT_EQ(kMaxInt32, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1CvtDW, assembler) {
|
||||
__ LoadImmediate(T0, 42);
|
||||
__ mtc1(T0, F2);
|
||||
|
@ -2008,78 +2103,6 @@ ASSEMBLER_TEST_RUN(Cop1CvtDW_neg, test) {
|
|||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1CvtDL, assembler) {
|
||||
if (TargetCPUFeatures::mips_version() == MIPS32r2) {
|
||||
__ LoadImmediate(T0, 0x1);
|
||||
__ mtc1(ZR, F2);
|
||||
__ mtc1(T0, F3); // D0 <- 0x100000000 = 4294967296
|
||||
__ cvtdl(D0, D1);
|
||||
} else {
|
||||
__ LoadImmediate(D0, 4294967296.0);
|
||||
}
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Cop1CvtDL, test) {
|
||||
typedef double (*SimpleCode)() DART_UNUSED;
|
||||
EXPECT(test != NULL);
|
||||
double res = EXECUTE_TEST_CODE_DOUBLE(SimpleCode, test->entry());
|
||||
EXPECT_FLOAT_EQ(4294967296.0, res, 0.001);
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1CvtDL_neg, assembler) {
|
||||
if (TargetCPUFeatures::mips_version() == MIPS32r2) {
|
||||
__ LoadImmediate(T0, 0xffffffff);
|
||||
__ mtc1(T0, F2);
|
||||
__ mtc1(T0, F3); // D0 <- 0xffffffffffffffff = -1
|
||||
__ cvtdl(D0, D1);
|
||||
} else {
|
||||
__ LoadImmediate(D0, -1.0);
|
||||
}
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Cop1CvtDL_neg, test) {
|
||||
typedef double (*SimpleCode)() DART_UNUSED;
|
||||
EXPECT(test != NULL);
|
||||
double res = EXECUTE_TEST_CODE_DOUBLE(SimpleCode, test->entry());
|
||||
EXPECT_FLOAT_EQ(-1.0, res, 0.001);
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1CvtWD, assembler) {
|
||||
__ LoadImmediate(D1, 42.0);
|
||||
__ cvtwd(F0, D1);
|
||||
__ mfc1(V0, F0);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Cop1CvtWD, test) {
|
||||
typedef int (*SimpleCode)() DART_UNUSED;
|
||||
EXPECT(test != NULL);
|
||||
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1CvtWD_neg, assembler) {
|
||||
__ LoadImmediate(D1, -42.0);
|
||||
__ cvtwd(F0, D1);
|
||||
__ mfc1(V0, F0);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Cop1CvtWD_neg, test) {
|
||||
typedef int (*SimpleCode)() DART_UNUSED;
|
||||
EXPECT(test != NULL);
|
||||
EXPECT_EQ(-42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Cop1CvtSD, assembler) {
|
||||
__ LoadImmediate(D2, -42.42);
|
||||
__ cvtsd(F2, D2);
|
||||
|
|
|
@ -440,9 +440,9 @@ enum Cop1Function {
|
|||
COP1_SQRT = 0x04,
|
||||
COP1_MOV = 0x06,
|
||||
COP1_NEG = 0x07,
|
||||
COP1_TRUNC_W = 0x0d,
|
||||
COP1_CVT_S = 0x20,
|
||||
COP1_CVT_D = 0x21,
|
||||
COP1_CVT_W = 0x24,
|
||||
COP1_C_F = 0x30,
|
||||
COP1_C_UN = 0x31,
|
||||
COP1_C_EQ = 0x32,
|
||||
|
|
|
@ -581,12 +581,16 @@ void MIPSDecoder::DecodeCop1(Instr* instr) {
|
|||
Format(instr, "c.ule.'fmt 'fs, 'ft");
|
||||
break;
|
||||
}
|
||||
case COP1_CVT_D: {
|
||||
Format(instr, "cvt.d.'fmt 'fd, 'fs");
|
||||
case COP1_TRUNC_W: {
|
||||
Format(instr, "trunc.w.'fmt 'fd, 'fs");
|
||||
break;
|
||||
}
|
||||
case COP1_CVT_W: {
|
||||
Format(instr, "cvt.w.'fmt 'fd, 'fs");
|
||||
case COP1_CVT_S: {
|
||||
Format(instr, "cvt.s.'fmt 'fd, 'fs");
|
||||
break;
|
||||
}
|
||||
case COP1_CVT_D: {
|
||||
Format(instr, "cvt.d.'fmt 'fd, 'fs");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
|
|
@ -4206,7 +4206,7 @@ void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
ASSERT(result == V0);
|
||||
ASSERT(result != value_obj);
|
||||
__ LoadDFromOffset(DTMP, value_obj, Double::value_offset() - kHeapObjectTag);
|
||||
__ cvtwd(STMP1, DTMP);
|
||||
__ truncwd(STMP1, DTMP);
|
||||
__ mfc1(result, STMP1);
|
||||
|
||||
// Overflow is signaled with minint.
|
||||
|
@ -4229,7 +4229,7 @@ void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
instance_call()->token_pos(),
|
||||
target,
|
||||
kNumberOfArguments,
|
||||
Object::null_array(), // No argument names.,
|
||||
Object::null_array(), // No argument names.
|
||||
locs(),
|
||||
ICData::Handle());
|
||||
__ Bind(&done);
|
||||
|
@ -4252,7 +4252,7 @@ void DoubleToSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptDoubleToSmi);
|
||||
Register result = locs()->out(0).reg();
|
||||
DRegister value = locs()->in(0).fpu_reg();
|
||||
__ cvtwd(STMP1, value);
|
||||
__ truncwd(STMP1, value);
|
||||
__ mfc1(result, STMP1);
|
||||
|
||||
// Check for overflow and that it fits into Smi.
|
||||
|
|
|
@ -1538,7 +1538,7 @@ void Intrinsifier::DoubleToInteger(Assembler* assembler) {
|
|||
__ lw(T0, Address(SP, 0 * kWordSize));
|
||||
__ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag);
|
||||
|
||||
__ cvtwd(F2, D0);
|
||||
__ truncwd(F2, D0);
|
||||
__ mfc1(V0, F2);
|
||||
|
||||
// Overflow is signaled with minint.
|
||||
|
|
|
@ -1888,6 +1888,28 @@ void Simulator::DecodeCop1(Instr* instr) {
|
|||
(fs_val <= ft_val) || isnan(fs_val) || isnan(ft_val));
|
||||
break;
|
||||
}
|
||||
case COP1_TRUNC_W: {
|
||||
switch (instr->FormatField()) {
|
||||
case FMT_D: {
|
||||
double fs_dbl = get_fregister_double(instr->FsField());
|
||||
int32_t fs_int;
|
||||
if (isnan(fs_dbl) || isinf(fs_dbl) || (fs_dbl > kMaxInt32) ||
|
||||
(fs_dbl < kMinInt32)) {
|
||||
fs_int = kMaxInt32;
|
||||
} else {
|
||||
fs_int = static_cast<int32_t>(fs_dbl);
|
||||
}
|
||||
set_fregister(instr->FdField(), fs_int);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits());
|
||||
UnimplementedInstruction(instr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case COP1_CVT_D: {
|
||||
switch (instr->FormatField()) {
|
||||
case FMT_W: {
|
||||
|
@ -1902,34 +1924,6 @@ void Simulator::DecodeCop1(Instr* instr) {
|
|||
set_fregister_double(instr->FdField(), fs_dbl);
|
||||
break;
|
||||
}
|
||||
case FMT_L: {
|
||||
int64_t fs_int = get_fregister_long(instr->FsField());
|
||||
double fs_dbl = static_cast<double>(fs_int);
|
||||
set_fregister_double(instr->FdField(), fs_dbl);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits());
|
||||
UnimplementedInstruction(instr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case COP1_CVT_W: {
|
||||
switch (instr->FormatField()) {
|
||||
case FMT_D: {
|
||||
double fs_dbl = get_fregister_double(instr->FsField());
|
||||
int32_t fs_int;
|
||||
if (isnan(fs_dbl) || isinf(fs_dbl) || (fs_dbl > INT_MAX) ||
|
||||
(fs_dbl < INT_MIN)) {
|
||||
fs_int = INT_MIN;
|
||||
} else {
|
||||
fs_int = static_cast<int32_t>(fs_dbl);
|
||||
}
|
||||
set_fregister(instr->FdField(), fs_int);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits());
|
||||
UnimplementedInstruction(instr);
|
||||
|
|
|
@ -59,9 +59,6 @@ LibTest/core/List/List_class_A01_t02: Pass, Slow
|
|||
[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && ($arch != x64 && $arch != simarm64 && $arch != arm64) ]
|
||||
LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
|
||||
|
||||
[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == mips ]
|
||||
LibTest/core/double/toInt_A01_t01: Fail # Issue 25900
|
||||
|
||||
[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && ($arch == mips || $arch == arm64) ]
|
||||
# These tests take too much memory (300 MB) for our 1 GB test machine.
|
||||
# co19 issue 673. http://code.google.com/p/co19/issues/detail?id=673
|
||||
|
|
Loading…
Reference in a new issue