Index: src/mips64/simulator-mips64.cc |
diff --git a/src/mips64/simulator-mips64.cc b/src/mips64/simulator-mips64.cc |
index 4702e7db44349783c955079b778d3c5b1ca70fde..beabc88e36adc3461de50a09f86768ca203617e3 100644 |
--- a/src/mips64/simulator-mips64.cc |
+++ b/src/mips64/simulator-mips64.cc |
@@ -2332,6 +2332,87 @@ void Simulator::SignalException(Exception e) { |
static_cast<int>(e)); |
} |
+template <typename T> |
+T FPAbs(T a); |
+ |
+template <> |
+double FPAbs<double>(double a) { |
+ return fabs(a); |
+} |
+ |
+template <> |
+float FPAbs<float>(float a) { |
+ return fabsf(a); |
+} |
+ |
+template <typename T> |
+bool Simulator::FPUProcessNaNsAndZeros(T a, T b, IsMin min, T& result) { |
+ if (std::isnan(a) && std::isnan(b)) { |
+ result = a; |
+ } else if (std::isnan(a)) { |
+ result = b; |
+ } else if (std::isnan(b)) { |
+ result = a; |
+ } else if (b == a) { |
+ // Handle -0.0 == 0.0 case. |
+ // std::signbit() returns int 0 or 1 so substracting IsMin::kMax negates the |
+ // result. |
+ result = std::signbit(b) - static_cast<int>(min) ? b : a; |
+ } else { |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+template <typename T> |
+T Simulator::FPUMin(T a, T b) { |
+ T result; |
+ if (FPUProcessNaNsAndZeros(a, b, IsMin::kMin, result)) { |
+ return result; |
+ } else { |
+ return b < a ? b : a; |
+ } |
+} |
+ |
+template <typename T> |
+T Simulator::FPUMax(T a, T b) { |
+ T result; |
+ if (FPUProcessNaNsAndZeros(a, b, IsMin::kMax, result)) { |
+ return result; |
+ } else { |
+ return b > a ? b : a; |
+ } |
+} |
+ |
+template <typename T> |
+T Simulator::FPUMinA(T a, T b) { |
+ T result; |
+ if (!FPUProcessNaNsAndZeros(a, b, IsMin::kMin, result)) { |
+ if (FPAbs(a) < FPAbs(b)) { |
+ result = a; |
+ } else if (FPAbs(b) < FPAbs(a)) { |
+ result = b; |
+ } else { |
+ result = a < b ? a : b; |
+ } |
+ } |
+ return result; |
+} |
+ |
+template <typename T> |
+T Simulator::FPUMaxA(T a, T b) { |
+ T result; |
+ if (!FPUProcessNaNsAndZeros(a, b, IsMin::kMin, result)) { |
+ if (FPAbs(a) > FPAbs(b)) { |
+ result = a; |
+ } else if (FPAbs(b) > FPAbs(a)) { |
+ result = b; |
+ } else { |
+ result = a > b ? a : b; |
+ } |
+ } |
+ return result; |
+} |
// Handle execution based on instruction types. |
@@ -2616,71 +2697,19 @@ void Simulator::DecodeTypeRegisterSRsType() { |
} |
case MINA: |
DCHECK(kArchVariant == kMips64r6); |
- fs = get_fpu_register_float(fs_reg()); |
- if (std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), fs); |
- } else if (std::isnan(fs) && !std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), ft); |
- } else if (!std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), fs); |
- } else { |
- float result; |
- if (fabs(fs) > fabs(ft)) { |
- result = ft; |
- } else if (fabs(fs) < fabs(ft)) { |
- result = fs; |
- } else { |
- result = (fs < ft ? fs : ft); |
- } |
- set_fpu_register_float(fd_reg(), result); |
- } |
+ set_fpu_register_float(fd_reg(), FPUMinA(ft, fs)); |
break; |
case MAXA: |
DCHECK(kArchVariant == kMips64r6); |
- fs = get_fpu_register_float(fs_reg()); |
- if (std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), fs); |
- } else if (std::isnan(fs) && !std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), ft); |
- } else if (!std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), fs); |
- } else { |
- float result; |
- if (fabs(fs) < fabs(ft)) { |
- result = ft; |
- } else if (fabs(fs) > fabs(ft)) { |
- result = fs; |
- } else { |
- result = (fs > ft ? fs : ft); |
- } |
- set_fpu_register_float(fd_reg(), result); |
- } |
+ set_fpu_register_float(fd_reg(), FPUMaxA(ft, fs)); |
break; |
case MIN: |
DCHECK(kArchVariant == kMips64r6); |
- fs = get_fpu_register_float(fs_reg()); |
- if (std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), fs); |
- } else if (std::isnan(fs) && !std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), ft); |
- } else if (!std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), fs); |
- } else { |
- set_fpu_register_float(fd_reg(), (fs >= ft) ? ft : fs); |
- } |
+ set_fpu_register_float(fd_reg(), FPUMin(ft, fs)); |
break; |
case MAX: |
DCHECK(kArchVariant == kMips64r6); |
- fs = get_fpu_register_float(fs_reg()); |
- if (std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), fs); |
- } else if (std::isnan(fs) && !std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), ft); |
- } else if (!std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_float(fd_reg(), fs); |
- } else { |
- set_fpu_register_float(fd_reg(), (fs <= ft) ? ft : fs); |
- } |
+ set_fpu_register_float(fd_reg(), FPUMax(ft, fs)); |
break; |
case SEL: |
DCHECK(kArchVariant == kMips64r6); |
@@ -2825,71 +2854,19 @@ void Simulator::DecodeTypeRegisterDRsType() { |
} |
case MINA: |
DCHECK(kArchVariant == kMips64r6); |
- fs = get_fpu_register_double(fs_reg()); |
- if (std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), fs); |
- } else if (std::isnan(fs) && !std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), ft); |
- } else if (!std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), fs); |
- } else { |
- double result; |
- if (fabs(fs) > fabs(ft)) { |
- result = ft; |
- } else if (fabs(fs) < fabs(ft)) { |
- result = fs; |
- } else { |
- result = (fs < ft ? fs : ft); |
- } |
- set_fpu_register_double(fd_reg(), result); |
- } |
+ set_fpu_register_double(fd_reg(), FPUMinA(ft, fs)); |
break; |
case MAXA: |
DCHECK(kArchVariant == kMips64r6); |
- fs = get_fpu_register_double(fs_reg()); |
- if (std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), fs); |
- } else if (std::isnan(fs) && !std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), ft); |
- } else if (!std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), fs); |
- } else { |
- double result; |
- if (fabs(fs) < fabs(ft)) { |
- result = ft; |
- } else if (fabs(fs) > fabs(ft)) { |
- result = fs; |
- } else { |
- result = (fs > ft ? fs : ft); |
- } |
- set_fpu_register_double(fd_reg(), result); |
- } |
+ set_fpu_register_double(fd_reg(), FPUMaxA(ft, fs)); |
break; |
case MIN: |
DCHECK(kArchVariant == kMips64r6); |
- fs = get_fpu_register_double(fs_reg()); |
- if (std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), fs); |
- } else if (std::isnan(fs) && !std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), ft); |
- } else if (!std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), fs); |
- } else { |
- set_fpu_register_double(fd_reg(), (fs >= ft) ? ft : fs); |
- } |
+ set_fpu_register_double(fd_reg(), FPUMin(ft, fs)); |
break; |
case MAX: |
DCHECK(kArchVariant == kMips64r6); |
- fs = get_fpu_register_double(fs_reg()); |
- if (std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), fs); |
- } else if (std::isnan(fs) && !std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), ft); |
- } else if (!std::isnan(fs) && std::isnan(ft)) { |
- set_fpu_register_double(fd_reg(), fs); |
- } else { |
- set_fpu_register_double(fd_reg(), (fs <= ft) ? ft : fs); |
- } |
+ set_fpu_register_double(fd_reg(), FPUMax(ft, fs)); |
break; |
case ADD_D: |
set_fpu_register_double(fd_reg(), fs + ft); |