MIPS: Add float instructions and test coverage, part two
authorDjordje.Pesic <Djordje.Pesic@imgtec.com>
Fri, 22 May 2015 13:49:20 +0000 (06:49 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 22 May 2015 13:49:00 +0000 (13:49 +0000)
Implement assembler, disassembler tests for all instructions for mips32 and mips64. Additionally, add missing single precision float instructions for r2 and r6 architecture variants in assembler, simulator and disassembler with corresponding tests.

Review URL: https://codereview.chromium.org/1145223002

Cr-Commit-Position: refs/heads/master@{#28595}

18 files changed:
src/mips/assembler-mips.cc
src/mips/assembler-mips.h
src/mips/constants-mips.cc
src/mips/constants-mips.h
src/mips/disasm-mips.cc
src/mips/simulator-mips.cc
src/mips/simulator-mips.h
src/mips64/assembler-mips64.cc
src/mips64/assembler-mips64.h
src/mips64/constants-mips64.cc
src/mips64/constants-mips64.h
src/mips64/disasm-mips64.cc
src/mips64/simulator-mips64.cc
src/mips64/simulator-mips64.h
test/cctest/test-assembler-mips.cc
test/cctest/test-assembler-mips64.cc
test/cctest/test-disasm-mips.cc
test/cctest/test-disasm-mips64.cc

index 1535ff9d06140599e602ec0b9f32be677dd684b4..50732026b09667d870dd00effd0880efeedbadb4 100644 (file)
@@ -1936,6 +1936,12 @@ void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
 }
 
 
+void Assembler::bitswap(Register rd, Register rt) {
+  DCHECK(kArchVariant == kMips32r6);
+  GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BITSWAP);
+}
+
+
 void Assembler::pref(int32_t hint, const MemOperand& rs) {
   DCHECK(!IsMipsArchVariant(kLoongson));
   DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
@@ -2422,6 +2428,18 @@ void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
 }
 
 
+void Assembler::class_s(FPURegister fd, FPURegister fs) {
+  DCHECK(IsMipsArchVariant(kMips32r6));
+  GenInstrRegister(COP1, S, f0, fs, fd, CLASS_S);
+}
+
+
+void Assembler::class_d(FPURegister fd, FPURegister fs) {
+  DCHECK(IsMipsArchVariant(kMips32r6));
+  GenInstrRegister(COP1, D, f0, fs, fd, CLASS_D);
+}
+
+
 void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister fs,
                     FPURegister ft) {
   DCHECK(IsMipsArchVariant(kMips32r6));
@@ -2500,7 +2518,7 @@ void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
 
 
 void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
-  DCHECK(IsMipsArchVariant(kMips32r2));
+  DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
   GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
 }
 
@@ -2537,6 +2555,17 @@ void Assembler::cmp(FPUCondition cond, SecondaryField fmt,
 }
 
 
+void Assembler::cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs,
+                      FPURegister ft) {
+  cmp(cond, W, fd, fs, ft);
+}
+
+void Assembler::cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs,
+                      FPURegister ft) {
+  cmp(cond, L, fd, fs, ft);
+}
+
+
 void Assembler::bc1eqz(int16_t offset, FPURegister ft) {
   DCHECK(IsMipsArchVariant(kMips32r6));
   Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask);
@@ -2555,6 +2584,7 @@ void Assembler::bc1nez(int16_t offset, FPURegister ft) {
 void Assembler::c(FPUCondition cond, SecondaryField fmt,
     FPURegister fs, FPURegister ft, uint16_t cc) {
   DCHECK(is_uint3(cc));
+  DCHECK(fmt == S || fmt == D);
   DCHECK((fmt & ~(31 << kRsShift)) == 0);
   Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
       | cc << 8 | 3 << 4 | cond;
@@ -2562,6 +2592,18 @@ void Assembler::c(FPUCondition cond, SecondaryField fmt,
 }
 
 
+void Assembler::c_s(FPUCondition cond, FPURegister fs, FPURegister ft,
+                    uint16_t cc) {
+  c(cond, S, fs, ft, cc);
+}
+
+
+void Assembler::c_d(FPUCondition cond, FPURegister fs, FPURegister ft,
+                    uint16_t cc) {
+  c(cond, D, fs, ft, cc);
+}
+
+
 void Assembler::fcmp(FPURegister src1, const double src2,
       FPUCondition cond) {
   DCHECK(src2 == 0.0);
index 71942c2047cc797fd62e05040a425829ae2b1edf..ff05aab1875d7bb8a9f8fb099195705969ac1328 100644 (file)
@@ -878,6 +878,7 @@ class Assembler : public AssemblerBase {
   void clz(Register rd, Register rs);
   void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
   void ext_(Register rt, Register rs, uint16_t pos, uint16_t size);
+  void bitswap(Register rd, Register rt);
 
   // --------Coprocessor-instructions----------------
 
@@ -946,6 +947,9 @@ class Assembler : public AssemblerBase {
   void ceil_l_s(FPURegister fd, FPURegister fs);
   void ceil_l_d(FPURegister fd, FPURegister fs);
 
+  void class_s(FPURegister fd, FPURegister fs);
+  void class_d(FPURegister fd, FPURegister fs);
+
   void min(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
   void mina(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
   void max(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
@@ -970,6 +974,8 @@ class Assembler : public AssemblerBase {
   // Conditions and branches for MIPSr6.
   void cmp(FPUCondition cond, SecondaryField fmt,
          FPURegister fd, FPURegister ft, FPURegister fs);
+  void cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs, FPURegister ft);
+  void cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs, FPURegister ft);
 
   void bc1eqz(int16_t offset, FPURegister ft);
   void bc1eqz(Label* L, FPURegister ft) {
@@ -983,6 +989,8 @@ class Assembler : public AssemblerBase {
   // Conditions and branches for non MIPSr6.
   void c(FPUCondition cond, SecondaryField fmt,
          FPURegister ft, FPURegister fs, uint16_t cc = 0);
+  void c_s(FPUCondition cond, FPURegister ft, FPURegister fs, uint16_t cc = 0);
+  void c_d(FPUCondition cond, FPURegister ft, FPURegister fs, uint16_t cc = 0);
 
   void bc1f(int16_t offset, uint16_t cc = 0);
   void bc1f(Label* L, uint16_t cc = 0) { bc1f(branch_offset(L, false)>>2, cc); }
index 7ecfe742955950e4d008480a5652b45d149d7fce..9facbda94d4810a39c7f7695ab0351d7096db893 100644 (file)
@@ -272,6 +272,7 @@ Instruction::Type Instruction::InstructionType() const {
       switch (FunctionFieldRaw()) {
         case INS:
         case EXT:
+        case BITSWAP:
           return kRegisterType;
         default:
           return kUnsupported;
index f3a331ef0253dda263143738f6871312be158d22..bdeb8c060b2c0e6f97a41490506d860f5d12f28c 100644 (file)
@@ -435,6 +435,7 @@ enum SecondaryField {
   // SPECIAL3 Encoding of Function Field.
   EXT = ((0 << 3) + 0),
   INS = ((0 << 3) + 4),
+  BITSWAP = ((4 << 3) + 0),
 
   // REGIMM  encoding of rt Field.
   BLTZ = ((0 << 3) + 0) << 16,
@@ -457,6 +458,7 @@ enum SecondaryField {
   L = ((2 << 3) + 5) << 21,
   PS = ((2 << 3) + 6) << 21,
   // COP1 Encoding of Function Field When rs=S.
+
   ADD_S = ((0 << 3) + 0),
   SUB_S = ((0 << 3) + 1),
   MUL_S = ((0 << 3) + 2),
@@ -475,10 +477,12 @@ enum SecondaryField {
   FLOOR_W_S = ((1 << 3) + 7),
   RECIP_S = ((2 << 3) + 5),
   RSQRT_S = ((2 << 3) + 6),
+  CLASS_S = ((3 << 3) + 3),
   CVT_D_S = ((4 << 3) + 1),
   CVT_W_S = ((4 << 3) + 4),
   CVT_L_S = ((4 << 3) + 5),
   CVT_PS_S = ((4 << 3) + 6),
+
   // COP1 Encoding of Function Field When rs=D.
   ADD_D = ((0 << 3) + 0),
   SUB_D = ((0 << 3) + 1),
@@ -498,6 +502,11 @@ enum SecondaryField {
   FLOOR_W_D = ((1 << 3) + 7),
   RECIP_D = ((2 << 3) + 5),
   RSQRT_D = ((2 << 3) + 6),
+  CLASS_D = ((3 << 3) + 3),
+  MIN = ((3 << 3) + 4),
+  MINA = ((3 << 3) + 5),
+  MAX = ((3 << 3) + 6),
+  MAXA = ((3 << 3) + 7),
   CVT_S_D = ((4 << 3) + 0),
   CVT_W_D = ((4 << 3) + 4),
   CVT_L_D = ((4 << 3) + 5),
@@ -509,6 +518,7 @@ enum SecondaryField {
   C_ULT_D = ((6 << 3) + 5),
   C_OLE_D = ((6 << 3) + 6),
   C_ULE_D = ((6 << 3) + 7),
+
   // COP1 Encoding of Function Field When rs=W or L.
   CVT_S_W = ((4 << 3) + 0),
   CVT_D_W = ((4 << 3) + 1),
@@ -551,10 +561,6 @@ enum SecondaryField {
   CMP_SUGT = ((3 << 3) + 6),  // Reserved, not implemented.
   CMP_SOGT = ((3 << 3) + 7),  // Reserved, not implemented.
 
-  MIN = ((3 << 3) + 4),
-  MINA = ((3 << 3) + 5),
-  MAX = ((3 << 3) + 6),
-  MAXA = ((3 << 3) + 7),
   SEL = ((2 << 3) + 0),
   MOVZ_C = ((2 << 3) + 2),
   MOVN_C = ((2 << 3) + 3),
@@ -698,14 +704,21 @@ inline Condition CommuteCondition(Condition cc) {
 enum FPUCondition {
   kNoFPUCondition = -1,
 
-  F     = 0,  // False.
-  UN    = 1,  // Unordered.
-  EQ    = 2,  // Equal.
-  UEQ   = 3,  // Unordered or Equal.
-  OLT   = 4,  // Ordered or Less Than.
-  ULT   = 5,  // Unordered or Less Than.
-  OLE   = 6,  // Ordered or Less Than or Equal.
-  ULE   = 7   // Unordered or Less Than or Equal.
+  F = 0x00,    // False.
+  UN = 0x01,   // Unordered.
+  EQ = 0x02,   // Equal.
+  UEQ = 0x03,  // Unordered or Equal.
+  OLT = 0x04,  // Ordered or Less Than, on Mips release < 6.
+  LT = 0x04,   // Ordered or Less Than, on Mips release >= 6.
+  ULT = 0x05,  // Unordered or Less Than.
+  OLE = 0x06,  // Ordered or Less Than or Equal, on Mips release < 6.
+  LE = 0x06,   // Ordered or Less Than or Equal, on Mips release >= 6.
+  ULE = 0x07,  // Unordered or Less Than or Equal.
+
+  // Following constants are available on Mips release >= 6 only.
+  ORD = 0x11,  // Ordered, on Mips release >= 6.
+  UNE = 0x12,  // Not equal, on Mips release >= 6.
+  NE = 0x13,   // Ordered Greater Than or Less Than. on Mips >= 6 only.
 };
 
 
index 32dffff1d2945212a8d81997f997980ce3cc21ae..f68876456e1f174c9d954930dc07ed921dda1b13 100644 (file)
@@ -581,6 +581,9 @@ bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
     case CEIL_W_D:
       Format(instr, "ceil.w.'t 'fd, 'fs");
       break;
+    case CLASS_D:
+      Format(instr, "class.'t 'fd, 'fs");
+      break;
     case CEIL_L_D:
       Format(instr, "ceil.l.'t 'fd, 'fs");
       break;
@@ -647,6 +650,9 @@ void Decoder::DecodeTypeRegisterLRsType(Instruction* instr) {
     case CVT_S_L:
       Format(instr, "cvt.s.l 'fd, 'fs");
       break;
+    case CMP_AF:
+      Format(instr, "cmp.af.d  'fd,  'fs, 'ft");
+      break;
     case CMP_UN:
       Format(instr, "cmp.un.d  'fd,  'fs, 'ft");
       break;
@@ -950,6 +956,14 @@ void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* instr) {
       }
       break;
     }
+    case BITSWAP: {
+      if (IsMipsArchVariant(kMips32r6)) {
+        Format(instr, "bitswap 'rd, 'rt");
+      } else {
+        Unknown(instr);
+      }
+      break;
+    }
     default:
       UNREACHABLE();
   }
index a8c3bedcd3098dbee0e42eed6b440e285ee123d9..abddd910ce45aedd6816941cba52b2198b38b0fd 100644 (file)
@@ -1302,6 +1302,8 @@ unsigned int Simulator::get_fcsr_rounding_mode() {
 }
 
 
+// Sets the rounding error codes in FCSR based on the result of the rounding.
+// Returns true if the operation was invalid.
 bool Simulator::set_fcsr_round_error(double original, double rounded) {
   bool ret = false;
   double max_int32 = std::numeric_limits<int32_t>::max();
@@ -1364,6 +1366,8 @@ bool Simulator::set_fcsr_round64_error(double original, double rounded) {
 }
 
 
+// Sets the rounding error codes in FCSR based on the result of the rounding.
+// Returns true if the operation was invalid.
 bool Simulator::set_fcsr_round_error(float original, float rounded) {
   bool ret = false;
   double max_int32 = std::numeric_limits<int32_t>::max();
@@ -1467,6 +1471,129 @@ void Simulator::round_according_to_fcsr(double toRound, double& rounded,
 }
 
 
+void Simulator::round_according_to_fcsr(float toRound, float& rounded,
+                                        int32_t& rounded_int, float fs) {
+  // 0 RN (round to nearest): Round a result to the nearest
+  // representable value; if the result is exactly halfway between
+  // two representable values, round to zero. Behave like round_w_d.
+
+  // 1 RZ (round toward zero): Round a result to the closest
+  // representable value whose absolute value is less than or
+  // equal to the infinitely accurate result. Behave like trunc_w_d.
+
+  // 2 RP (round up, or toward  infinity): Round a result to the
+  // next representable value up. Behave like ceil_w_d.
+
+  // 3 RD (round down, or toward âˆ’infinity): Round a result to
+  // the next representable value down. Behave like floor_w_d.
+  switch (get_fcsr_rounding_mode()) {
+    case kRoundToNearest:
+      rounded = std::floor(fs + 0.5);
+      rounded_int = static_cast<int32_t>(rounded);
+      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
+        // If the number is halfway between two integers,
+        // round to the even one.
+        rounded_int--;
+      }
+      break;
+    case kRoundToZero:
+      rounded = trunc(fs);
+      rounded_int = static_cast<int32_t>(rounded);
+      break;
+    case kRoundToPlusInf:
+      rounded = std::ceil(fs);
+      rounded_int = static_cast<int32_t>(rounded);
+      break;
+    case kRoundToMinusInf:
+      rounded = std::floor(fs);
+      rounded_int = static_cast<int32_t>(rounded);
+      break;
+  }
+}
+
+
+void Simulator::round64_according_to_fcsr(double toRound, double& rounded,
+                                          int64_t& rounded_int, double fs) {
+  // 0 RN (round to nearest): Round a result to the nearest
+  // representable value; if the result is exactly halfway between
+  // two representable values, round to zero. Behave like round_w_d.
+
+  // 1 RZ (round toward zero): Round a result to the closest
+  // representable value whose absolute value is less than or.
+  // equal to the infinitely accurate result. Behave like trunc_w_d.
+
+  // 2 RP (round up, or toward +infinity): Round a result to the
+  // next representable value up. Behave like ceil_w_d.
+
+  // 3 RN (round down, or toward âˆ’infinity): Round a result to
+  // the next representable value down. Behave like floor_w_d.
+  switch (FCSR_ & 3) {
+    case kRoundToNearest:
+      rounded = std::floor(fs + 0.5);
+      rounded_int = static_cast<int64_t>(rounded);
+      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
+        // If the number is halfway between two integers,
+        // round to the even one.
+        rounded_int--;
+      }
+      break;
+    case kRoundToZero:
+      rounded = trunc(fs);
+      rounded_int = static_cast<int64_t>(rounded);
+      break;
+    case kRoundToPlusInf:
+      rounded = std::ceil(fs);
+      rounded_int = static_cast<int64_t>(rounded);
+      break;
+    case kRoundToMinusInf:
+      rounded = std::floor(fs);
+      rounded_int = static_cast<int64_t>(rounded);
+      break;
+  }
+}
+
+
+void Simulator::round64_according_to_fcsr(float toRound, float& rounded,
+                                          int64_t& rounded_int, float fs) {
+  // 0 RN (round to nearest): Round a result to the nearest
+  // representable value; if the result is exactly halfway between
+  // two representable values, round to zero. Behave like round_w_d.
+
+  // 1 RZ (round toward zero): Round a result to the closest
+  // representable value whose absolute value is less than or.
+  // equal to the infinitely accurate result. Behave like trunc_w_d.
+
+  // 2 RP (round up, or toward +infinity): Round a result to the
+  // next representable value up. Behave like ceil_w_d.
+
+  // 3 RN (round down, or toward âˆ’infinity): Round a result to
+  // the next representable value down. Behave like floor_w_d.
+  switch (FCSR_ & 3) {
+    case kRoundToNearest:
+      rounded = std::floor(fs + 0.5);
+      rounded_int = static_cast<int64_t>(rounded);
+      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
+        // If the number is halfway between two integers,
+        // round to the even one.
+        rounded_int--;
+      }
+      break;
+    case kRoundToZero:
+      rounded = trunc(fs);
+      rounded_int = static_cast<int64_t>(rounded);
+      break;
+    case kRoundToPlusInf:
+      rounded = std::ceil(fs);
+      rounded_int = static_cast<int64_t>(rounded);
+      break;
+    case kRoundToMinusInf:
+      rounded = std::floor(fs);
+      rounded_int = static_cast<int64_t>(rounded);
+      break;
+  }
+}
+
+
 // Raw access to the PC register.
 void Simulator::set_pc(int32_t value) {
   pc_modified_ = true;
@@ -2284,6 +2411,30 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
           *alu_out = (rs_u & (mask << lsb)) >> lsb;
           break;
         }
+        case BITSWAP: {  // Mips32r6 instruction
+          uint32_t input = static_cast<uint32_t>(rt);
+          uint32_t output = 0;
+          uint8_t i_byte, o_byte;
+
+          // Reverse the bit in byte for each individual byte
+          for (int i = 0; i < 4; i++) {
+            output = output >> 8;
+            i_byte = input & 0xff;
+
+            // Fast way to reverse bits in byte
+            // Devised by Sean Anderson, July 13, 2001
+            o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
+                                           (i_byte * 0x8020LU & 0x88440LU)) *
+                                              0x10101LU >>
+                                          16);
+
+            output = output | (static_cast<uint32_t>(o_byte << 24));
+            input = input >> 8;
+          }
+
+          *alu_out = static_cast<int32_t>(output);
+          break;
+        }
         default:
           UNREACHABLE();
       }
@@ -2570,14 +2721,19 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
       set_fpu_register_float(fd_reg, static_cast<float>(fs));
       break;
     case CVT_L_D: {  // Mips32r2: Truncate double to 64-bit long-word.
-      double rounded = trunc(fs);
-      i64 = static_cast<int64_t>(rounded);
       if (IsFp64Mode()) {
-        set_fpu_register(fd_reg, i64);
+        int64_t result;
+        double rounded;
+        round64_according_to_fcsr(fs, rounded, result, fs);
+        set_fpu_register(fd_reg, result);
+        if (set_fcsr_round64_error(fs, rounded)) {
+          set_fpu_register(fd_reg, kFPU64InvalidResult);
+        }
       } else {
         UNSUPPORTED();
       }
       break;
+      break;
     }
     case TRUNC_L_D: {  // Mips32r2 instruction.
       DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
@@ -2641,9 +2797,75 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
       }
       break;
     }
-    case C_F_D:
-      UNIMPLEMENTED_MIPS();
+    case CLASS_D: {  // Mips32r6 instruction
+      // Convert double input to uint64_t for easier bit manipulation
+      uint64_t classed = bit_cast<uint64_t>(fs);
+
+      // Extracting sign, exponent and mantissa from the input double
+      uint32_t sign = (classed >> 63) & 1;
+      uint32_t exponent = (classed >> 52) & 0x00000000000007ff;
+      uint64_t mantissa = classed & 0x000fffffffffffff;
+      uint64_t result;
+      double dResult;
+
+      // Setting flags if input double is negative infinity,
+      // positive infinity, negative zero or positive zero
+      bool negInf = (classed == 0xFFF0000000000000);
+      bool posInf = (classed == 0x7FF0000000000000);
+      bool negZero = (classed == 0x8000000000000000);
+      bool posZero = (classed == 0x0000000000000000);
+
+      bool signalingNan;
+      bool quietNan;
+      bool negSubnorm;
+      bool posSubnorm;
+      bool negNorm;
+      bool posNorm;
+
+      // Setting flags if double is NaN
+      signalingNan = false;
+      quietNan = false;
+      if (!negInf && !posInf && exponent == 0x7ff) {
+        quietNan = ((mantissa & 0x0008000000000000) != 0) &&
+                   ((mantissa & (0x0008000000000000 - 1)) == 0);
+        signalingNan = !quietNan;
+      }
+
+      // Setting flags if double is subnormal number
+      posSubnorm = false;
+      negSubnorm = false;
+      if ((exponent == 0) && (mantissa != 0)) {
+        DCHECK(sign == 0 || sign == 1);
+        posSubnorm = (sign == 0);
+        negSubnorm = (sign == 1);
+      }
+
+      // Setting flags if double is normal number
+      posNorm = false;
+      negNorm = false;
+      if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
+          !quietNan && !negZero && !posZero) {
+        DCHECK(sign == 0 || sign == 1);
+        posNorm = (sign == 0);
+        negNorm = (sign == 1);
+      }
+
+      // Calculating result according to description of CLASS.D instruction
+      result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
+               (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
+               (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
+
+      DCHECK(result != 0);
+
+      dResult = bit_cast<double>(result);
+      set_fpu_register_double(fd_reg, dResult);
+
+      break;
+    }
+    case C_F_D: {
+      set_fcsr_bit(fcsr_cc, false);
       break;
+    }
     default:
       UNREACHABLE();
   }
@@ -2652,7 +2874,10 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
 
 void Simulator::DecodeTypeRegisterWRsType(Instruction* instr, int32_t& alu_out,
                                           const int32_t& fd_reg,
-                                          const int32_t& fs_reg) {
+                                          const int32_t& fs_reg,
+                                          const int32_t& ft_reg) {
+  float fs = get_fpu_register_float(fs_reg);
+  float ft = get_fpu_register_float(ft_reg);
   switch (instr->FunctionFieldRaw()) {
     case CVT_S_W:  // Convert word to float (single).
       alu_out = get_fpu_register_signed_word(fs_reg);
@@ -2662,7 +2887,80 @@ void Simulator::DecodeTypeRegisterWRsType(Instruction* instr, int32_t& alu_out,
       alu_out = get_fpu_register_signed_word(fs_reg);
       set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
       break;
-    default:  // Mips64r6 CMP.S instructions unimplemented.
+    case CMP_AF:
+      set_fpu_register_word(fd_reg, 0);
+      break;
+    case CMP_UN:
+      if (std::isnan(fs) || std::isnan(ft)) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_EQ:
+      if (fs == ft) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_UEQ:
+      if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_LT:
+      if (fs < ft) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_ULT:
+      if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_LE:
+      if (fs <= ft) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_ULE:
+      if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_OR:
+      if (!std::isnan(fs) && !std::isnan(ft)) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_UNE:
+      if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_NE:
+      if (fs != ft) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    default:
       UNREACHABLE();
   }
 }
@@ -2754,6 +3052,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
       set_fpu_register_float(fd_reg, result);
       break;
     }
+    case C_F_D:
+      set_fcsr_bit(fcsr_cc, false);
+      break;
     case C_UN_D:
       set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
       break;
@@ -2782,6 +3083,72 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
       DCHECK(IsMipsArchVariant(kMips32r6));
       set_fpu_register_float(fd_reg, (fd_int & 0x1) == 0 ? fs : ft);
       break;
+    case CLASS_S: {  // Mips32r6 instruction
+      // Convert float input to uint32_t for easier bit manipulation
+      float fs = get_fpu_register_float(fs_reg);
+      uint32_t classed = bit_cast<uint32_t>(fs);
+
+      // Extracting sign, exponent and mantissa from the input float
+      uint32_t sign = (classed >> 31) & 1;
+      uint32_t exponent = (classed >> 23) & 0x000000ff;
+      uint32_t mantissa = classed & 0x007fffff;
+      uint32_t result;
+      float fResult;
+
+      // Setting flags if input float is negative infinity,
+      // positive infinity, negative zero or positive zero
+      bool negInf = (classed == 0xFF800000);
+      bool posInf = (classed == 0x7F800000);
+      bool negZero = (classed == 0x80000000);
+      bool posZero = (classed == 0x00000000);
+
+      bool signalingNan;
+      bool quietNan;
+      bool negSubnorm;
+      bool posSubnorm;
+      bool negNorm;
+      bool posNorm;
+
+      // Setting flags if float is NaN
+      signalingNan = false;
+      quietNan = false;
+      if (!negInf && !posInf && (exponent == 0xff)) {
+        quietNan = ((mantissa & 0x00200000) == 0) &&
+                   ((mantissa & (0x00200000 - 1)) == 0);
+        signalingNan = !quietNan;
+      }
+
+      // Setting flags if float is subnormal number
+      posSubnorm = false;
+      negSubnorm = false;
+      if ((exponent == 0) && (mantissa != 0)) {
+        DCHECK(sign == 0 || sign == 1);
+        posSubnorm = (sign == 0);
+        negSubnorm = (sign == 1);
+      }
+
+      // Setting flags if float is normal number
+      posNorm = false;
+      negNorm = false;
+      if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
+          !quietNan && !negZero && !posZero) {
+        DCHECK(sign == 0 || sign == 1);
+        posNorm = (sign == 0);
+        negNorm = (sign == 1);
+      }
+
+      // Calculating result according to description of CLASS.S instruction
+      result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
+               (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
+               (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
+
+      DCHECK(result != 0);
+
+      fResult = bit_cast<float>(result);
+      set_fpu_register_float(fd_reg, fResult);
+
+      break;
+    }
     case SELEQZ_C:
       DCHECK(IsMipsArchVariant(kMips32r6));
       set_fpu_register_float(
@@ -2994,6 +3361,30 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
         set_fpu_register_float(fd_reg, result);
       }
       break;
+    case CVT_L_S: {
+      if (IsFp64Mode()) {
+        int64_t result;
+        float rounded;
+        round64_according_to_fcsr(fs, rounded, result, fs);
+        set_fpu_register(fd_reg, result);
+        if (set_fcsr_round64_error(fs, rounded)) {
+          set_fpu_register(fd_reg, kFPU64InvalidResult);
+        }
+      } else {
+        UNSUPPORTED();
+      }
+      break;
+    }
+    case CVT_W_S: {
+      float rounded;
+      int32_t result;
+      round_according_to_fcsr(fs, rounded, result, fs);
+      set_fpu_register_word(fd_reg, result);
+      if (set_fcsr_round_error(fs, rounded)) {
+        set_fpu_register_word(fd_reg, kFPUInvalidResult);
+      }
+      break;
+    }
     default:
       // CVT_W_S CVT_L_S  ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
       // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
@@ -3022,10 +3413,16 @@ void Simulator::DecodeTypeRegisterLRsType(Instruction* instr,
       set_fpu_register_double(fd_reg, static_cast<double>(i64));
       break;
     case CVT_S_L:
-      UNIMPLEMENTED_MIPS();
+      if (IsFp64Mode()) {
+        i64 = get_fpu_register(fs_reg);
+      } else {
+        i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg));
+        i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg + 1)) << 32;
+      }
+      set_fpu_register_float(fd_reg, static_cast<float>(i64));
       break;
     case CMP_AF:  // Mips64r6 CMP.D instructions.
-      UNIMPLEMENTED_MIPS();
+      set_fpu_register(fd_reg, 0);
       break;
     case CMP_UN:
       if (std::isnan(fs) || std::isnan(ft)) {
@@ -3076,7 +3473,28 @@ void Simulator::DecodeTypeRegisterLRsType(Instruction* instr,
         set_fpu_register(fd_reg, 0);
       }
       break;
-    default:  // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED.
+    case CMP_OR:
+      if (!std::isnan(fs) && !std::isnan(ft)) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_UNE:
+      if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_NE:
+      if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    default:
       UNREACHABLE();
   }
 }
@@ -3120,7 +3538,7 @@ void Simulator::DecodeTypeRegisterCOP1(
       DecodeTypeRegisterDRsType(instr, fr_reg, fs_reg, ft_reg, fd_reg);
       break;
     case W:
-      DecodeTypeRegisterWRsType(instr, alu_out, fd_reg, fs_reg);
+      DecodeTypeRegisterWRsType(instr, alu_out, fd_reg, fs_reg, ft_reg);
       break;
     case L:
       DecodeTypeRegisterLRsType(instr, ft_reg, fs_reg, fd_reg);
@@ -3335,6 +3753,7 @@ void Simulator::DecodeTypeRegisterSPECIAL2(Instruction* instr,
 
 void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
                                            const int32_t& rt_reg,
+                                           const int32_t& rd_reg,
                                            int32_t& alu_out) {
   switch (instr->FunctionFieldRaw()) {
     case INS:
@@ -3345,6 +3764,9 @@ void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
       // Ext instr leaves result in Rt, rather than Rd.
       set_register(rt_reg, alu_out);
       break;
+    case BITSWAP:
+      set_register(rd_reg, alu_out);
+      break;
     default:
       UNREACHABLE();
   }
@@ -3412,7 +3834,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
       DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out);
       break;
     case SPECIAL3:
-      DecodeTypeRegisterSPECIAL3(instr, rt_reg, alu_out);
+      DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
       break;
     // Unimplemented opcodes raised an error in the configuration step before,
     // so we can use the default here to set the destination register in common
index de06200850b5c52a03ca7b0533dcd091270c14d3..0e9c2129837f3a9265c248ed0f37842bc15c2707 100644 (file)
@@ -183,6 +183,12 @@ class Simulator {
   bool set_fcsr_round64_error(float original, float rounded);
   void round_according_to_fcsr(double toRound, double& rounded,
                                int32_t& rounded_int, double fs);
+  void round_according_to_fcsr(float toRound, float& rounded,
+                               int32_t& rounded_int, float fs);
+  void round64_according_to_fcsr(double toRound, double& rounded,
+                                 int64_t& rounded_int, double fs);
+  void round64_according_to_fcsr(float toRound, float& rounded,
+                                 int64_t& rounded_int, float fs);
   // Special case of set_register and get_register to access the raw PC value.
   void set_pc(int32_t value);
   int32_t get_pc() const;
@@ -278,7 +284,8 @@ class Simulator {
                                  const int32_t& fs_reg, const int32_t& ft_reg,
                                  const int32_t& fd_reg);
   void DecodeTypeRegisterWRsType(Instruction* instr, int32_t& alu_out,
-                                 const int32_t& fd_reg, const int32_t& fs_reg);
+                                 const int32_t& fd_reg, const int32_t& fs_reg,
+                                 const int32_t& ft_reg);
   void DecodeTypeRegisterSRsType(Instruction* instr, const int32_t& ft_reg,
                                  const int32_t& fs_reg, const int32_t& fd_reg);
   void DecodeTypeRegisterLRsType(Instruction* instr, const int32_t& ft_reg,
@@ -312,7 +319,7 @@ class Simulator {
                                   int32_t& alu_out);
 
   void DecodeTypeRegisterSPECIAL3(Instruction* instr, const int32_t& rt_reg,
-                                  int32_t& alu_out);
+                                  const int32_t& rd_reg, int32_t& alu_out);
 
   // Helper function for DecodeTypeRegister.
   void ConfigureTypeRegister(Instruction* instr,
index 2bec3f064a3eeb99838d81cbd0c52fb72eedf5d7..08f70ad33dbc4e69c24d0308d67df8997e904ea9 100644 (file)
@@ -2205,6 +2205,18 @@ void Assembler::dext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
 }
 
 
+void Assembler::bitswap(Register rd, Register rt) {
+  DCHECK(kArchVariant == kMips64r6);
+  GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BITSWAP);
+}
+
+
+void Assembler::dbitswap(Register rd, Register rt) {
+  DCHECK(kArchVariant == kMips64r6);
+  GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, DBITSWAP);
+}
+
+
 void Assembler::pref(int32_t hint, const MemOperand& rs) {
   DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
   Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
@@ -2642,6 +2654,18 @@ void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
 }
 
 
+void Assembler::class_s(FPURegister fd, FPURegister fs) {
+  DCHECK(kArchVariant == kMips64r6);
+  GenInstrRegister(COP1, S, f0, fs, fd, CLASS_S);
+}
+
+
+void Assembler::class_d(FPURegister fd, FPURegister fs) {
+  DCHECK(kArchVariant == kMips64r6);
+  GenInstrRegister(COP1, D, f0, fs, fd, CLASS_D);
+}
+
+
 void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister fs,
                      FPURegister ft) {
   DCHECK(kArchVariant == kMips64r6);
@@ -2701,6 +2725,17 @@ void Assembler::cmp(FPUCondition cond, SecondaryField fmt,
 }
 
 
+void Assembler::cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs,
+                      FPURegister ft) {
+  cmp(cond, W, fd, fs, ft);
+}
+
+void Assembler::cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs,
+                      FPURegister ft) {
+  cmp(cond, L, fd, fs, ft);
+}
+
+
 void Assembler::bc1eqz(int16_t offset, FPURegister ft) {
   DCHECK(kArchVariant == kMips64r6);
   Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask);
@@ -2728,6 +2763,18 @@ void Assembler::c(FPUCondition cond, SecondaryField fmt,
 }
 
 
+void Assembler::c_s(FPUCondition cond, FPURegister fs, FPURegister ft,
+                    uint16_t cc) {
+  c(cond, S, fs, ft, cc);
+}
+
+
+void Assembler::c_d(FPUCondition cond, FPURegister fs, FPURegister ft,
+                    uint16_t cc) {
+  c(cond, D, fs, ft, cc);
+}
+
+
 void Assembler::fcmp(FPURegister src1, const double src2,
       FPUCondition cond) {
   DCHECK(src2 == 0.0);
index 7c63095452eac03c8b7d613a43086598e3af8cc6..1fea4001d1eda473ff497b4484bd4f690508bb72 100644 (file)
@@ -907,6 +907,8 @@ class Assembler : public AssemblerBase {
   void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
   void ext_(Register rt, Register rs, uint16_t pos, uint16_t size);
   void dext_(Register rt, Register rs, uint16_t pos, uint16_t size);
+  void bitswap(Register rd, Register rt);
+  void dbitswap(Register rd, Register rt);
 
   // --------Coprocessor-instructions----------------
 
@@ -978,6 +980,9 @@ class Assembler : public AssemblerBase {
   void ceil_l_s(FPURegister fd, FPURegister fs);
   void ceil_l_d(FPURegister fd, FPURegister fs);
 
+  void class_s(FPURegister fd, FPURegister fs);
+  void class_d(FPURegister fd, FPURegister fs);
+
   void min(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
   void mina(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
   void max(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
@@ -1002,6 +1007,8 @@ class Assembler : public AssemblerBase {
   // Conditions and branches for MIPSr6.
   void cmp(FPUCondition cond, SecondaryField fmt,
          FPURegister fd, FPURegister ft, FPURegister fs);
+  void cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs, FPURegister ft);
+  void cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs, FPURegister ft);
 
   void bc1eqz(int16_t offset, FPURegister ft);
   void bc1eqz(Label* L, FPURegister ft) {
@@ -1015,6 +1022,8 @@ class Assembler : public AssemblerBase {
   // Conditions and branches for non MIPSr6.
   void c(FPUCondition cond, SecondaryField fmt,
          FPURegister ft, FPURegister fs, uint16_t cc = 0);
+  void c_s(FPUCondition cond, FPURegister ft, FPURegister fs, uint16_t cc = 0);
+  void c_d(FPUCondition cond, FPURegister ft, FPURegister fs, uint16_t cc = 0);
 
   void bc1f(int16_t offset, uint16_t cc = 0);
   void bc1f(Label* L, uint16_t cc = 0) {
index 6a26c2bd5b5dd335ad5d7c62298f4f1085e55997..1d96c4c889e4b9ca1e88e78e8b462a8c6081bfc0 100644 (file)
@@ -290,6 +290,8 @@ Instruction::Type Instruction::InstructionType() const {
         case INS:
         case EXT:
         case DEXT:
+        case BITSWAP:
+        case DBITSWAP:
           return kRegisterType;
         default:
           return kUnsupported;
index 37de91a0e2318d99f52f2b27b5e1d8ba86181754..cc41265497c1cb3d3b1bd707135d827df016dca8 100644 (file)
@@ -443,8 +443,13 @@ enum SecondaryField {
   DINSU = ((0 << 3) + 6),
   DINS = ((0 << 3) + 7),
 
+  BITSWAP = ((4 << 3) + 0),
+  DBITSWAP = ((4 << 3) + 4),
   DSBH = ((4 << 3) + 4),
 
+  // SPECIAL3 Encoding of sa Field.
+  DBITSWAP_SA = ((0 << 3) + 0) << kSaShift,
+
   // REGIMM  encoding of rt Field.
   BLTZ = ((0 << 3) + 0) << 16,
   BGEZ = ((0 << 3) + 1) << 16,
@@ -470,6 +475,7 @@ enum SecondaryField {
   L = ((2 << 3) + 5) << 21,
   PS = ((2 << 3) + 6) << 21,
   // COP1 Encoding of Function Field When rs=S.
+
   ADD_S = ((0 << 3) + 0),
   SUB_S = ((0 << 3) + 1),
   MUL_S = ((0 << 3) + 2),
@@ -488,6 +494,7 @@ enum SecondaryField {
   FLOOR_W_S = ((1 << 3) + 7),
   RECIP_S = ((2 << 3) + 5),
   RSQRT_S = ((2 << 3) + 6),
+  CLASS_S = ((3 << 3) + 3),
   CVT_D_S = ((4 << 3) + 1),
   CVT_W_S = ((4 << 3) + 4),
   CVT_L_S = ((4 << 3) + 5),
@@ -511,6 +518,11 @@ enum SecondaryField {
   FLOOR_W_D = ((1 << 3) + 7),
   RECIP_D = ((2 << 3) + 5),
   RSQRT_D = ((2 << 3) + 6),
+  CLASS_D = ((3 << 3) + 3),
+  MIN = ((3 << 3) + 4),
+  MINA = ((3 << 3) + 5),
+  MAX = ((3 << 3) + 6),
+  MAXA = ((3 << 3) + 7),
   CVT_S_D = ((4 << 3) + 0),
   CVT_W_D = ((4 << 3) + 4),
   CVT_L_D = ((4 << 3) + 5),
@@ -522,6 +534,7 @@ enum SecondaryField {
   C_ULT_D = ((6 << 3) + 5),
   C_OLE_D = ((6 << 3) + 6),
   C_ULE_D = ((6 << 3) + 7),
+
   // COP1 Encoding of Function Field When rs=W or L.
   CVT_S_W = ((4 << 3) + 0),
   CVT_D_W = ((4 << 3) + 1),
@@ -564,10 +577,6 @@ enum SecondaryField {
   CMP_SUGT = ((3 << 3) + 6),  // Reserved, not implemented.
   CMP_SOGT = ((3 << 3) + 7),  // Reserved, not implemented.
 
-  MIN = ((3 << 3) + 4),
-  MINA = ((3 << 3) + 5),
-  MAX = ((3 << 3) + 6),
-  MAXA = ((3 << 3) + 7),
   SEL = ((2 << 3) + 0),
   MOVF = ((2 << 3) + 1),      // Function field for MOVT.fmt and MOVF.fmt
   MOVZ_C = ((2 << 3) + 2),    // COP1 on FPR registers.
@@ -712,14 +721,21 @@ inline Condition CommuteCondition(Condition cc) {
 enum FPUCondition {
   kNoFPUCondition = -1,
 
-  F     = 0,  // False.
-  UN    = 1,  // Unordered.
-  EQ    = 2,  // Equal.
-  UEQ   = 3,  // Unordered or Equal.
-  OLT   = 4,  // Ordered or Less Than.
-  ULT   = 5,  // Unordered or Less Than.
-  OLE   = 6,  // Ordered or Less Than or Equal.
-  ULE   = 7   // Unordered or Less Than or Equal.
+  F = 0x00,    // False.
+  UN = 0x01,   // Unordered.
+  EQ = 0x02,   // Equal.
+  UEQ = 0x03,  // Unordered or Equal.
+  OLT = 0x04,  // Ordered or Less Than, on Mips release < 6.
+  LT = 0x04,   // Ordered or Less Than, on Mips release >= 6.
+  ULT = 0x05,  // Unordered or Less Than.
+  OLE = 0x06,  // Ordered or Less Than or Equal, on Mips release < 6.
+  LE = 0x06,   // Ordered or Less Than or Equal, on Mips release >= 6.
+  ULE = 0x07,  // Unordered or Less Than or Equal.
+
+  // Following constants are available on Mips release >= 6 only.
+  ORD = 0x11,  // Ordered, on Mips release >= 6.
+  UNE = 0x12,  // Not equal, on Mips release >= 6.
+  NE = 0x13,   // Ordered Greater Than or Less Than. on Mips >= 6 only.
 };
 
 
index 7fcdb909d2ce498ccb22c6ac64bd03c6182120aa..67715ff2274dd5b759bca2597b17f587ca34654e 100644 (file)
@@ -614,6 +614,9 @@ bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
     case CEIL_L_D:
       Format(instr, "ceil.l.'t 'fd, 'fs");
       break;
+    case CLASS_D:
+      Format(instr, "class.'t 'fd, 'fs");
+      break;
     case CVT_S_D:
       Format(instr, "cvt.s.'t 'fd, 'fs");
       break;
@@ -677,6 +680,9 @@ void Decoder::DecodeTypeRegisterLRsType(Instruction* instr) {
     case CVT_S_L:
       Format(instr, "cvt.s.l 'fd, 'fs");
       break;
+    case CMP_AF:
+      Format(instr, "cmp.af.d  'fd,  'fs, 'ft");
+      break;
     case CMP_UN:
       Format(instr, "cmp.un.d  'fd,  'fs, 'ft");
       break;
@@ -1129,6 +1135,20 @@ void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* instr) {
       Format(instr, "dext    'rt, 'rs, 'sa, 'ss1");
       break;
     }
+    case BITSWAP: {
+      Format(instr, "bitswap 'rd, 'rt");
+      break;
+    }
+    case DBITSWAP: {
+      switch (instr->SaFieldRaw()) {
+        case DBITSWAP_SA:
+          Format(instr, "dbitswap 'rd, 'rt");
+          break;
+        default:
+          UNREACHABLE();
+      }
+      break;
+    }
     default:
       UNREACHABLE();
   }
index 4298ca0e16cda9f61e8a10293278a910c2f0cea8..4b251f2b2fa037cbcbebe72d658bfde9ec66e18e 100644 (file)
@@ -1282,6 +1282,8 @@ bool Simulator::set_fcsr_round64_error(double original, double rounded) {
 }
 
 
+// Sets the rounding error codes in FCSR based on the result of the rounding.
+// Returns true if the operation was invalid.
 bool Simulator::set_fcsr_round_error(float original, float rounded) {
   bool ret = false;
   double max_int32 = std::numeric_limits<int32_t>::max();
@@ -1344,7 +1346,7 @@ bool Simulator::set_fcsr_round64_error(float original, float rounded) {
 }
 
 
-// for cvt instructions only
+// For cvt instructions only
 void Simulator::round_according_to_fcsr(double toRound, double& rounded,
                                         int32_t& rounded_int, double fs) {
   // 0 RN (round to nearest): Round a result to the nearest
@@ -1427,6 +1429,89 @@ void Simulator::round64_according_to_fcsr(double toRound, double& rounded,
 }
 
 
+// for cvt instructions only
+void Simulator::round_according_to_fcsr(float toRound, float& rounded,
+                                        int32_t& rounded_int, float fs) {
+  // 0 RN (round to nearest): Round a result to the nearest
+  // representable value; if the result is exactly halfway between
+  // two representable values, round to zero. Behave like round_w_d.
+
+  // 1 RZ (round toward zero): Round a result to the closest
+  // representable value whose absolute value is less than or
+  // equal to the infinitely accurate result. Behave like trunc_w_d.
+
+  // 2 RP (round up, or toward +infinity): Round a result to the
+  // next representable value up. Behave like ceil_w_d.
+
+  // 3 RN (round down, or toward âˆ’infinity): Round a result to
+  // the next representable value down. Behave like floor_w_d.
+  switch (FCSR_ & 3) {
+    case kRoundToNearest:
+      rounded = std::floor(fs + 0.5);
+      rounded_int = static_cast<int32_t>(rounded);
+      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
+        // If the number is halfway between two integers,
+        // round to the even one.
+        rounded_int--;
+      }
+      break;
+    case kRoundToZero:
+      rounded = trunc(fs);
+      rounded_int = static_cast<int32_t>(rounded);
+      break;
+    case kRoundToPlusInf:
+      rounded = std::ceil(fs);
+      rounded_int = static_cast<int32_t>(rounded);
+      break;
+    case kRoundToMinusInf:
+      rounded = std::floor(fs);
+      rounded_int = static_cast<int32_t>(rounded);
+      break;
+  }
+}
+
+
+void Simulator::round64_according_to_fcsr(float toRound, float& rounded,
+                                          int64_t& rounded_int, float fs) {
+  // 0 RN (round to nearest): Round a result to the nearest
+  // representable value; if the result is exactly halfway between
+  // two representable values, round to zero. Behave like round_w_d.
+
+  // 1 RZ (round toward zero): Round a result to the closest
+  // representable value whose absolute value is less than or.
+  // equal to the infinitely accurate result. Behave like trunc_w_d.
+
+  // 2 RP (round up, or toward +infinity): Round a result to the
+  // next representable value up. Behave like ceil_w_d.
+
+  // 3 RN (round down, or toward âˆ’infinity): Round a result to
+  // the next representable value down. Behave like floor_w_d.
+  switch (FCSR_ & 3) {
+    case kRoundToNearest:
+      rounded = std::floor(fs + 0.5);
+      rounded_int = static_cast<int64_t>(rounded);
+      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
+        // If the number is halfway between two integers,
+        // round to the even one.
+        rounded_int--;
+      }
+      break;
+    case kRoundToZero:
+      rounded = trunc(fs);
+      rounded_int = static_cast<int64_t>(rounded);
+      break;
+    case kRoundToPlusInf:
+      rounded = std::ceil(fs);
+      rounded_int = static_cast<int64_t>(rounded);
+      break;
+    case kRoundToMinusInf:
+      rounded = std::floor(fs);
+      rounded_int = static_cast<int64_t>(rounded);
+      break;
+  }
+}
+
+
 // Raw access to the PC register.
 void Simulator::set_pc(int64_t value) {
   pc_modified_ = true;
@@ -2434,6 +2519,62 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
           *alu_out = static_cast<int64_t>((rs_u & (mask << lsb)) >> lsb);
           break;
         }
+        case BITSWAP: {  // Mips32r6 instruction
+          uint32_t input = static_cast<uint32_t>(rt);
+          uint32_t output = 0;
+          uint8_t i_byte, o_byte;
+
+          // Reverse the bit in byte for each individual byte
+          for (int i = 0; i < 4; i++) {
+            output = output >> 8;
+            i_byte = input & 0xff;
+
+            // Fast way to reverse bits in byte
+            // Devised by Sean Anderson, July 13, 2001
+            o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
+                                           (i_byte * 0x8020LU & 0x88440LU)) *
+                                              0x10101LU >>
+                                          16);
+
+            output = output | (static_cast<uint32_t>(o_byte << 24));
+            input = input >> 8;
+          }
+
+          *alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
+          break;
+        }
+        case DBITSWAP: {
+          switch (instr->SaFieldRaw()) {
+            case DBITSWAP_SA: {  // Mips64r6
+              uint64_t input = static_cast<uint64_t>(rt);
+              uint64_t output = 0;
+              uint8_t i_byte, o_byte;
+
+              // Reverse the bit in byte for each individual byte
+              for (int i = 0; i < 8; i++) {
+                output = output >> 8;
+                i_byte = input & 0xff;
+
+                // Fast way to reverse bits in byte
+                // Devised by Sean Anderson, July 13, 2001
+                o_byte =
+                    static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
+                                          (i_byte * 0x8020LU & 0x88440LU)) *
+                                             0x10101LU >>
+                                         16);
+
+                output = output | ((static_cast<uint64_t>(o_byte) << 56));
+                input = input >> 8;
+              }
+
+              *alu_out = static_cast<int64_t>(output);
+              break;
+            }
+            default:
+              UNREACHABLE();
+          }
+          break;
+        }
         default:
           UNREACHABLE();
       }
@@ -2530,6 +2671,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
       set_fpu_register_float(fd_reg, result);
       break;
     }
+    case C_F_D:
+      set_fcsr_bit(fcsr_cc, false);
+      break;
     case C_UN_D:
       set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
       break;
@@ -2554,6 +2698,91 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
     case CVT_D_S:
       set_fpu_register_double(fd_reg, static_cast<double>(fs));
       break;
+    case CLASS_S: {  // Mips64r6 instruction
+      // Convert float input to uint32_t for easier bit manipulation
+      uint32_t classed = bit_cast<uint32_t>(fs);
+
+      // Extracting sign, exponent and mantissa from the input float
+      uint32_t sign = (classed >> 31) & 1;
+      uint32_t exponent = (classed >> 23) & 0x000000ff;
+      uint32_t mantissa = classed & 0x007fffff;
+      uint32_t result;
+      float fResult;
+
+      // Setting flags if input float is negative infinity,
+      // positive infinity, negative zero or positive zero
+      bool negInf = (classed == 0xFF800000);
+      bool posInf = (classed == 0x7F800000);
+      bool negZero = (classed == 0x80000000);
+      bool posZero = (classed == 0x00000000);
+
+      bool signalingNan;
+      bool quietNan;
+      bool negSubnorm;
+      bool posSubnorm;
+      bool negNorm;
+      bool posNorm;
+
+      // Setting flags if float is NaN
+      signalingNan = false;
+      quietNan = false;
+      if (!negInf && !posInf && (exponent == 0xff)) {
+        quietNan = ((mantissa & 0x00200000) == 0) &&
+                   ((mantissa & (0x00200000 - 1)) == 0);
+        signalingNan = !quietNan;
+      }
+
+      // Setting flags if float is subnormal number
+      posSubnorm = false;
+      negSubnorm = false;
+      if ((exponent == 0) && (mantissa != 0)) {
+        DCHECK(sign == 0 || sign == 1);
+        posSubnorm = (sign == 0);
+        negSubnorm = (sign == 1);
+      }
+
+      // Setting flags if float is normal number
+      posNorm = false;
+      negNorm = false;
+      if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
+          !quietNan && !negZero && !posZero) {
+        DCHECK(sign == 0 || sign == 1);
+        posNorm = (sign == 0);
+        negNorm = (sign == 1);
+      }
+
+      // Calculating result according to description of CLASS.S instruction
+      result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
+               (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
+               (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
+
+      DCHECK(result != 0);
+
+      fResult = bit_cast<float>(result);
+      set_fpu_register_float(fd_reg, fResult);
+
+      break;
+    }
+    case CVT_L_S: {
+      float rounded;
+      int64_t result;
+      round64_according_to_fcsr(fs, rounded, result, fs);
+      set_fpu_register(fd_reg, result);
+      if (set_fcsr_round64_error(fs, rounded)) {
+        set_fpu_register(fd_reg, kFPU64InvalidResult);
+      }
+      break;
+    }
+    case CVT_W_S: {
+      float rounded;
+      int32_t result;
+      round_according_to_fcsr(fs, rounded, result, fs);
+      set_fpu_register_word(fd_reg, result);
+      if (set_fcsr_round_error(fs, rounded)) {
+        set_fpu_register_word(fd_reg, kFPUInvalidResult);
+      }
+      break;
+    }
     case TRUNC_W_S: {  // Truncate single to word (round towards 0).
       float rounded = trunc(fs);
       int32_t result = static_cast<int32_t>(rounded);
@@ -2751,7 +2980,7 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
       break;
     }
     default:
-      // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
+      // TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
       // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
       UNREACHABLE();
   }
@@ -3037,7 +3266,7 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
       round64_according_to_fcsr(fs, rounded, result, fs);
       set_fpu_register(fd_reg, result);
       if (set_fcsr_round64_error(fs, rounded)) {
-        set_fpu_register(fd_reg, kFPUInvalidResult);
+        set_fpu_register(fd_reg, kFPU64InvalidResult);
       }
       break;
     }
@@ -3083,9 +3312,75 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
       }
       break;
     }
-    case C_F_D:
-      UNIMPLEMENTED_MIPS();
+    case CLASS_D: {  // Mips64r6 instruction
+      // Convert double input to uint64_t for easier bit manipulation
+      uint64_t classed = bit_cast<uint64_t>(fs);
+
+      // Extracting sign, exponent and mantissa from the input double
+      uint32_t sign = (classed >> 63) & 1;
+      uint32_t exponent = (classed >> 52) & 0x00000000000007ff;
+      uint64_t mantissa = classed & 0x000fffffffffffff;
+      uint64_t result;
+      double dResult;
+
+      // Setting flags if input double is negative infinity,
+      // positive infinity, negative zero or positive zero
+      bool negInf = (classed == 0xFFF0000000000000);
+      bool posInf = (classed == 0x7FF0000000000000);
+      bool negZero = (classed == 0x8000000000000000);
+      bool posZero = (classed == 0x0000000000000000);
+
+      bool signalingNan;
+      bool quietNan;
+      bool negSubnorm;
+      bool posSubnorm;
+      bool negNorm;
+      bool posNorm;
+
+      // Setting flags if double is NaN
+      signalingNan = false;
+      quietNan = false;
+      if (!negInf && !posInf && exponent == 0x7ff) {
+        quietNan = ((mantissa & 0x0008000000000000) != 0) &&
+                   ((mantissa & (0x0008000000000000 - 1)) == 0);
+        signalingNan = !quietNan;
+      }
+
+      // Setting flags if double is subnormal number
+      posSubnorm = false;
+      negSubnorm = false;
+      if ((exponent == 0) && (mantissa != 0)) {
+        DCHECK(sign == 0 || sign == 1);
+        posSubnorm = (sign == 0);
+        negSubnorm = (sign == 1);
+      }
+
+      // Setting flags if double is normal number
+      posNorm = false;
+      negNorm = false;
+      if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
+          !quietNan && !negZero && !posZero) {
+        DCHECK(sign == 0 || sign == 1);
+        posNorm = (sign == 0);
+        negNorm = (sign == 1);
+      }
+
+      // Calculating result according to description of CLASS.D instruction
+      result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
+               (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
+               (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
+
+      DCHECK(result != 0);
+
+      dResult = bit_cast<double>(result);
+      set_fpu_register_double(fd_reg, dResult);
+
+      break;
+    }
+    case C_F_D: {
+      set_fcsr_bit(fcsr_cc, false);
       break;
+    }
     default:
       UNREACHABLE();
   }
@@ -3095,7 +3390,10 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
 void Simulator::DecodeTypeRegisterWRsType(Instruction* instr,
                                           const int32_t& fs_reg,
                                           const int32_t& fd_reg,
+                                          const int32_t& ft_reg,
                                           int64_t& alu_out) {
+  float fs = get_fpu_register_float(fs_reg);
+  float ft = get_fpu_register_float(ft_reg);
   switch (instr->FunctionFieldRaw()) {
     case CVT_S_W:  // Convert word to float (single).
       alu_out = get_fpu_register_signed_word(fs_reg);
@@ -3105,7 +3403,80 @@ void Simulator::DecodeTypeRegisterWRsType(Instruction* instr,
       alu_out = get_fpu_register_signed_word(fs_reg);
       set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
       break;
-    default:  // Mips64r6 CMP.S instructions unimplemented.
+    case CMP_AF:
+      set_fpu_register_word(fd_reg, 0);
+      break;
+    case CMP_UN:
+      if (std::isnan(fs) || std::isnan(ft)) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_EQ:
+      if (fs == ft) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_UEQ:
+      if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_LT:
+      if (fs < ft) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_ULT:
+      if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_LE:
+      if (fs <= ft) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_ULE:
+      if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_OR:
+      if (!std::isnan(fs) && !std::isnan(ft)) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_UNE:
+      if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    case CMP_NE:
+      if (fs != ft) {
+        set_fpu_register_word(fd_reg, -1);
+      } else {
+        set_fpu_register_word(fd_reg, 0);
+      }
+      break;
+    default:
       UNREACHABLE();
   }
 }
@@ -3124,10 +3495,11 @@ void Simulator::DecodeTypeRegisterLRsType(Instruction* instr,
       set_fpu_register_double(fd_reg, static_cast<double>(i64));
       break;
     case CVT_S_L:
-      UNIMPLEMENTED_MIPS();
+      i64 = get_fpu_register(fs_reg);
+      set_fpu_register_float(fd_reg, static_cast<float>(i64));
       break;
-    case CMP_AF:  // Mips64r6 CMP.D instructions.
-      UNIMPLEMENTED_MIPS();
+    case CMP_AF:
+      set_fpu_register(fd_reg, 0);
       break;
     case CMP_UN:
       if (std::isnan(fs) || std::isnan(ft)) {
@@ -3178,7 +3550,28 @@ void Simulator::DecodeTypeRegisterLRsType(Instruction* instr,
         set_fpu_register(fd_reg, 0);
       }
       break;
-    default:  // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED
+    case CMP_OR:
+      if (!std::isnan(fs) && !std::isnan(ft)) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_UNE:
+      if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    case CMP_NE:
+      if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
+        set_fpu_register(fd_reg, -1);
+      } else {
+        set_fpu_register(fd_reg, 0);
+      }
+      break;
+    default:
       UNREACHABLE();
   }
 }
@@ -3227,7 +3620,7 @@ void Simulator::DecodeTypeRegisterCOP1(
       DecodeTypeRegisterDRsType(instr, fs_reg, ft_reg, fd_reg);
       break;
     case W:
-      DecodeTypeRegisterWRsType(instr, fs_reg, fd_reg, alu_out);
+      DecodeTypeRegisterWRsType(instr, fs_reg, fd_reg, ft_reg, alu_out);
       break;
     case L:
       DecodeTypeRegisterLRsType(instr, fs_reg, fd_reg, ft_reg);
@@ -3446,6 +3839,7 @@ void Simulator::DecodeTypeRegisterSPECIAL2(Instruction* instr,
 
 void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
                                            const int64_t& rt_reg,
+                                           const int64_t& rd_reg,
                                            int64_t& alu_out) {
   switch (instr->FunctionFieldRaw()) {
     case INS:
@@ -3459,6 +3853,11 @@ void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
       set_register(rt_reg, alu_out);
       TraceRegWr(alu_out);
       break;
+    case BITSWAP:
+    case DBITSWAP:
+      set_register(rd_reg, alu_out);
+      TraceRegWr(alu_out);
+      break;
     default:
       UNREACHABLE();
   }
@@ -3534,7 +3933,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
       DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out);
       break;
     case SPECIAL3:
-      DecodeTypeRegisterSPECIAL3(instr, rt_reg, alu_out);
+      DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
       break;
     // Unimplemented opcodes raised an error in the configuration step before,
     // so we can use the default here to set the destination register in common
index bb5ab2a5257e3577e1de87ecc32988157379dd6f..aa76c94ad9e1b5626d6f2cc804767cc435c2462f 100644 (file)
@@ -213,6 +213,10 @@ class Simulator {
                                int32_t& rounded_int, double fs);
   void round64_according_to_fcsr(double toRound, double& rounded,
                                  int64_t& rounded_int, double fs);
+  void round_according_to_fcsr(float toRound, float& rounded,
+                               int32_t& rounded_int, float fs);
+  void round64_according_to_fcsr(float toRound, float& rounded,
+                                 int64_t& rounded_int, float fs);
   void set_fcsr_rounding_mode(FPURoundingMode mode);
   unsigned int get_fcsr_rounding_mode();
   // Special case of set_register and get_register to access the raw PC value.
@@ -347,7 +351,7 @@ class Simulator {
                                   int64_t& alu_out);
 
   void DecodeTypeRegisterSPECIAL3(Instruction* instr, const int64_t& rt_reg,
-                                  int64_t& alu_out);
+                                  const int64_t& rd_reg, int64_t& alu_out);
 
   void DecodeTypeRegisterSRsType(Instruction* instr, const int32_t& fs_reg,
                                  const int32_t& ft_reg, const int32_t& fd_reg);
@@ -356,7 +360,8 @@ class Simulator {
                                  const int32_t& ft_reg, const int32_t& fd_reg);
 
   void DecodeTypeRegisterWRsType(Instruction* instr, const int32_t& fs_reg,
-                                 const int32_t& fd_reg, int64_t& alu_out);
+                                 const int32_t& ft_reg, const int32_t& fd_reg,
+                                 int64_t& alu_out);
 
   void DecodeTypeRegisterLRsType(Instruction* instr, const int32_t& fs_reg,
                                  const int32_t& fd_reg, const int32_t& ft_reg);
index b53ca8773db556ea5e55bcf5c5b552b63929e3b2..a797328b1a122a1c26fa040e2430f3473320aa42 100644 (file)
@@ -1918,28 +1918,26 @@ TEST(trunc_l) {
       int64_t c;  // a trunc result
       int64_t d;  // b trunc result
     }Test;
-    const int tableLength = 16;
+    const int tableLength = 15;
     double inputs_D[tableLength] = {
         2.1, 2.6, 2.5, 3.1, 3.6, 3.5,
         -2.1, -2.6, -2.5, -3.1, -3.6, -3.5,
         2147483648.0,
         std::numeric_limits<double>::quiet_NaN(),
-        std::numeric_limits<double>::infinity(),
-        9223372036854775808.0
+        std::numeric_limits<double>::infinity()
         };
     float inputs_S[tableLength] = {
         2.1, 2.6, 2.5, 3.1, 3.6, 3.5,
         -2.1, -2.6, -2.5, -3.1, -3.6, -3.5,
         2147483648.0,
         std::numeric_limits<float>::quiet_NaN(),
-        std::numeric_limits<float>::infinity(),
-        9223372036854775808.0
+        std::numeric_limits<float>::infinity()
         };
     double outputs[tableLength] = {
         2.0, 2.0, 2.0, 3.0, 3.0, 3.0,
         -2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
         2147483648.0, dFPU64InvalidResult,
-        dFPU64InvalidResult, dFPU64InvalidResult};
+        dFPU64InvalidResult};
 
     __ ldc1(f4, MemOperand(a0, OFFSET_OF(Test, a)) );
     __ lwc1(f6, MemOperand(a0, OFFSET_OF(Test, b)) );
@@ -2355,28 +2353,26 @@ TEST(round_l) {
       int64_t c;
       int64_t d;
     }Test;
-    const int tableLength = 16;
+    const int tableLength = 15;
     double inputs_D[tableLength] = {
         2.1, 2.6, 2.5, 3.1, 3.6, 3.5,
         -2.1, -2.6, -2.5, -3.1, -3.6, -3.5,
         2147483648.0,
         std::numeric_limits<double>::quiet_NaN(),
-        std::numeric_limits<double>::infinity(),
-        9223372036854775808.0
+        std::numeric_limits<double>::infinity()
         };
     float inputs_S[tableLength] = {
         2.1, 2.6, 2.5, 3.1, 3.6, 3.5,
         -2.1, -2.6, -2.5, -3.1, -3.6, -3.5,
         2147483648.0,
         std::numeric_limits<float>::quiet_NaN(),
-        std::numeric_limits<float>::infinity(),
-        9223372036854775808.0
+        std::numeric_limits<float>::infinity()
         };
     double outputs[tableLength] = {
         2.0, 3.0, 2.0, 3.0, 4.0, 4.0,
         -2.0, -3.0, -2.0, -3.0, -4.0, -4.0,
         2147483648.0, dFPU64InvalidResult,
-        dFPU64InvalidResult, dFPU64InvalidResult};
+        dFPU64InvalidResult};
 
     __ ldc1(f4, MemOperand(a0, OFFSET_OF(Test, a)) );
     __ lwc1(f6, MemOperand(a0, OFFSET_OF(Test, b)) );
@@ -2804,28 +2800,26 @@ TEST(floor_l) {
       int64_t c;
       int64_t d;
     }Test;
-    const int tableLength = 16;
+    const int tableLength = 15;
     double inputs_D[tableLength] = {
         2.1, 2.6, 2.5, 3.1, 3.6, 3.5,
         -2.1, -2.6, -2.5, -3.1, -3.6, -3.5,
         2147483648.0,
         std::numeric_limits<double>::quiet_NaN(),
-        std::numeric_limits<double>::infinity(),
-        9223372036854775808.0
+        std::numeric_limits<double>::infinity()
         };
     float inputs_S[tableLength] = {
         2.1, 2.6, 2.5, 3.1, 3.6, 3.5,
         -2.1, -2.6, -2.5, -3.1, -3.6, -3.5,
         2147483648.0,
         std::numeric_limits<float>::quiet_NaN(),
-        std::numeric_limits<float>::infinity(),
-        9223372036854775808.0
+        std::numeric_limits<float>::infinity()
         };
     double outputs[tableLength] = {
         2.0, 2.0, 2.0, 3.0, 3.0, 3.0,
         -3.0, -3.0, -3.0, -4.0, -4.0, -4.0,
         2147483648.0, dFPU64InvalidResult,
-        dFPU64InvalidResult, dFPU64InvalidResult};
+        dFPU64InvalidResult};
 
     __ ldc1(f4, MemOperand(a0, OFFSET_OF(Test, a)) );
     __ lwc1(f6, MemOperand(a0, OFFSET_OF(Test, b)) );
@@ -2922,28 +2916,26 @@ TEST(ceil_l) {
       int64_t c;
       int64_t d;
     }Test;
-    const int tableLength = 16;
+    const int tableLength = 15;
     double inputs_D[tableLength] = {
         2.1, 2.6, 2.5, 3.1, 3.6, 3.5,
         -2.1, -2.6, -2.5, -3.1, -3.6, -3.5,
         2147483648.0,
         std::numeric_limits<double>::quiet_NaN(),
-        std::numeric_limits<double>::infinity(),
-        9223372036854775808.0
+        std::numeric_limits<double>::infinity()
         };
     float inputs_S[tableLength] = {
         2.1, 2.6, 2.5, 3.1, 3.6, 3.5,
         -2.1, -2.6, -2.5, -3.1, -3.6, -3.5,
         2147483648.0,
         std::numeric_limits<float>::quiet_NaN(),
-        std::numeric_limits<float>::infinity(),
-        9223372036854775808.0
+        std::numeric_limits<float>::infinity()
         };
     double outputs[tableLength] = {
         3.0, 3.0, 3.0, 4.0, 4.0, 4.0,
         -2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
         2147483648.0, dFPU64InvalidResult,
-        dFPU64InvalidResult, dFPU64InvalidResult};
+        dFPU64InvalidResult};
 
     __ ldc1(f4, MemOperand(a0, OFFSET_OF(Test, a)) );
     __ lwc1(f6, MemOperand(a0, OFFSET_OF(Test, b)) );
@@ -3181,4 +3173,1174 @@ TEST(jump_tables3) {
 }
 
 
+TEST(BITSWAP) {
+  // Test BITSWAP
+  if (IsMipsArchVariant(kMips32r6)) {
+    CcTest::InitializeVM();
+    Isolate* isolate = CcTest::i_isolate();
+    HandleScope scope(isolate);
+
+    typedef struct {
+      int32_t r1;
+      int32_t r2;
+      int32_t r3;
+      int32_t r4;
+    } T;
+    T t;
+
+    Assembler assm(isolate, NULL, 0);
+
+    __ lw(a2, MemOperand(a0, OFFSET_OF(T, r1)));
+    __ nop();
+    __ bitswap(a1, a2);
+    __ sw(a1, MemOperand(a0, OFFSET_OF(T, r1)));
+
+    __ lw(a2, MemOperand(a0, OFFSET_OF(T, r2)));
+    __ nop();
+    __ bitswap(a1, a2);
+    __ sw(a1, MemOperand(a0, OFFSET_OF(T, r2)));
+
+    __ jr(ra);
+    __ nop();
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+    t.r1 = 0x781A15C3;
+    t.r2 = 0x8B71FCDE;
+    Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+    USE(dummy);
+
+    CHECK_EQ(static_cast<int32_t>(0x1E58A8C3), t.r1);
+    CHECK_EQ(static_cast<int32_t>(0xD18E3F7B), t.r2);
+  }
+}
+
+
+TEST(class_fmt) {
+  if (IsMipsArchVariant(kMips32r6)) {
+    // Test CLASS.fmt instruction.
+    CcTest::InitializeVM();
+    Isolate* isolate = CcTest::i_isolate();
+    HandleScope scope(isolate);
+
+    typedef struct {
+      double dSignalingNan;
+      double dQuietNan;
+      double dNegInf;
+      double dNegNorm;
+      double dNegSubnorm;
+      double dNegZero;
+      double dPosInf;
+      double dPosNorm;
+      double dPosSubnorm;
+      double dPosZero;
+      float  fSignalingNan;
+      float  fQuietNan;
+      float  fNegInf;
+      float  fNegNorm;
+      float  fNegSubnorm;
+      float  fNegZero;
+      float  fPosInf;
+      float  fPosNorm;
+      float  fPosSubnorm;
+      float  fPosZero;  } T;
+    T t;
+
+    // Create a function that accepts &t, and loads, manipulates, and stores
+    // the doubles t.a ... t.f.
+    MacroAssembler assm(isolate, NULL, 0);
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dSignalingNan)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dSignalingNan)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dQuietNan)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dQuietNan)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dNegInf)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dNegInf)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dNegNorm)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dNegNorm)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dNegSubnorm)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dNegSubnorm)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dNegZero)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dNegZero)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dPosInf)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dPosInf)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dPosNorm)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dPosNorm)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dPosSubnorm)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dPosSubnorm)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dPosZero)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dPosZero)));
+
+    // Testing instruction CLASS.S
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fSignalingNan)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fSignalingNan)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fQuietNan)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fQuietNan)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fNegInf)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fNegInf)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fNegNorm)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fNegNorm)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fNegSubnorm)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fNegSubnorm)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fNegZero)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fNegZero)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fPosInf)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fPosInf)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fPosNorm)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fPosNorm)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fPosSubnorm)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fPosSubnorm)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fPosZero)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fPosZero)));
+
+    __ jr(ra);
+    __ nop();
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+
+    t.dSignalingNan =  std::numeric_limits<double>::signaling_NaN();
+    t.dQuietNan = std::numeric_limits<double>::quiet_NaN();
+    t.dNegInf       = -1.0 / 0.0;
+    t.dNegNorm      = -5.0;
+    t.dNegSubnorm   = -DBL_MIN / 2.0;
+    t.dNegZero      = -0.0;
+    t.dPosInf       = 2.0 / 0.0;
+    t.dPosNorm      = 275.35;
+    t.dPosSubnorm   = DBL_MIN / 2.0;
+    t.dPosZero      = +0.0;
+    // Float test values
+
+    t.fSignalingNan = std::numeric_limits<float>::signaling_NaN();
+    t.fQuietNan     = std::numeric_limits<float>::quiet_NaN();
+    t.fNegInf       = -0.5/0.0;
+    t.fNegNorm      = -FLT_MIN;
+    t.fNegSubnorm   = -FLT_MIN / 1.5;
+    t.fNegZero      = -0.0;
+    t.fPosInf       = 100000.0 / 0.0;
+    t.fPosNorm      = FLT_MAX;
+    t.fPosSubnorm   = FLT_MIN / 20.0;
+    t.fPosZero      = +0.0;
+
+    Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+    USE(dummy);
+    // Expected double results.
+    CHECK_EQ(bit_cast<uint64_t>(t.dSignalingNan), 0x001);
+    CHECK_EQ(bit_cast<uint64_t>(t.dQuietNan),     0x002);
+    CHECK_EQ(bit_cast<uint64_t>(t.dNegInf),       0x004);
+    CHECK_EQ(bit_cast<uint64_t>(t.dNegNorm),      0x008);
+    CHECK_EQ(bit_cast<uint64_t>(t.dNegSubnorm),   0x010);
+    CHECK_EQ(bit_cast<uint64_t>(t.dNegZero),      0x020);
+    CHECK_EQ(bit_cast<uint64_t>(t.dPosInf),       0x040);
+    CHECK_EQ(bit_cast<uint64_t>(t.dPosNorm),      0x080);
+    CHECK_EQ(bit_cast<uint64_t>(t.dPosSubnorm),   0x100);
+    CHECK_EQ(bit_cast<uint64_t>(t.dPosZero),      0x200);
+
+    // Expected float results.
+    CHECK_EQ(bit_cast<uint32_t>(t.fSignalingNan), 0x001);
+    CHECK_EQ(bit_cast<uint32_t>(t.fQuietNan),     0x002);
+    CHECK_EQ(bit_cast<uint32_t>(t.fNegInf),       0x004);
+    CHECK_EQ(bit_cast<uint32_t>(t.fNegNorm),      0x008);
+    CHECK_EQ(bit_cast<uint32_t>(t.fNegSubnorm),   0x010);
+    CHECK_EQ(bit_cast<uint32_t>(t.fNegZero),      0x020);
+    CHECK_EQ(bit_cast<uint32_t>(t.fPosInf),       0x040);
+    CHECK_EQ(bit_cast<uint32_t>(t.fPosNorm),      0x080);
+    CHECK_EQ(bit_cast<uint32_t>(t.fPosSubnorm),   0x100);
+    CHECK_EQ(bit_cast<uint32_t>(t.fPosZero),      0x200);
+  }
+}
+
+
+TEST(ABS) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  MacroAssembler assm(isolate, NULL, 0);
+
+  typedef struct test_float {
+    int64_t fir;
+    double a;
+    float b;
+    double fcsr;
+  } TestFloat;
+
+  TestFloat test;
+
+  // Save FIR.
+  __ cfc1(a1, FCSR);
+  // Disable FPU exceptions.
+  __ ctc1(zero_reg, FCSR);
+
+  __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, a)));
+  __ abs_d(f10, f4);
+  __ sdc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, a)));
+
+  __ lwc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, b)));
+  __ abs_s(f10, f4);
+  __ swc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, b)));
+
+  // Restore FCSR.
+  __ ctc1(a1, FCSR);
+
+  __ jr(ra);
+  __ nop();
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  test.a = -2.0;
+  test.b = -2.0;
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, 2.0);
+  CHECK_EQ(test.b, 2.0);
+
+  test.a = 2.0;
+  test.b = 2.0;
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, 2.0);
+  CHECK_EQ(test.b, 2.0);
+
+  // Testing biggest positive number
+  test.a = std::numeric_limits<double>::max();
+  test.b = std::numeric_limits<float>::max();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, std::numeric_limits<double>::max());
+  CHECK_EQ(test.b, std::numeric_limits<float>::max());
+
+  // Testing smallest negative number
+  test.a = -std::numeric_limits<double>::lowest();
+  test.b = -std::numeric_limits<float>::lowest();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, std::numeric_limits<double>::max());
+  CHECK_EQ(test.b, std::numeric_limits<float>::max());
+
+  // Testing smallest positive number
+  test.a = -std::numeric_limits<double>::min();
+  test.b = -std::numeric_limits<float>::min();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, std::numeric_limits<double>::min());
+  CHECK_EQ(test.b, std::numeric_limits<float>::min());
+
+  // Testing infinity
+  test.a = -std::numeric_limits<double>::max()
+          / std::numeric_limits<double>::min();
+  test.b = -std::numeric_limits<float>::max()
+          / std::numeric_limits<float>::min();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, std::numeric_limits<double>::max()
+                 / std::numeric_limits<double>::min());
+  CHECK_EQ(test.b, std::numeric_limits<float>::max()
+                 / std::numeric_limits<float>::min());
+
+  test.a = std::numeric_limits<double>::quiet_NaN();
+  test.b = std::numeric_limits<float>::quiet_NaN();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(std::isnan(test.a), true);
+  CHECK_EQ(std::isnan(test.b), true);
+
+  test.a = std::numeric_limits<double>::signaling_NaN();
+  test.b = std::numeric_limits<float>::signaling_NaN();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(std::isnan(test.a), true);
+  CHECK_EQ(std::isnan(test.b), true);
+}
+
+
+TEST(ADD_FMT) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  MacroAssembler assm(isolate, NULL, 0);
+
+  typedef struct test_float {
+    double a;
+    double b;
+    double c;
+    float fa;
+    float fb;
+    float fc;
+  } TestFloat;
+
+  TestFloat test;
+
+  __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, a)));
+  __ ldc1(f8, MemOperand(a0, OFFSET_OF(TestFloat, b)));
+  __ add_d(f10, f8, f4);
+  __ sdc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, c)));
+
+  __ lwc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, fa)));
+  __ lwc1(f8, MemOperand(a0, OFFSET_OF(TestFloat, fb)));
+  __ add_s(f10, f8, f4);
+  __ swc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, fc)));
+
+  __ jr(ra);
+  __ nop();
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  test.a = 2.0;
+  test.b = 3.0;
+  test.fa = 2.0;
+  test.fb = 3.0;
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.c, 5.0);
+  CHECK_EQ(test.fc, 5.0);
+
+  test.a = std::numeric_limits<double>::max();
+  test.b = std::numeric_limits<double>::lowest();
+  test.fa = std::numeric_limits<float>::max();
+  test.fb = std::numeric_limits<float>::lowest();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.c, 0.0);
+  CHECK_EQ(test.fc, 0.0);
+
+  test.a = std::numeric_limits<double>::max();
+  test.b = std::numeric_limits<double>::max();
+  test.fa = std::numeric_limits<float>::max();
+  test.fb = std::numeric_limits<float>::max();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(std::isfinite(test.c), false);
+  CHECK_EQ(std::isfinite(test.fc), false);
+
+  test.a = 5.0;
+  test.b = std::numeric_limits<double>::signaling_NaN();
+  test.fa = 5.0;
+  test.fb = std::numeric_limits<float>::signaling_NaN();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(std::isnan(test.c), true);
+  CHECK_EQ(std::isnan(test.fc), true);
+}
+
+
+TEST(C_COND_FMT) {
+  if ((IsMipsArchVariant(kMips32r1)) || (IsMipsArchVariant(kMips32r2))) {
+    CcTest::InitializeVM();
+    Isolate* isolate = CcTest::i_isolate();
+    HandleScope scope(isolate);
+    MacroAssembler assm(isolate, NULL, 0);
+
+    typedef struct test_float {
+      double dOp1;
+      double dOp2;
+      uint32_t dF;
+      uint32_t dUn;
+      uint32_t dEq;
+      uint32_t dUeq;
+      uint32_t dOlt;
+      uint32_t dUlt;
+      uint32_t dOle;
+      uint32_t dUle;
+      float fOp1;
+      float fOp2;
+      uint32_t fF;
+      uint32_t fUn;
+      uint32_t fEq;
+      uint32_t fUeq;
+      uint32_t fOlt;
+      uint32_t fUlt;
+      uint32_t fOle;
+      uint32_t fUle;
+    } TestFloat;
+
+    TestFloat test;
+
+    __ li(t1, 1);
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, dOp1)));
+    __ ldc1(f6, MemOperand(a0, OFFSET_OF(TestFloat, dOp2)));
+
+    __ lwc1(f14, MemOperand(a0, OFFSET_OF(TestFloat, fOp1)));
+    __ lwc1(f16, MemOperand(a0, OFFSET_OF(TestFloat, fOp2)));
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(F, f4, f6, 0);
+    __ c_s(F, f14, f16, 2);
+    __ movt(t2, t1, 0);
+    __ movt(t3, t1, 2);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dF)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fF)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(UN, f4, f6, 2);
+    __ c_s(UN, f14, f16, 4);
+    __ movt(t2, t1, 2);
+    __ movt(t3, t1, 4);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dUn)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fUn)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(EQ, f4, f6, 4);
+    __ c_s(EQ, f14, f16, 6);
+    __ movt(t2, t1, 4);
+    __ movt(t3, t1, 6);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dEq)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fEq)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(UEQ, f4, f6, 6);
+    __ c_s(UEQ, f14, f16, 0);
+    __ movt(t2, t1, 6);
+    __ movt(t3, t1, 0);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dUeq)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fUeq)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(OLT, f4, f6, 0);
+    __ c_s(OLT, f14, f16, 2);
+    __ movt(t2, t1, 0);
+    __ movt(t3, t1, 2);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dOlt)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fOlt)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(ULT, f4, f6, 2);
+    __ c_s(ULT, f14, f16, 4);
+    __ movt(t2, t1, 2);
+    __ movt(t3, t1, 4);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dUlt)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fUlt)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(OLE, f4, f6, 4);
+    __ c_s(OLE, f14, f16, 6);
+    __ movt(t2, t1, 4);
+    __ movt(t3, t1, 6);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dOle)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fOle)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(ULE, f4, f6, 6);
+    __ c_s(ULE, f14, f16, 0);
+    __ movt(t2, t1, 6);
+    __ movt(t3, t1, 0);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dUle)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fUle)) );
+
+    __ jr(ra);
+    __ nop();
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+    test.dOp1 = 2.0;
+    test.dOp2 = 3.0;
+    test.fOp1 = 2.0;
+    test.fOp2 = 3.0;
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(test.dF, 0);
+    CHECK_EQ(test.dUn, 0);
+    CHECK_EQ(test.dEq, 0);
+    CHECK_EQ(test.dUeq, 0);
+    CHECK_EQ(test.dOlt, 1);
+    CHECK_EQ(test.dUlt, 1);
+    CHECK_EQ(test.dOle, 1);
+    CHECK_EQ(test.dUle, 1);
+    CHECK_EQ(test.fF, 0);
+    CHECK_EQ(test.fUn, 0);
+    CHECK_EQ(test.fEq, 0);
+    CHECK_EQ(test.fUeq, 0);
+    CHECK_EQ(test.fOlt, 1);
+    CHECK_EQ(test.fUlt, 1);
+    CHECK_EQ(test.fOle, 1);
+    CHECK_EQ(test.fUle, 1);
+
+    test.dOp1 = std::numeric_limits<double>::max();
+    test.dOp2 = std::numeric_limits<double>::min();
+    test.fOp1 = std::numeric_limits<float>::min();
+    test.fOp2 = std::numeric_limits<float>::lowest();
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(test.dF, 0);
+    CHECK_EQ(test.dUn, 0);
+    CHECK_EQ(test.dEq, 0);
+    CHECK_EQ(test.dUeq, 0);
+    CHECK_EQ(test.dOlt, 0);
+    CHECK_EQ(test.dUlt, 0);
+    CHECK_EQ(test.dOle, 0);
+    CHECK_EQ(test.dUle, 0);
+    CHECK_EQ(test.fF, 0);
+    CHECK_EQ(test.fUn, 0);
+    CHECK_EQ(test.fEq, 0);
+    CHECK_EQ(test.fUeq, 0);
+    CHECK_EQ(test.fOlt, 0);
+    CHECK_EQ(test.fUlt, 0);
+    CHECK_EQ(test.fOle, 0);
+    CHECK_EQ(test.fUle, 0);
+
+    test.dOp1 = std::numeric_limits<double>::lowest();
+    test.dOp2 = std::numeric_limits<double>::lowest();
+    test.fOp1 = std::numeric_limits<float>::max();
+    test.fOp2 = std::numeric_limits<float>::max();
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(test.dF, 0);
+    CHECK_EQ(test.dUn, 0);
+    CHECK_EQ(test.dEq, 1);
+    CHECK_EQ(test.dUeq, 1);
+    CHECK_EQ(test.dOlt, 0);
+    CHECK_EQ(test.dUlt, 0);
+    CHECK_EQ(test.dOle, 1);
+    CHECK_EQ(test.dUle, 1);
+    CHECK_EQ(test.fF, 0);
+    CHECK_EQ(test.fUn, 0);
+    CHECK_EQ(test.fEq, 1);
+    CHECK_EQ(test.fUeq, 1);
+    CHECK_EQ(test.fOlt, 0);
+    CHECK_EQ(test.fUlt, 0);
+    CHECK_EQ(test.fOle, 1);
+    CHECK_EQ(test.fUle, 1);
+
+    test.dOp1 = std::numeric_limits<double>::quiet_NaN();
+    test.dOp2 = 0.0;
+    test.fOp1 = std::numeric_limits<float>::quiet_NaN();
+    test.fOp2 = 0.0;
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(test.dF, 0);
+    CHECK_EQ(test.dUn, 1);
+    CHECK_EQ(test.dEq, 0);
+    CHECK_EQ(test.dUeq, 1);
+    CHECK_EQ(test.dOlt, 0);
+    CHECK_EQ(test.dUlt, 1);
+    CHECK_EQ(test.dOle, 0);
+    CHECK_EQ(test.dUle, 1);
+    CHECK_EQ(test.fF, 0);
+    CHECK_EQ(test.fUn, 1);
+    CHECK_EQ(test.fEq, 0);
+    CHECK_EQ(test.fUeq, 1);
+    CHECK_EQ(test.fOlt, 0);
+    CHECK_EQ(test.fUlt, 1);
+    CHECK_EQ(test.fOle, 0);
+    CHECK_EQ(test.fUle, 1);
+  }
+}
+
+
+TEST(CMP_COND_FMT) {
+  if (IsMipsArchVariant(kMips32r6)) {
+    CcTest::InitializeVM();
+    Isolate* isolate = CcTest::i_isolate();
+    HandleScope scope(isolate);
+    MacroAssembler assm(isolate, NULL, 0);
+
+    typedef struct test_float {
+      double dOp1;
+      double dOp2;
+      double dF;
+      double dUn;
+      double dEq;
+      double dUeq;
+      double dOlt;
+      double dUlt;
+      double dOle;
+      double dUle;
+      double dOr;
+      double dUne;
+      double dNe;
+      float fOp1;
+      float fOp2;
+      float fF;
+      float fUn;
+      float fEq;
+      float fUeq;
+      float fOlt;
+      float fUlt;
+      float fOle;
+      float fUle;
+      float fOr;
+      float fUne;
+      float fNe;
+    } TestFloat;
+
+    TestFloat test;
+
+    __ li(t1, 1);
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, dOp1)));
+    __ ldc1(f6, MemOperand(a0, OFFSET_OF(TestFloat, dOp2)));
+
+    __ lwc1(f14, MemOperand(a0, OFFSET_OF(TestFloat, fOp1)));
+    __ lwc1(f16, MemOperand(a0, OFFSET_OF(TestFloat, fOp2)));
+
+    __ cmp_d(F, f2, f4, f6);
+    __ cmp_s(F, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dF)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fF)) );
+
+    __ cmp_d(UN, f2, f4, f6);
+    __ cmp_s(UN, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dUn)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fUn)) );
+
+    __ cmp_d(EQ, f2, f4, f6);
+    __ cmp_s(EQ, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dEq)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fEq)) );
+
+    __ cmp_d(UEQ, f2, f4, f6);
+    __ cmp_s(UEQ, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dUeq)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fUeq)) );
+
+    __ cmp_d(LT, f2, f4, f6);
+    __ cmp_s(LT, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dOlt)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fOlt)) );
+
+    __ cmp_d(ULT, f2, f4, f6);
+    __ cmp_s(ULT, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dUlt)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fUlt)) );
+
+    __ cmp_d(LE, f2, f4, f6);
+    __ cmp_s(LE, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dOle)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fOle)) );
+
+    __ cmp_d(ULE, f2, f4, f6);
+    __ cmp_s(ULE, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dUle)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fUle)) );
+
+    __ cmp_d(ORD, f2, f4, f6);
+    __ cmp_s(ORD, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dOr)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fOr)) );
+
+    __ cmp_d(UNE, f2, f4, f6);
+    __ cmp_s(UNE, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dUne)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fUne)) );
+
+    __ cmp_d(NE, f2, f4, f6);
+    __ cmp_s(NE, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dNe)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fNe)) );
+
+    __ jr(ra);
+    __ nop();
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+    uint64_t dTrue  = 0xFFFFFFFFFFFFFFFF;
+    uint64_t dFalse = 0x0000000000000000;
+    uint32_t fTrue  = 0xFFFFFFFF;
+    uint32_t fFalse = 0x00000000;
+
+    test.dOp1 = 2.0;
+    test.dOp2 = 3.0;
+    test.fOp1 = 2.0;
+    test.fOp2 = 3.0;
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOle), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dNe), dTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOle), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue);
+
+    test.dOp1 = std::numeric_limits<double>::max();
+    test.dOp2 = std::numeric_limits<double>::min();
+    test.fOp1 = std::numeric_limits<float>::min();
+    test.fOp2 = std::numeric_limits<float>::lowest();
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOle), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUle), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dNe), dTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOle), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUle), fFalse);
+
+    test.dOp1 = std::numeric_limits<double>::lowest();
+    test.dOp2 = std::numeric_limits<double>::lowest();
+    test.fOp1 = std::numeric_limits<float>::max();
+    test.fOp2 = std::numeric_limits<float>::max();
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dEq), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOle), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUne), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dNe), dFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fEq), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOle), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue);
+
+    test.dOp1 = std::numeric_limits<double>::quiet_NaN();
+    test.dOp2 = 0.0;
+    test.fOp1 = std::numeric_limits<float>::quiet_NaN();
+    test.fOp2 = 0.0;
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUn), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOle), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOr), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dNe), dFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUn), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOle), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue);
+  }
+}
+
+
+TEST(CVT) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  MacroAssembler assm(isolate, NULL, 0);
+
+  typedef struct test_float {
+    float    cvt_d_s_in;
+    double   cvt_d_s_out;
+    int32_t  cvt_d_w_in;
+    double   cvt_d_w_out;
+    int64_t  cvt_d_l_in;
+    double   cvt_d_l_out;
+
+    float    cvt_l_s_in;
+    int64_t  cvt_l_s_out;
+    double   cvt_l_d_in;
+    int64_t  cvt_l_d_out;
+
+    double   cvt_s_d_in;
+    float    cvt_s_d_out;
+    int32_t  cvt_s_w_in;
+    float    cvt_s_w_out;
+    int64_t  cvt_s_l_in;
+    float    cvt_s_l_out;
+
+    float    cvt_w_s_in;
+    int32_t  cvt_w_s_out;
+    double   cvt_w_d_in;
+    int32_t  cvt_w_d_out;
+  } TestFloat;
+
+  TestFloat test;
+
+  // Save FCSR.
+  __ cfc1(a1, FCSR);
+  // Disable FPU exceptions.
+  __ ctc1(zero_reg, FCSR);
+
+#define GENERATE_CVT_TEST(x, y, z) \
+  __ y##c1(f0, MemOperand(a0, OFFSET_OF(TestFloat, x##_in))); \
+  __ x(f0, f0); \
+  __ nop(); \
+  __ z##c1(f0, MemOperand(a0, OFFSET_OF(TestFloat, x##_out)));
+
+  GENERATE_CVT_TEST(cvt_d_s, lw, sd)
+  GENERATE_CVT_TEST(cvt_d_w, lw, sd)
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    GENERATE_CVT_TEST(cvt_d_l, ld, sd)
+  }
+
+  if (IsFp64Mode()) {
+    GENERATE_CVT_TEST(cvt_l_s, lw, sd)
+    GENERATE_CVT_TEST(cvt_l_d, ld, sd)
+  }
+
+  GENERATE_CVT_TEST(cvt_s_d, ld, sw)
+  GENERATE_CVT_TEST(cvt_s_w, lw, sw)
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    GENERATE_CVT_TEST(cvt_s_l, ld, sw)
+  }
+
+  GENERATE_CVT_TEST(cvt_w_s, lw, sw)
+  GENERATE_CVT_TEST(cvt_w_d, ld, sw)
+
+  // Restore FCSR.
+  __ ctc1(a1, FCSR);
+
+  __ jr(ra);
+  __ nop();
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+
+  test.cvt_d_s_in = -0.51;
+  test.cvt_d_w_in = -1;
+  test.cvt_d_l_in = -1;
+  test.cvt_l_s_in = -0.51;
+  test.cvt_l_d_in = -0.51;
+  test.cvt_s_d_in = -0.51;
+  test.cvt_s_w_in = -1;
+  test.cvt_s_l_in = -1;
+  test.cvt_w_s_in = -0.51;
+  test.cvt_w_d_in = -0.51;
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in));
+  CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in));
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in));
+  }
+  if (IsFp64Mode()) {
+    CHECK_EQ(test.cvt_l_s_out, -1);
+    CHECK_EQ(test.cvt_l_d_out, -1);
+  }
+  CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in));
+  CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in));
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in));
+  }
+  CHECK_EQ(test.cvt_w_s_out, -1);
+  CHECK_EQ(test.cvt_w_d_out, -1);
+
+
+  test.cvt_d_s_in = 0.49;
+  test.cvt_d_w_in = 1;
+  test.cvt_d_l_in = 1;
+  test.cvt_l_s_in = 0.49;
+  test.cvt_l_d_in = 0.49;
+  test.cvt_s_d_in = 0.49;
+  test.cvt_s_w_in = 1;
+  test.cvt_s_l_in = 1;
+  test.cvt_w_s_in = 0.49;
+  test.cvt_w_d_in = 0.49;
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in));
+  CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in));
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in));
+  }
+  if (IsFp64Mode()) {
+    CHECK_EQ(test.cvt_l_s_out, 0);
+    CHECK_EQ(test.cvt_l_d_out, 0);
+  }
+  CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in));
+  CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in));
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in));
+  }
+  CHECK_EQ(test.cvt_w_s_out, 0);
+  CHECK_EQ(test.cvt_w_d_out, 0);
+
+  test.cvt_d_s_in = std::numeric_limits<float>::max();
+  test.cvt_d_w_in = std::numeric_limits<int32_t>::max();
+  test.cvt_d_l_in = std::numeric_limits<int64_t>::max();
+  test.cvt_l_s_in = std::numeric_limits<float>::max();
+  test.cvt_l_d_in = std::numeric_limits<double>::max();
+  test.cvt_s_d_in = std::numeric_limits<double>::max();
+  test.cvt_s_w_in = std::numeric_limits<int32_t>::max();
+  test.cvt_s_l_in = std::numeric_limits<int64_t>::max();
+  test.cvt_w_s_in = std::numeric_limits<float>::max();
+  test.cvt_w_d_in = std::numeric_limits<double>::max();
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in));
+  CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in));
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in));
+  }
+  if (IsFp64Mode()) {
+    CHECK_EQ(test.cvt_l_s_out, std::numeric_limits<int64_t>::max());
+    CHECK_EQ(test.cvt_l_d_out, std::numeric_limits<int64_t>::max());
+  }
+  CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in));
+  CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in));
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in));
+  }
+  CHECK_EQ(test.cvt_w_s_out, std::numeric_limits<int32_t>::max());
+  CHECK_EQ(test.cvt_w_d_out, std::numeric_limits<int32_t>::max());
+
+
+  test.cvt_d_s_in = std::numeric_limits<float>::lowest();
+  test.cvt_d_w_in = std::numeric_limits<int32_t>::lowest();
+  test.cvt_d_l_in = std::numeric_limits<int64_t>::lowest();
+  test.cvt_l_s_in = std::numeric_limits<float>::lowest();
+  test.cvt_l_d_in = std::numeric_limits<double>::lowest();
+  test.cvt_s_d_in = std::numeric_limits<double>::lowest();
+  test.cvt_s_w_in = std::numeric_limits<int32_t>::lowest();
+  test.cvt_s_l_in = std::numeric_limits<int64_t>::lowest();
+  test.cvt_w_s_in = std::numeric_limits<float>::lowest();
+  test.cvt_w_d_in = std::numeric_limits<double>::lowest();
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in));
+  CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in));
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in));
+  }
+  // The returned value when converting from fixed-point to float-point
+  // is not consistent between board, simulator and specification
+  // in this test case, therefore modifying the test
+  if (IsFp64Mode()) {
+    CHECK(test.cvt_l_s_out == std::numeric_limits<int64_t>::min() ||
+         test.cvt_l_s_out == std::numeric_limits<int64_t>::max());
+    CHECK(test.cvt_l_d_out == std::numeric_limits<int64_t>::min() ||
+          test.cvt_l_d_out == std::numeric_limits<int64_t>::max());
+  }
+  CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in));
+  CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in));
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in));
+  }
+  CHECK(test.cvt_w_s_out == std::numeric_limits<int32_t>::min() ||
+        test.cvt_w_s_out == std::numeric_limits<int32_t>::max());
+  CHECK(test.cvt_w_d_out == std::numeric_limits<int32_t>::min() ||
+        test.cvt_w_d_out == std::numeric_limits<int32_t>::max());
+
+
+  test.cvt_d_s_in = std::numeric_limits<float>::min();
+  test.cvt_d_w_in = std::numeric_limits<int32_t>::min();
+  test.cvt_d_l_in = std::numeric_limits<int64_t>::min();
+  test.cvt_l_s_in = std::numeric_limits<float>::min();
+  test.cvt_l_d_in = std::numeric_limits<double>::min();
+  test.cvt_s_d_in = std::numeric_limits<double>::min();
+  test.cvt_s_w_in = std::numeric_limits<int32_t>::min();
+  test.cvt_s_l_in = std::numeric_limits<int64_t>::min();
+  test.cvt_w_s_in = std::numeric_limits<float>::min();
+  test.cvt_w_d_in = std::numeric_limits<double>::min();
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in));
+  CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in));
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in));
+  }
+  if (IsFp64Mode()) {
+    CHECK_EQ(test.cvt_l_s_out, 0);
+    CHECK_EQ(test.cvt_l_d_out, 0);
+  }
+  CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in));
+  CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in));
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in));
+  }
+  CHECK_EQ(test.cvt_w_s_out, 0);
+  CHECK_EQ(test.cvt_w_d_out, 0);
+}
+
+
+TEST(DIV_FMT) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  MacroAssembler assm(isolate, NULL, 0);
+
+  typedef struct test {
+    double dOp1;
+    double dOp2;
+    double dRes;
+    float  fOp1;
+    float  fOp2;
+    float  fRes;
+  } Test;
+
+  Test test;
+
+  // Save FCSR.
+  __ cfc1(a1, FCSR);
+  // Disable FPU exceptions.
+  __ ctc1(zero_reg, FCSR);
+
+  __ ldc1(f4, MemOperand(a0, OFFSET_OF(Test, dOp1)) );
+  __ ldc1(f2, MemOperand(a0, OFFSET_OF(Test, dOp2)) );
+  __ nop();
+  __ div_d(f6, f4, f2);
+  __ sdc1(f6, MemOperand(a0, OFFSET_OF(Test, dRes)) );
+
+  __ lwc1(f4, MemOperand(a0, OFFSET_OF(Test, fOp1)) );
+  __ lwc1(f2, MemOperand(a0, OFFSET_OF(Test, fOp2)) );
+  __ nop();
+  __ div_s(f6, f4, f2);
+  __ swc1(f6, MemOperand(a0, OFFSET_OF(Test, fRes)) );
+
+    // Restore FCSR.
+  __ ctc1(a1, FCSR);
+
+  __ jr(ra);
+  __ nop();
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+
+  const int test_size = 3;
+
+  double dOp1[test_size] = {
+    5.0,
+    DBL_MAX,
+    DBL_MAX,
+  };
+  double dOp2[test_size] = {
+    2.0,
+    2.0,
+    -DBL_MAX,
+  };
+  double dRes[test_size] = {
+    2.5,
+    DBL_MAX / 2.0,
+    -1.0,
+  };
+  float fOp1[test_size] = {
+    5.0,
+    FLT_MAX,
+    FLT_MAX,
+  };
+  float fOp2[test_size] = {
+    2.0,
+    2.0,
+    -FLT_MAX,
+  };
+  float fRes[test_size] = {
+    2.5,
+    FLT_MAX / 2.0,
+    -1.0,
+  };
+
+  for (int i = 0; i < test_size; i++) {
+    test.dOp1 = dOp1[i];
+    test.dOp2 = dOp2[i];
+    test.fOp1 = fOp1[i];
+    test.fOp2 = fOp2[i];
+
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(test.dRes, dRes[i]);
+    CHECK_EQ(test.fRes, fRes[i]);
+  }
+
+  test.dOp1 = DBL_MAX;
+  test.dOp2 = -0.0;
+  test.fOp1 = FLT_MAX;
+  test.fOp2 = -0.0;
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(false, std::isfinite(test.dRes));
+  CHECK_EQ(false, std::isfinite(test.fRes));
+
+  test.dOp1 = 0.0;
+  test.dOp2 = -0.0;
+  test.fOp1 = 0.0;
+  test.fOp2 = -0.0;
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(true, std::isnan(test.dRes));
+  CHECK_EQ(true, std::isnan(test.fRes));
+
+  test.dOp1 = std::numeric_limits<double>::quiet_NaN();
+  test.dOp2 = -5.0;
+  test.fOp1 = std::numeric_limits<float>::quiet_NaN();
+  test.fOp2 = -5.0;
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(true, std::isnan(test.dRes));
+  CHECK_EQ(true, std::isnan(test.fRes));
+}
+
+
 #undef __
index 97f9984b212288876ce8a345038c3fef5a53846b..4798bdbcddcf55e34c90dc23f4f3c01c9a5b144b 100644 (file)
@@ -3284,4 +3284,1166 @@ TEST(jump_tables3) {
 }
 
 
+TEST(BITSWAP) {
+  // Test BITSWAP
+  if (kArchVariant == kMips64r6) {
+    CcTest::InitializeVM();
+    Isolate* isolate = CcTest::i_isolate();
+    HandleScope scope(isolate);
+
+    typedef struct {
+      int64_t r1;
+      int64_t r2;
+      int64_t r3;
+      int64_t r4;
+      int64_t r5;
+      int64_t r6;
+    } T;
+    T t;
+
+    Assembler assm(isolate, NULL, 0);
+
+    __ ld(a4, MemOperand(a0, OFFSET_OF(T, r1)));
+    __ nop();
+    __ bitswap(a6, a4);
+    __ sd(a6, MemOperand(a0, OFFSET_OF(T, r1)));
+
+    __ ld(a4, MemOperand(a0, OFFSET_OF(T, r2)));
+    __ nop();
+    __ bitswap(a6, a4);
+    __ sd(a6, MemOperand(a0, OFFSET_OF(T, r2)));
+
+    __ ld(a4, MemOperand(a0, OFFSET_OF(T, r3)));
+    __ nop();
+    __ bitswap(a6, a4);
+    __ sd(a6, MemOperand(a0, OFFSET_OF(T, r3)));
+
+    __ ld(a4, MemOperand(a0, OFFSET_OF(T, r4)));
+    __ nop();
+    __ bitswap(a6, a4);
+    __ sd(a6, MemOperand(a0, OFFSET_OF(T, r4)));
+
+    __ ld(a4, MemOperand(a0, OFFSET_OF(T, r5)));
+    __ nop();
+    __ dbitswap(a6, a4);
+    __ sd(a6, MemOperand(a0, OFFSET_OF(T, r5)));
+
+    __ ld(a4, MemOperand(a0, OFFSET_OF(T, r6)));
+    __ nop();
+    __ dbitswap(a6, a4);
+    __ sd(a6, MemOperand(a0, OFFSET_OF(T, r6)));
+
+    __ jr(ra);
+    __ nop();
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+    t.r1 = 0x00102100781A15C3;
+    t.r2 = 0x001021008B71FCDE;
+    t.r3 = 0xFF8017FF781A15C3;
+    t.r4 = 0xFF8017FF8B71FCDE;
+    t.r5 = 0x10C021098B71FCDE;
+    t.r6 = 0xFB8017FF781A15C3;
+    Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+    USE(dummy);
+
+    CHECK_EQ(static_cast<int64_t>(0x000000001E58A8C3L), t.r1);
+    CHECK_EQ(static_cast<int64_t>(0xFFFFFFFFD18E3F7BL), t.r2);
+    CHECK_EQ(static_cast<int64_t>(0x000000001E58A8C3L), t.r3);
+    CHECK_EQ(static_cast<int64_t>(0xFFFFFFFFD18E3F7BL), t.r4);
+    CHECK_EQ(static_cast<int64_t>(0x08038490D18E3F7BL), t.r5);
+    CHECK_EQ(static_cast<int64_t>(0xDF01E8FF1E58A8C3L), t.r6);
+  }
+}
+
+
+TEST(class_fmt) {
+  if (kArchVariant == kMips64r6) {
+    // Test CLASS.fmt instruction.
+    CcTest::InitializeVM();
+    Isolate* isolate = CcTest::i_isolate();
+    HandleScope scope(isolate);
+
+    typedef struct {
+      double dSignalingNan;
+      double dQuietNan;
+      double dNegInf;
+      double dNegNorm;
+      double dNegSubnorm;
+      double dNegZero;
+      double dPosInf;
+      double dPosNorm;
+      double dPosSubnorm;
+      double dPosZero;
+      float  fSignalingNan;
+      float  fQuietNan;
+      float  fNegInf;
+      float  fNegNorm;
+      float  fNegSubnorm;
+      float  fNegZero;
+      float  fPosInf;
+      float  fPosNorm;
+      float  fPosSubnorm;
+      float  fPosZero;  } T;
+    T t;
+
+    // Create a function that accepts &t, and loads, manipulates, and stores
+    // the doubles t.a ... t.f.
+    MacroAssembler assm(isolate, NULL, 0);
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dSignalingNan)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dSignalingNan)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dQuietNan)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dQuietNan)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dNegInf)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dNegInf)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dNegNorm)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dNegNorm)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dNegSubnorm)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dNegSubnorm)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dNegZero)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dNegZero)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dPosInf)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dPosInf)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dPosNorm)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dPosNorm)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dPosSubnorm)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dPosSubnorm)));
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, dPosZero)));
+    __ class_d(f6, f4);
+    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, dPosZero)));
+
+    // Testing instruction CLASS.S
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fSignalingNan)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fSignalingNan)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fQuietNan)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fQuietNan)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fNegInf)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fNegInf)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fNegNorm)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fNegNorm)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fNegSubnorm)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fNegSubnorm)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fNegZero)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fNegZero)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fPosInf)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fPosInf)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fPosNorm)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fPosNorm)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fPosSubnorm)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fPosSubnorm)));
+
+    __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fPosZero)));
+    __ class_s(f6, f4);
+    __ swc1(f6, MemOperand(a0, OFFSET_OF(T, fPosZero)));
+
+    __ jr(ra);
+    __ nop();
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+
+    // Double test values.
+    t.dSignalingNan =  std::numeric_limits<double>::signaling_NaN();
+    t.dQuietNan = std::numeric_limits<double>::quiet_NaN();
+    t.dNegInf       = -1.0 / 0.0;
+    t.dNegNorm      = -5.0;
+    t.dNegSubnorm   = -DBL_MIN / 2.0;
+    t.dNegZero      = -0.0;
+    t.dPosInf       = 2.0 / 0.0;
+    t.dPosNorm      = 275.35;
+    t.dPosSubnorm   = DBL_MIN / 2.0;
+    t.dPosZero      = +0.0;
+    // Float test values
+
+    t.fSignalingNan = std::numeric_limits<float>::signaling_NaN();
+    t.fQuietNan     = std::numeric_limits<float>::quiet_NaN();
+    t.fNegInf       = -0.5/0.0;
+    t.fNegNorm      = -FLT_MIN;
+    t.fNegSubnorm   = -FLT_MIN / 1.5;
+    t.fNegZero      = -0.0;
+    t.fPosInf       = 100000.0 / 0.0;
+    t.fPosNorm      = FLT_MAX;
+    t.fPosSubnorm   = FLT_MIN / 20.0;
+    t.fPosZero      = +0.0;
+
+    Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+    USE(dummy);
+    // Expected double results.
+    CHECK_EQ(bit_cast<uint64_t>(t.dNegInf),       0x004);
+    CHECK_EQ(bit_cast<uint64_t>(t.dNegNorm),      0x008);
+    CHECK_EQ(bit_cast<uint64_t>(t.dNegSubnorm),   0x010);
+    CHECK_EQ(bit_cast<uint64_t>(t.dNegZero),      0x020);
+    CHECK_EQ(bit_cast<uint64_t>(t.dPosInf),       0x040);
+    CHECK_EQ(bit_cast<uint64_t>(t.dPosNorm),      0x080);
+    CHECK_EQ(bit_cast<uint64_t>(t.dPosSubnorm),   0x100);
+    CHECK_EQ(bit_cast<uint64_t>(t.dPosZero),      0x200);
+
+    // Expected float results.
+    CHECK_EQ(bit_cast<uint32_t>(t.fNegInf),       0x004);
+    CHECK_EQ(bit_cast<uint32_t>(t.fNegNorm),      0x008);
+    CHECK_EQ(bit_cast<uint32_t>(t.fNegSubnorm),   0x010);
+    CHECK_EQ(bit_cast<uint32_t>(t.fNegZero),      0x020);
+    CHECK_EQ(bit_cast<uint32_t>(t.fPosInf),       0x040);
+    CHECK_EQ(bit_cast<uint32_t>(t.fPosNorm),      0x080);
+    CHECK_EQ(bit_cast<uint32_t>(t.fPosSubnorm),   0x100);
+    CHECK_EQ(bit_cast<uint32_t>(t.fPosZero),      0x200);
+  }
+}
+
+
+TEST(ABS) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  MacroAssembler assm(isolate, NULL, 0);
+
+  typedef struct test_float {
+    int64_t fir;
+    double a;
+    float b;
+    double fcsr;
+  } TestFloat;
+
+  TestFloat test;
+
+  // Save FIR.
+  __ cfc1(a1, FCSR);
+  __ sd(a1, MemOperand(a0, OFFSET_OF(TestFloat, fcsr)));
+  // Disable FPU exceptions.
+  __ ctc1(zero_reg, FCSR);
+
+  __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, a)));
+  __ abs_d(f10, f4);
+  __ sdc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, a)));
+
+  __ lwc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, b)));
+  __ abs_s(f10, f4);
+  __ swc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, b)));
+
+  // Restore FCSR.
+  __ ctc1(a1, FCSR);
+
+  __ jr(ra);
+  __ nop();
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  test.a = -2.0;
+  test.b = -2.0;
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, 2.0);
+  CHECK_EQ(test.b, 2.0);
+
+  test.a = 2.0;
+  test.b = 2.0;
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, 2.0);
+  CHECK_EQ(test.b, 2.0);
+
+  // Testing biggest positive number
+  test.a = std::numeric_limits<double>::max();
+  test.b = std::numeric_limits<float>::max();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, std::numeric_limits<double>::max());
+  CHECK_EQ(test.b, std::numeric_limits<float>::max());
+
+  // Testing smallest negative number
+  test.a = -std::numeric_limits<double>::lowest();
+  test.b = -std::numeric_limits<float>::lowest();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, std::numeric_limits<double>::max());
+  CHECK_EQ(test.b, std::numeric_limits<float>::max());
+
+  // Testing smallest positive number
+  test.a = -std::numeric_limits<double>::min();
+  test.b = -std::numeric_limits<float>::min();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, std::numeric_limits<double>::min());
+  CHECK_EQ(test.b, std::numeric_limits<float>::min());
+
+  // Testing infinity
+  test.a = -std::numeric_limits<double>::max()
+          / std::numeric_limits<double>::min();
+  test.b = -std::numeric_limits<float>::max()
+          / std::numeric_limits<float>::min();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.a, std::numeric_limits<double>::max()
+                 / std::numeric_limits<double>::min());
+  CHECK_EQ(test.b, std::numeric_limits<float>::max()
+                 / std::numeric_limits<float>::min());
+
+  test.a = std::numeric_limits<double>::quiet_NaN();
+  test.b = std::numeric_limits<float>::quiet_NaN();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(std::isnan(test.a), true);
+  CHECK_EQ(std::isnan(test.b), true);
+
+  test.a = std::numeric_limits<double>::signaling_NaN();
+  test.b = std::numeric_limits<float>::signaling_NaN();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(std::isnan(test.a), true);
+  CHECK_EQ(std::isnan(test.b), true);
+}
+
+
+TEST(ADD_FMT) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  MacroAssembler assm(isolate, NULL, 0);
+
+  typedef struct test_float {
+    double a;
+    double b;
+    double c;
+    float fa;
+    float fb;
+    float fc;
+  } TestFloat;
+
+  TestFloat test;
+
+  __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, a)));
+  __ ldc1(f8, MemOperand(a0, OFFSET_OF(TestFloat, b)));
+  __ add_d(f10, f8, f4);
+  __ sdc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, c)));
+
+  __ lwc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, fa)));
+  __ lwc1(f8, MemOperand(a0, OFFSET_OF(TestFloat, fb)));
+  __ add_s(f10, f8, f4);
+  __ swc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, fc)));
+
+  __ jr(ra);
+  __ nop();
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  test.a = 2.0;
+  test.b = 3.0;
+  test.fa = 2.0;
+  test.fb = 3.0;
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.c, 5.0);
+  CHECK_EQ(test.fc, 5.0);
+
+  test.a = std::numeric_limits<double>::max();
+  test.b = std::numeric_limits<double>::lowest();
+  test.fa = std::numeric_limits<float>::max();
+  test.fb = std::numeric_limits<float>::lowest();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.c, 0.0);
+  CHECK_EQ(test.fc, 0.0);
+
+  test.a = std::numeric_limits<double>::max();
+  test.b = std::numeric_limits<double>::max();
+  test.fa = std::numeric_limits<float>::max();
+  test.fb = std::numeric_limits<float>::max();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(std::isfinite(test.c), false);
+  CHECK_EQ(std::isfinite(test.fc), false);
+
+  test.a = 5.0;
+  test.b = std::numeric_limits<double>::signaling_NaN();
+  test.fa = 5.0;
+  test.fb = std::numeric_limits<float>::signaling_NaN();
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(std::isnan(test.c), true);
+  CHECK_EQ(std::isnan(test.fc), true);
+}
+
+
+TEST(C_COND_FMT) {
+  if (kArchVariant == kMips64r2) {
+    CcTest::InitializeVM();
+    Isolate* isolate = CcTest::i_isolate();
+    HandleScope scope(isolate);
+    MacroAssembler assm(isolate, NULL, 0);
+
+    typedef struct test_float {
+      double dOp1;
+      double dOp2;
+      uint32_t dF;
+      uint32_t dUn;
+      uint32_t dEq;
+      uint32_t dUeq;
+      uint32_t dOlt;
+      uint32_t dUlt;
+      uint32_t dOle;
+      uint32_t dUle;
+      float fOp1;
+      float fOp2;
+      uint32_t fF;
+      uint32_t fUn;
+      uint32_t fEq;
+      uint32_t fUeq;
+      uint32_t fOlt;
+      uint32_t fUlt;
+      uint32_t fOle;
+      uint32_t fUle;
+    } TestFloat;
+
+    TestFloat test;
+
+    __ li(t1, 1);
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, dOp1)));
+    __ ldc1(f6, MemOperand(a0, OFFSET_OF(TestFloat, dOp2)));
+
+    __ lwc1(f14, MemOperand(a0, OFFSET_OF(TestFloat, fOp1)));
+    __ lwc1(f16, MemOperand(a0, OFFSET_OF(TestFloat, fOp2)));
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(F, f4, f6, 0);
+    __ c_s(F, f14, f16, 2);
+    __ movt(t2, t1, 0);
+    __ movt(t3, t1, 2);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dF)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fF)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(UN, f4, f6, 2);
+    __ c_s(UN, f14, f16, 4);
+    __ movt(t2, t1, 2);
+    __ movt(t3, t1, 4);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dUn)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fUn)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(EQ, f4, f6, 4);
+    __ c_s(EQ, f14, f16, 6);
+    __ movt(t2, t1, 4);
+    __ movt(t3, t1, 6);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dEq)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fEq)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(UEQ, f4, f6, 6);
+    __ c_s(UEQ, f14, f16, 0);
+    __ movt(t2, t1, 6);
+    __ movt(t3, t1, 0);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dUeq)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fUeq)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(OLT, f4, f6, 0);
+    __ c_s(OLT, f14, f16, 2);
+    __ movt(t2, t1, 0);
+    __ movt(t3, t1, 2);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dOlt)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fOlt)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(ULT, f4, f6, 2);
+    __ c_s(ULT, f14, f16, 4);
+    __ movt(t2, t1, 2);
+    __ movt(t3, t1, 4);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dUlt)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fUlt)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(OLE, f4, f6, 4);
+    __ c_s(OLE, f14, f16, 6);
+    __ movt(t2, t1, 4);
+    __ movt(t3, t1, 6);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dOle)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fOle)) );
+
+    __ mov(t2, zero_reg);
+    __ mov(t3, zero_reg);
+    __ c_d(ULE, f4, f6, 6);
+    __ c_s(ULE, f14, f16, 0);
+    __ movt(t2, t1, 6);
+    __ movt(t3, t1, 0);
+    __ sw(t2, MemOperand(a0, OFFSET_OF(TestFloat, dUle)) );
+    __ sw(t3, MemOperand(a0, OFFSET_OF(TestFloat, fUle)) );
+
+    __ jr(ra);
+    __ nop();
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+    test.dOp1 = 2.0;
+    test.dOp2 = 3.0;
+    test.fOp1 = 2.0;
+    test.fOp2 = 3.0;
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(test.dF, 0);
+    CHECK_EQ(test.dUn, 0);
+    CHECK_EQ(test.dEq, 0);
+    CHECK_EQ(test.dUeq, 0);
+    CHECK_EQ(test.dOlt, 1);
+    CHECK_EQ(test.dUlt, 1);
+    CHECK_EQ(test.dOle, 1);
+    CHECK_EQ(test.dUle, 1);
+    CHECK_EQ(test.fF, 0);
+    CHECK_EQ(test.fUn, 0);
+    CHECK_EQ(test.fEq, 0);
+    CHECK_EQ(test.fUeq, 0);
+    CHECK_EQ(test.fOlt, 1);
+    CHECK_EQ(test.fUlt, 1);
+    CHECK_EQ(test.fOle, 1);
+    CHECK_EQ(test.fUle, 1);
+
+    test.dOp1 = std::numeric_limits<double>::max();
+    test.dOp2 = std::numeric_limits<double>::min();
+    test.fOp1 = std::numeric_limits<float>::min();
+    test.fOp2 = std::numeric_limits<float>::lowest();
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(test.dF, 0);
+    CHECK_EQ(test.dUn, 0);
+    CHECK_EQ(test.dEq, 0);
+    CHECK_EQ(test.dUeq, 0);
+    CHECK_EQ(test.dOlt, 0);
+    CHECK_EQ(test.dUlt, 0);
+    CHECK_EQ(test.dOle, 0);
+    CHECK_EQ(test.dUle, 0);
+    CHECK_EQ(test.fF, 0);
+    CHECK_EQ(test.fUn, 0);
+    CHECK_EQ(test.fEq, 0);
+    CHECK_EQ(test.fUeq, 0);
+    CHECK_EQ(test.fOlt, 0);
+    CHECK_EQ(test.fUlt, 0);
+    CHECK_EQ(test.fOle, 0);
+    CHECK_EQ(test.fUle, 0);
+
+    test.dOp1 = std::numeric_limits<double>::lowest();
+    test.dOp2 = std::numeric_limits<double>::lowest();
+    test.fOp1 = std::numeric_limits<float>::max();
+    test.fOp2 = std::numeric_limits<float>::max();
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(test.dF, 0);
+    CHECK_EQ(test.dUn, 0);
+    CHECK_EQ(test.dEq, 1);
+    CHECK_EQ(test.dUeq, 1);
+    CHECK_EQ(test.dOlt, 0);
+    CHECK_EQ(test.dUlt, 0);
+    CHECK_EQ(test.dOle, 1);
+    CHECK_EQ(test.dUle, 1);
+    CHECK_EQ(test.fF, 0);
+    CHECK_EQ(test.fUn, 0);
+    CHECK_EQ(test.fEq, 1);
+    CHECK_EQ(test.fUeq, 1);
+    CHECK_EQ(test.fOlt, 0);
+    CHECK_EQ(test.fUlt, 0);
+    CHECK_EQ(test.fOle, 1);
+    CHECK_EQ(test.fUle, 1);
+
+    test.dOp1 = std::numeric_limits<double>::quiet_NaN();
+    test.dOp2 = 0.0;
+    test.fOp1 = std::numeric_limits<float>::quiet_NaN();
+    test.fOp2 = 0.0;
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(test.dF, 0);
+    CHECK_EQ(test.dUn, 1);
+    CHECK_EQ(test.dEq, 0);
+    CHECK_EQ(test.dUeq, 1);
+    CHECK_EQ(test.dOlt, 0);
+    CHECK_EQ(test.dUlt, 1);
+    CHECK_EQ(test.dOle, 0);
+    CHECK_EQ(test.dUle, 1);
+    CHECK_EQ(test.fF, 0);
+    CHECK_EQ(test.fUn, 1);
+    CHECK_EQ(test.fEq, 0);
+    CHECK_EQ(test.fUeq, 1);
+    CHECK_EQ(test.fOlt, 0);
+    CHECK_EQ(test.fUlt, 1);
+    CHECK_EQ(test.fOle, 0);
+    CHECK_EQ(test.fUle, 1);
+  }
+}
+
+
+TEST(CMP_COND_FMT) {
+  if (kArchVariant == kMips64r6) {
+    CcTest::InitializeVM();
+    Isolate* isolate = CcTest::i_isolate();
+    HandleScope scope(isolate);
+    MacroAssembler assm(isolate, NULL, 0);
+
+    typedef struct test_float {
+      double dOp1;
+      double dOp2;
+      double dF;
+      double dUn;
+      double dEq;
+      double dUeq;
+      double dOlt;
+      double dUlt;
+      double dOle;
+      double dUle;
+      double dOr;
+      double dUne;
+      double dNe;
+      float fOp1;
+      float fOp2;
+      float fF;
+      float fUn;
+      float fEq;
+      float fUeq;
+      float fOlt;
+      float fUlt;
+      float fOle;
+      float fUle;
+      float fOr;
+      float fUne;
+      float fNe;
+    } TestFloat;
+
+    TestFloat test;
+
+    __ li(t1, 1);
+
+    __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, dOp1)));
+    __ ldc1(f6, MemOperand(a0, OFFSET_OF(TestFloat, dOp2)));
+
+    __ lwc1(f14, MemOperand(a0, OFFSET_OF(TestFloat, fOp1)));
+    __ lwc1(f16, MemOperand(a0, OFFSET_OF(TestFloat, fOp2)));
+
+    __ cmp_d(F, f2, f4, f6);
+    __ cmp_s(F, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dF)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fF)) );
+
+    __ cmp_d(UN, f2, f4, f6);
+    __ cmp_s(UN, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dUn)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fUn)) );
+
+    __ cmp_d(EQ, f2, f4, f6);
+    __ cmp_s(EQ, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dEq)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fEq)) );
+
+    __ cmp_d(UEQ, f2, f4, f6);
+    __ cmp_s(UEQ, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dUeq)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fUeq)) );
+
+    __ cmp_d(LT, f2, f4, f6);
+    __ cmp_s(LT, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dOlt)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fOlt)) );
+
+    __ cmp_d(ULT, f2, f4, f6);
+    __ cmp_s(ULT, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dUlt)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fUlt)) );
+
+    __ cmp_d(LE, f2, f4, f6);
+    __ cmp_s(LE, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dOle)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fOle)) );
+
+    __ cmp_d(ULE, f2, f4, f6);
+    __ cmp_s(ULE, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dUle)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fUle)) );
+
+    __ cmp_d(ORD, f2, f4, f6);
+    __ cmp_s(ORD, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dOr)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fOr)) );
+
+    __ cmp_d(UNE, f2, f4, f6);
+    __ cmp_s(UNE, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dUne)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fUne)) );
+
+    __ cmp_d(NE, f2, f4, f6);
+    __ cmp_s(NE, f12, f14, f16);
+    __ sdc1(f2, MemOperand(a0, OFFSET_OF(TestFloat, dNe)) );
+    __ swc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, fNe)) );
+
+    __ jr(ra);
+    __ nop();
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+    uint64_t dTrue  = 0xFFFFFFFFFFFFFFFF;
+    uint64_t dFalse = 0x0000000000000000;
+    uint32_t fTrue  = 0xFFFFFFFF;
+    uint32_t fFalse = 0x00000000;
+
+    test.dOp1 = 2.0;
+    test.dOp2 = 3.0;
+    test.fOp1 = 2.0;
+    test.fOp2 = 3.0;
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOle), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dNe), dTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOle), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue);
+
+    test.dOp1 = std::numeric_limits<double>::max();
+    test.dOp2 = std::numeric_limits<double>::min();
+    test.fOp1 = std::numeric_limits<float>::min();
+    test.fOp2 = std::numeric_limits<float>::lowest();
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOle), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUle), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dNe), dTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOle), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUle), fFalse);
+
+    test.dOp1 = std::numeric_limits<double>::lowest();
+    test.dOp2 = std::numeric_limits<double>::lowest();
+    test.fOp1 = std::numeric_limits<float>::max();
+    test.fOp2 = std::numeric_limits<float>::max();
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dEq), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOle), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUne), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dNe), dFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fEq), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOle), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue);
+
+    test.dOp1 = std::numeric_limits<double>::quiet_NaN();
+    test.dOp2 = 0.0;
+    test.fOp1 = std::numeric_limits<float>::quiet_NaN();
+    test.fOp2 = 0.0;
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUn), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOle), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dOr), dFalse);
+    CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue);
+    CHECK_EQ(bit_cast<uint64_t>(test.dNe), dFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUn), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fTrue);
+    CHECK_EQ(bit_cast<uint32_t>(test.fOle), fFalse);
+    CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue);
+  }
+}
+
+
+TEST(CVT) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  MacroAssembler assm(isolate, NULL, 0);
+
+  typedef struct test_float {
+    float    cvt_d_s_in;
+    double   cvt_d_s_out;
+    int32_t  cvt_d_w_in;
+    double   cvt_d_w_out;
+    int64_t  cvt_d_l_in;
+    double   cvt_d_l_out;
+
+    float    cvt_l_s_in;
+    int64_t  cvt_l_s_out;
+    double   cvt_l_d_in;
+    int64_t  cvt_l_d_out;
+
+    double   cvt_s_d_in;
+    float    cvt_s_d_out;
+    int32_t  cvt_s_w_in;
+    float    cvt_s_w_out;
+    int64_t  cvt_s_l_in;
+    float    cvt_s_l_out;
+
+    float    cvt_w_s_in;
+    int32_t  cvt_w_s_out;
+    double   cvt_w_d_in;
+    int32_t  cvt_w_d_out;
+  } TestFloat;
+
+  TestFloat test;
+
+  // Save FCSR.
+  __ cfc1(a1, FCSR);
+  // Disable FPU exceptions.
+  __ ctc1(zero_reg, FCSR);
+
+#define GENERATE_CVT_TEST(x, y, z) \
+  __ y##c1(f0, MemOperand(a0, OFFSET_OF(TestFloat, x##_in))); \
+  __ x(f0, f0); \
+  __ nop(); \
+  __ z##c1(f0, MemOperand(a0, OFFSET_OF(TestFloat, x##_out)));
+
+  GENERATE_CVT_TEST(cvt_d_s, lw, sd)
+  GENERATE_CVT_TEST(cvt_d_w, lw, sd)
+  GENERATE_CVT_TEST(cvt_d_l, ld, sd)
+
+  GENERATE_CVT_TEST(cvt_l_s, lw, sd)
+  GENERATE_CVT_TEST(cvt_l_d, ld, sd)
+
+  GENERATE_CVT_TEST(cvt_s_d, ld, sw)
+  GENERATE_CVT_TEST(cvt_s_w, lw, sw)
+  GENERATE_CVT_TEST(cvt_s_l, ld, sw)
+
+  GENERATE_CVT_TEST(cvt_w_s, lw, sw)
+  GENERATE_CVT_TEST(cvt_w_d, ld, sw)
+
+  // Restore FCSR.
+  __ ctc1(a1, FCSR);
+
+  __ jr(ra);
+  __ nop();
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+
+  test.cvt_d_s_in = -0.51;
+  test.cvt_d_w_in = -1;
+  test.cvt_d_l_in = -1;
+  test.cvt_l_s_in = -0.51;
+  test.cvt_l_d_in = -0.51;
+  test.cvt_s_d_in = -0.51;
+  test.cvt_s_w_in = -1;
+  test.cvt_s_l_in = -1;
+  test.cvt_w_s_in = -0.51;
+  test.cvt_w_d_in = -0.51;
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in));
+  CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in));
+  CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in));
+  CHECK_EQ(test.cvt_l_s_out, -1);
+  CHECK_EQ(test.cvt_l_d_out, -1);
+  CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in));
+  CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in));
+  CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in));
+  CHECK_EQ(test.cvt_w_s_out, -1);
+  CHECK_EQ(test.cvt_w_d_out, -1);
+
+
+  test.cvt_d_s_in = 0.49;
+  test.cvt_d_w_in = 1;
+  test.cvt_d_l_in = 1;
+  test.cvt_l_s_in = 0.49;
+  test.cvt_l_d_in = 0.49;
+  test.cvt_s_d_in = 0.49;
+  test.cvt_s_w_in = 1;
+  test.cvt_s_l_in = 1;
+  test.cvt_w_s_in = 0.49;
+  test.cvt_w_d_in = 0.49;
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in));
+  CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in));
+  CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in));
+  CHECK_EQ(test.cvt_l_s_out, 0);
+  CHECK_EQ(test.cvt_l_d_out, 0);
+  CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in));
+  CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in));
+  CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in));
+  CHECK_EQ(test.cvt_w_s_out, 0);
+  CHECK_EQ(test.cvt_w_d_out, 0);
+
+  test.cvt_d_s_in = std::numeric_limits<float>::max();
+  test.cvt_d_w_in = std::numeric_limits<int32_t>::max();
+  test.cvt_d_l_in = std::numeric_limits<int64_t>::max();
+  test.cvt_l_s_in = std::numeric_limits<float>::max();
+  test.cvt_l_d_in = std::numeric_limits<double>::max();
+  test.cvt_s_d_in = std::numeric_limits<double>::max();
+  test.cvt_s_w_in = std::numeric_limits<int32_t>::max();
+  test.cvt_s_l_in = std::numeric_limits<int64_t>::max();
+  test.cvt_w_s_in = std::numeric_limits<float>::max();
+  test.cvt_w_d_in = std::numeric_limits<double>::max();
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in));
+  CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in));
+  CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in));
+  CHECK_EQ(test.cvt_l_s_out, std::numeric_limits<int64_t>::max());
+  CHECK_EQ(test.cvt_l_d_out, std::numeric_limits<int64_t>::max());
+  CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in));
+  CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in));
+  CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in));
+  CHECK_EQ(test.cvt_w_s_out, std::numeric_limits<int32_t>::max());
+  CHECK_EQ(test.cvt_w_d_out, std::numeric_limits<int32_t>::max());
+
+
+  test.cvt_d_s_in = std::numeric_limits<float>::lowest();
+  test.cvt_d_w_in = std::numeric_limits<int32_t>::lowest();
+  test.cvt_d_l_in = std::numeric_limits<int64_t>::lowest();
+  test.cvt_l_s_in = std::numeric_limits<float>::lowest();
+  test.cvt_l_d_in = std::numeric_limits<double>::lowest();
+  test.cvt_s_d_in = std::numeric_limits<double>::lowest();
+  test.cvt_s_w_in = std::numeric_limits<int32_t>::lowest();
+  test.cvt_s_l_in = std::numeric_limits<int64_t>::lowest();
+  test.cvt_w_s_in = std::numeric_limits<float>::lowest();
+  test.cvt_w_d_in = std::numeric_limits<double>::lowest();
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in));
+  CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in));
+  CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in));
+  // The returned value when converting from fixed-point to float-point
+  // is not consistent between board, simulator and specification
+  // in this test case, therefore modifying the test
+  CHECK(test.cvt_l_s_out == std::numeric_limits<int64_t>::min() ||
+       test.cvt_l_s_out == std::numeric_limits<int64_t>::max());
+  CHECK(test.cvt_l_d_out == std::numeric_limits<int64_t>::min() ||
+        test.cvt_l_d_out == std::numeric_limits<int64_t>::max());
+  CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in));
+  CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in));
+  CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in));
+  CHECK(test.cvt_w_s_out == std::numeric_limits<int32_t>::min() ||
+        test.cvt_w_s_out == std::numeric_limits<int32_t>::max());
+  CHECK(test.cvt_w_d_out == std::numeric_limits<int32_t>::min() ||
+        test.cvt_w_d_out == std::numeric_limits<int32_t>::max());
+
+
+  test.cvt_d_s_in = std::numeric_limits<float>::min();
+  test.cvt_d_w_in = std::numeric_limits<int32_t>::min();
+  test.cvt_d_l_in = std::numeric_limits<int64_t>::min();
+  test.cvt_l_s_in = std::numeric_limits<float>::min();
+  test.cvt_l_d_in = std::numeric_limits<double>::min();
+  test.cvt_s_d_in = std::numeric_limits<double>::min();
+  test.cvt_s_w_in = std::numeric_limits<int32_t>::min();
+  test.cvt_s_l_in = std::numeric_limits<int64_t>::min();
+  test.cvt_w_s_in = std::numeric_limits<float>::min();
+  test.cvt_w_d_in = std::numeric_limits<double>::min();
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in));
+  CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in));
+  CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in));
+  CHECK_EQ(test.cvt_l_s_out, 0);
+  CHECK_EQ(test.cvt_l_d_out, 0);
+  CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in));
+  CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in));
+  CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in));
+  CHECK_EQ(test.cvt_w_s_out, 0);
+  CHECK_EQ(test.cvt_w_d_out, 0);
+}
+
+
+TEST(DIV_FMT) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  MacroAssembler assm(isolate, NULL, 0);
+
+  typedef struct test {
+    double dOp1;
+    double dOp2;
+    double dRes;
+    float  fOp1;
+    float  fOp2;
+    float  fRes;
+  } Test;
+
+  Test test;
+
+  // Save FCSR.
+  __ cfc1(a1, FCSR);
+  // Disable FPU exceptions.
+  __ ctc1(zero_reg, FCSR);
+
+  __ ldc1(f4, MemOperand(a0, OFFSET_OF(Test, dOp1)) );
+  __ ldc1(f2, MemOperand(a0, OFFSET_OF(Test, dOp2)) );
+  __ nop();
+  __ div_d(f6, f4, f2);
+  __ sdc1(f6, MemOperand(a0, OFFSET_OF(Test, dRes)) );
+
+  __ lwc1(f4, MemOperand(a0, OFFSET_OF(Test, fOp1)) );
+  __ lwc1(f2, MemOperand(a0, OFFSET_OF(Test, fOp2)) );
+  __ nop();
+  __ div_s(f6, f4, f2);
+  __ swc1(f6, MemOperand(a0, OFFSET_OF(Test, fRes)) );
+
+    // Restore FCSR.
+  __ ctc1(a1, FCSR);
+
+  __ jr(ra);
+  __ nop();
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+
+  const int test_size = 3;
+
+  double dOp1[test_size] = {
+    5.0,
+    DBL_MAX,
+    DBL_MAX,
+  };
+  double dOp2[test_size] = {
+    2.0,
+    2.0,
+    -DBL_MAX,
+  };
+  double dRes[test_size] = {
+    2.5,
+    DBL_MAX / 2.0,
+    -1.0,
+  };
+  float fOp1[test_size] = {
+    5.0,
+    FLT_MAX,
+    FLT_MAX,
+  };
+  float fOp2[test_size] = {
+    2.0,
+    2.0,
+    -FLT_MAX,
+  };
+  float fRes[test_size] = {
+    2.5,
+    FLT_MAX / 2.0,
+    -1.0,
+  };
+
+  for (int i = 0; i < test_size; i++) {
+    test.dOp1 = dOp1[i];
+    test.dOp2 = dOp2[i];
+    test.fOp1 = fOp1[i];
+    test.fOp2 = fOp2[i];
+
+    (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+    CHECK_EQ(test.dRes, dRes[i]);
+    CHECK_EQ(test.fRes, fRes[i]);
+  }
+
+  test.dOp1 = DBL_MAX;
+  test.dOp2 = -0.0;
+  test.fOp1 = FLT_MAX;
+  test.fOp2 = -0.0;
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(false, std::isfinite(test.dRes));
+  CHECK_EQ(false, std::isfinite(test.fRes));
+
+  test.dOp1 = 0.0;
+  test.dOp2 = -0.0;
+  test.fOp1 = 0.0;
+  test.fOp2 = -0.0;
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(true, std::isnan(test.dRes));
+  CHECK_EQ(true, std::isnan(test.fRes));
+
+  test.dOp1 = std::numeric_limits<double>::quiet_NaN();
+  test.dOp2 = -5.0;
+  test.fOp1 = std::numeric_limits<float>::quiet_NaN();
+  test.fOp2 = -5.0;
+
+  (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
+  CHECK_EQ(true, std::isnan(test.dRes));
+  CHECK_EQ(true, std::isnan(test.fRes));
+}
+
+
 #undef __
index 92adfa5e9e0675465d5768689ea58784ef045177..a60d144109390df3f9bdb2eacb67bdd86a6a578a 100644 (file)
@@ -520,6 +520,19 @@ TEST(Type0) {
     COMPARE(ext_(v0, v1, 0, 32),
             "7c62f800       ext     v0, v1, 0, 32");
   }
+  COMPARE(add_s(f4, f6, f8), "46083100       add.s   f4, f6, f8");
+  COMPARE(add_d(f12, f14, f16), "46307300       add.d   f12, f14, f16");
+
+  if (IsMipsArchVariant(kMips32r6)) {
+    COMPARE(bitswap(a0, a1), "7c052020       bitswap a0, a1");
+    COMPARE(bitswap(t8, s0), "7c10c020       bitswap t8, s0");
+  }
+
+  COMPARE(abs_s(f6, f8), "46004185       abs.s   f6, f8");
+  COMPARE(abs_d(f10, f12), "46206285       abs.d   f10, f12");
+
+  COMPARE(div_s(f2, f4, f6), "46062083       div.s   f2, f4, f6");
+  COMPARE(div_d(f2, f4, f6), "46262083       div.d   f2, f4, f6");
 
   VERIFY_RUN();
 }
@@ -616,3 +629,116 @@ TEST(Type1) {
   }
   VERIFY_RUN();
 }
+
+
+TEST(Type2) {
+  if (IsMipsArchVariant(kMips32r6)) {
+    SET_UP();
+
+    COMPARE(class_s(f3, f4), "460020db       class.s f3, f4");
+    COMPARE(class_d(f2, f3), "4620189b       class.d f2, f3");
+
+    VERIFY_RUN();
+  }
+}
+
+
+TEST(C_FMT_DISASM) {
+  if (IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2)) {
+    SET_UP();
+
+    COMPARE(c_s(F, f8, f10, 0), "460a4030       c.f.s   f8, f10, cc(0)");
+    COMPARE(c_d(F, f8, f10, 0), "462a4030       c.f.d   f8, f10, cc(0)");
+
+    COMPARE(c_s(UN, f8, f10, 2), "460a4231       c.un.s  f8, f10, cc(2)");
+    COMPARE(c_d(UN, f8, f10, 2), "462a4231       c.un.d  f8, f10, cc(2)");
+
+    COMPARE(c_s(EQ, f8, f10, 4), "460a4432       c.eq.s  f8, f10, cc(4)");
+    COMPARE(c_d(EQ, f8, f10, 4), "462a4432       c.eq.d  f8, f10, cc(4)");
+
+    COMPARE(c_s(UEQ, f8, f10, 6), "460a4633       c.ueq.s f8, f10, cc(6)");
+    COMPARE(c_d(UEQ, f8, f10, 6), "462a4633       c.ueq.d f8, f10, cc(6)");
+
+    COMPARE(c_s(OLT, f8, f10, 0), "460a4034       c.olt.s f8, f10, cc(0)");
+    COMPARE(c_d(OLT, f8, f10, 0), "462a4034       c.olt.d f8, f10, cc(0)");
+
+    COMPARE(c_s(ULT, f8, f10, 2), "460a4235       c.ult.s f8, f10, cc(2)");
+    COMPARE(c_d(ULT, f8, f10, 2), "462a4235       c.ult.d f8, f10, cc(2)");
+
+    COMPARE(c_s(OLE, f8, f10, 4), "460a4436       c.ole.s f8, f10, cc(4)");
+    COMPARE(c_d(OLE, f8, f10, 4), "462a4436       c.ole.d f8, f10, cc(4)");
+
+    COMPARE(c_s(ULE, f8, f10, 6), "460a4637       c.ule.s f8, f10, cc(6)");
+    COMPARE(c_d(ULE, f8, f10, 6), "462a4637       c.ule.d f8, f10, cc(6)");
+
+    VERIFY_RUN();
+  }
+}
+
+
+TEST(COND_FMT_DISASM) {
+  if (IsMipsArchVariant(kMips32r6)) {
+    SET_UP();
+
+    COMPARE(cmp_s(F, f6, f8, f10), "468a4180       cmp.af.s    f6, f8, f10");
+    COMPARE(cmp_d(F, f6, f8, f10), "46aa4180       cmp.af.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(UN, f6, f8, f10), "468a4181       cmp.un.s    f6, f8, f10");
+    COMPARE(cmp_d(UN, f6, f8, f10), "46aa4181       cmp.un.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(EQ, f6, f8, f10), "468a4182       cmp.eq.s    f6, f8, f10");
+    COMPARE(cmp_d(EQ, f6, f8, f10), "46aa4182       cmp.eq.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(UEQ, f6, f8, f10), "468a4183       cmp.ueq.s   f6, f8, f10");
+    COMPARE(cmp_d(UEQ, f6, f8, f10), "46aa4183       cmp.ueq.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(LT, f6, f8, f10), "468a4184       cmp.lt.s    f6, f8, f10");
+    COMPARE(cmp_d(LT, f6, f8, f10), "46aa4184       cmp.lt.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(ULT, f6, f8, f10), "468a4185       cmp.ult.s   f6, f8, f10");
+    COMPARE(cmp_d(ULT, f6, f8, f10), "46aa4185       cmp.ult.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(LE, f6, f8, f10), "468a4186       cmp.le.s    f6, f8, f10");
+    COMPARE(cmp_d(LE, f6, f8, f10), "46aa4186       cmp.le.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(ULE, f6, f8, f10), "468a4187       cmp.ule.s   f6, f8, f10");
+    COMPARE(cmp_d(ULE, f6, f8, f10), "46aa4187       cmp.ule.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(ORD, f6, f8, f10), "468a4191       cmp.or.s    f6, f8, f10");
+    COMPARE(cmp_d(ORD, f6, f8, f10), "46aa4191       cmp.or.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(UNE, f6, f8, f10), "468a4192       cmp.une.s   f6, f8, f10");
+    COMPARE(cmp_d(UNE, f6, f8, f10), "46aa4192       cmp.une.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(NE, f6, f8, f10), "468a4193       cmp.ne.s    f6, f8, f10");
+    COMPARE(cmp_d(NE, f6, f8, f10), "46aa4193       cmp.ne.d  f6,  f8, f10");
+
+    VERIFY_RUN();
+  }
+}
+
+
+TEST(CVT_DISSASM) {
+  SET_UP();
+  COMPARE(cvt_d_s(f22, f24), "4600c5a1       cvt.d.s f22, f24");
+  COMPARE(cvt_d_w(f22, f24), "4680c5a1       cvt.d.w f22, f24");
+  if (IsMipsArchVariant(kMips32r6) || IsMipsArchVariant(kMips32r2)) {
+    COMPARE(cvt_d_l(f22, f24), "46a0c5a1       cvt.d.l f22, f24");
+  }
+
+  if (IsMipsArchVariant(kMips32r6) || IsMipsArchVariant(kMips32r2)) {
+    COMPARE(cvt_l_s(f22, f24), "4600c5a5       cvt.l.s f22, f24");
+    COMPARE(cvt_l_d(f22, f24), "4620c5a5       cvt.l.d f22, f24");
+  }
+
+  COMPARE(cvt_s_d(f22, f24), "4620c5a0       cvt.s.d f22, f24");
+  COMPARE(cvt_s_w(f22, f24), "4680c5a0       cvt.s.w f22, f24");
+  if (IsMipsArchVariant(kMips32r6) || IsMipsArchVariant(kMips32r2)) {
+    COMPARE(cvt_s_l(f22, f24), "46a0c5a0       cvt.s.l f22, f24");
+  }
+
+  COMPARE(cvt_s_d(f22, f24), "4620c5a0       cvt.s.d f22, f24");
+  COMPARE(cvt_s_w(f22, f24), "4680c5a0       cvt.s.w f22, f24");
+
+  VERIFY_RUN();
+}
index adb9aa6be981cdbe806dcc29ea386d8f591eb88a..4d0b44024ca65777cebc1e8f532f3e4288b10258 100644 (file)
@@ -669,6 +669,22 @@ TEST(Type0) {
   COMPARE(ext_(v0, v1, 0, 32),
           "7c62f800       ext     v0, v1, 0, 32");
 
+  COMPARE(add_s(f4, f6, f8), "46083100       add.s   f4, f6, f8");
+  COMPARE(add_d(f12, f14, f16), "46307300       add.d   f12, f14, f16");
+
+  if (kArchVariant == kMips64r6) {
+    COMPARE(bitswap(a0, a1), "7c052020       bitswap a0, a1");
+    COMPARE(bitswap(t8, s0), "7c10c020       bitswap t8, s0");
+    COMPARE(dbitswap(a0, a1), "7c052024       dbitswap a0, a1");
+    COMPARE(dbitswap(t8, s0), "7c10c024       dbitswap t8, s0");
+  }
+
+  COMPARE(abs_s(f6, f8), "46004185       abs.s   f6, f8");
+  COMPARE(abs_d(f10, f12), "46206285       abs.d   f10, f12");
+
+  COMPARE(div_s(f2, f4, f6), "46062083       div.s   f2, f4, f6");
+  COMPARE(div_d(f2, f4, f6), "46262083       div.d   f2, f4, f6");
+
   VERIFY_RUN();
 }
 
@@ -763,3 +779,116 @@ TEST(Type1) {
   }
   VERIFY_RUN();
 }
+
+
+TEST(Type2) {
+  if (kArchVariant == kMips64r6) {
+    SET_UP();
+
+    COMPARE(class_s(f3, f4), "460020db       class.s f3, f4");
+    COMPARE(class_d(f2, f3), "4620189b       class.d f2, f3");
+
+    VERIFY_RUN();
+  }
+}
+
+
+TEST(C_FMT_DISASM) {
+  if (kArchVariant == kMips64r2) {
+    SET_UP();
+
+    COMPARE(c_s(F, f8, f10, 0), "460a4030       c.f.s   f8, f10, cc(0)");
+    COMPARE(c_d(F, f8, f10, 0), "462a4030       c.f.d   f8, f10, cc(0)");
+
+    COMPARE(c_s(UN, f8, f10, 2), "460a4231       c.un.s  f8, f10, cc(2)");
+    COMPARE(c_d(UN, f8, f10, 2), "462a4231       c.un.d  f8, f10, cc(2)");
+
+    COMPARE(c_s(EQ, f8, f10, 4), "460a4432       c.eq.s  f8, f10, cc(4)");
+    COMPARE(c_d(EQ, f8, f10, 4), "462a4432       c.eq.d  f8, f10, cc(4)");
+
+    COMPARE(c_s(UEQ, f8, f10, 6), "460a4633       c.ueq.s f8, f10, cc(6)");
+    COMPARE(c_d(UEQ, f8, f10, 6), "462a4633       c.ueq.d f8, f10, cc(6)");
+
+    COMPARE(c_s(OLT, f8, f10, 0), "460a4034       c.olt.s f8, f10, cc(0)");
+    COMPARE(c_d(OLT, f8, f10, 0), "462a4034       c.olt.d f8, f10, cc(0)");
+
+    COMPARE(c_s(ULT, f8, f10, 2), "460a4235       c.ult.s f8, f10, cc(2)");
+    COMPARE(c_d(ULT, f8, f10, 2), "462a4235       c.ult.d f8, f10, cc(2)");
+
+    COMPARE(c_s(OLE, f8, f10, 4), "460a4436       c.ole.s f8, f10, cc(4)");
+    COMPARE(c_d(OLE, f8, f10, 4), "462a4436       c.ole.d f8, f10, cc(4)");
+
+    COMPARE(c_s(ULE, f8, f10, 6), "460a4637       c.ule.s f8, f10, cc(6)");
+    COMPARE(c_d(ULE, f8, f10, 6), "462a4637       c.ule.d f8, f10, cc(6)");
+
+    VERIFY_RUN();
+  }
+}
+
+
+TEST(COND_FMT_DISASM) {
+  if (kArchVariant == kMips64r6) {
+    SET_UP();
+
+    COMPARE(cmp_s(F, f6, f8, f10), "468a4180       cmp.af.s    f6, f8, f10");
+    COMPARE(cmp_d(F, f6, f8, f10), "46aa4180       cmp.af.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(UN, f6, f8, f10), "468a4181       cmp.un.s    f6, f8, f10");
+    COMPARE(cmp_d(UN, f6, f8, f10), "46aa4181       cmp.un.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(EQ, f6, f8, f10), "468a4182       cmp.eq.s    f6, f8, f10");
+    COMPARE(cmp_d(EQ, f6, f8, f10), "46aa4182       cmp.eq.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(UEQ, f6, f8, f10), "468a4183       cmp.ueq.s   f6, f8, f10");
+    COMPARE(cmp_d(UEQ, f6, f8, f10), "46aa4183       cmp.ueq.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(LT, f6, f8, f10), "468a4184       cmp.lt.s    f6, f8, f10");
+    COMPARE(cmp_d(LT, f6, f8, f10), "46aa4184       cmp.lt.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(ULT, f6, f8, f10), "468a4185       cmp.ult.s   f6, f8, f10");
+    COMPARE(cmp_d(ULT, f6, f8, f10), "46aa4185       cmp.ult.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(LE, f6, f8, f10), "468a4186       cmp.le.s    f6, f8, f10");
+    COMPARE(cmp_d(LE, f6, f8, f10), "46aa4186       cmp.le.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(ULE, f6, f8, f10), "468a4187       cmp.ule.s   f6, f8, f10");
+    COMPARE(cmp_d(ULE, f6, f8, f10), "46aa4187       cmp.ule.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(ORD, f6, f8, f10), "468a4191       cmp.or.s    f6, f8, f10");
+    COMPARE(cmp_d(ORD, f6, f8, f10), "46aa4191       cmp.or.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(UNE, f6, f8, f10), "468a4192       cmp.une.s   f6, f8, f10");
+    COMPARE(cmp_d(UNE, f6, f8, f10), "46aa4192       cmp.une.d  f6,  f8, f10");
+
+    COMPARE(cmp_s(NE, f6, f8, f10), "468a4193       cmp.ne.s    f6, f8, f10");
+    COMPARE(cmp_d(NE, f6, f8, f10), "46aa4193       cmp.ne.d  f6,  f8, f10");
+
+    VERIFY_RUN();
+  }
+}
+
+
+TEST(CVT_DISSASM) {
+  SET_UP();
+  COMPARE(cvt_d_s(f22, f24), "4600c5a1       cvt.d.s f22, f24");
+  COMPARE(cvt_d_w(f22, f24), "4680c5a1       cvt.d.w f22, f24");
+  if (kArchVariant == kMips64r6 || kArchVariant == kMips64r2) {
+    COMPARE(cvt_d_l(f22, f24), "46a0c5a1       cvt.d.l f22, f24");
+  }
+
+  if (kArchVariant == kMips64r6 || kArchVariant == kMips64r2) {
+    COMPARE(cvt_l_s(f22, f24), "4600c5a5       cvt.l.s f22, f24");
+    COMPARE(cvt_l_d(f22, f24), "4620c5a5       cvt.l.d f22, f24");
+  }
+
+  COMPARE(cvt_s_d(f22, f24), "4620c5a0       cvt.s.d f22, f24");
+  COMPARE(cvt_s_w(f22, f24), "4680c5a0       cvt.s.w f22, f24");
+  if (kArchVariant == kMips64r6 || kArchVariant == kMips64r2) {
+    COMPARE(cvt_s_l(f22, f24), "46a0c5a0       cvt.s.l f22, f24");
+  }
+
+  COMPARE(cvt_s_d(f22, f24), "4620c5a0       cvt.s.d f22, f24");
+  COMPARE(cvt_s_w(f22, f24), "4680c5a0       cvt.s.w f22, f24");
+
+  VERIFY_RUN();
+}