Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(826)

Unified Diff: src/mips64/simulator-mips64.cc

Issue 1145223002: MIPS: Add float instructions and test coverage, part two (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Addressed comments Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/mips64/simulator-mips64.h ('k') | test/cctest/test-assembler-mips.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/mips64/simulator-mips64.cc
diff --git a/src/mips64/simulator-mips64.cc b/src/mips64/simulator-mips64.cc
index 4298ca0e16cda9f61e8a10293278a910c2f0cea8..4b251f2b2fa037cbcbebe72d658bfde9ec66e18e 100644
--- a/src/mips64/simulator-mips64.cc
+++ b/src/mips64/simulator-mips64.cc
@@ -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
« no previous file with comments | « src/mips64/simulator-mips64.h ('k') | test/cctest/test-assembler-mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698