diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h index 1654ac9a048..0ca794527a5 100644 --- a/runtime/vm/assembler_mips.h +++ b/runtime/vm/assembler_mips.h @@ -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(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(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(ds * 2); - FRegister fd = static_cast(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(ds * 2); EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_CVT_S); } - void cvtwd(FRegister fd, DRegister ds) { - FRegister fs = static_cast(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); } diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc index e3cad3d6a91..1a541a62daa 100644 --- a/runtime/vm/assembler_mips_test.cc +++ b/runtime/vm/assembler_mips_test.cc @@ -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); diff --git a/runtime/vm/constants_mips.h b/runtime/vm/constants_mips.h index ccf437a2c6d..bcde75e4c4c 100644 --- a/runtime/vm/constants_mips.h +++ b/runtime/vm/constants_mips.h @@ -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, diff --git a/runtime/vm/disassembler_mips.cc b/runtime/vm/disassembler_mips.cc index b9e0987e1ca..22fe462d8c6 100644 --- a/runtime/vm/disassembler_mips.cc +++ b/runtime/vm/disassembler_mips.cc @@ -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: { diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc index e82bb3d3c29..eb0cc06aaba 100644 --- a/runtime/vm/intermediate_language_mips.cc +++ b/runtime/vm/intermediate_language_mips.cc @@ -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. diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc index 57cb4d6fcca..ddd9c522ec2 100644 --- a/runtime/vm/intrinsifier_mips.cc +++ b/runtime/vm/intrinsifier_mips.cc @@ -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. diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc index 074fc8c7eb0..a828752d6f8 100644 --- a/runtime/vm/simulator_mips.cc +++ b/runtime/vm/simulator_mips.cc @@ -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(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(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(fs_dbl); - } - set_fregister(instr->FdField(), fs_int); - break; - } default: { OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits()); UnimplementedInstruction(instr); diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status index 48d07ffce3a..ea348b60c40 100644 --- a/tests/co19/co19-runtime.status +++ b/tests/co19/co19-runtime.status @@ -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