Index: src/ppc/simulator-ppc.cc |
diff --git a/src/ppc/simulator-ppc.cc b/src/ppc/simulator-ppc.cc |
index b3c8a176ec922bc30716bafd21f4caf0209bee0e..8de58f31aede7b053fd265894abec6f6a8641bd1 100644 |
--- a/src/ppc/simulator-ppc.cc |
+++ b/src/ppc/simulator-ppc.cc |
@@ -2908,119 +2908,91 @@ void Simulator::ExecuteExt4(Instruction* instr) { |
set_d_register_from_double(frt, frt_val); |
return; |
} |
- case FCTID: { |
+ case FCTID: |
+ case FCTIDZ: { |
int frt = instr->RTValue(); |
int frb = instr->RBValue(); |
double frb_val = get_double_from_d_register(frb); |
+ int mode = (opcode == FCTIDZ) ? kRoundToZero |
+ : (fp_condition_reg_ & kFPRoundingModeMask); |
int64_t frt_val; |
int64_t one = 1; // work-around gcc |
- int64_t kMinLongLong = (one << 63); |
- int64_t kMaxLongLong = kMinLongLong - 1; |
+ int64_t kMinVal = (one << 63); |
+ int64_t kMaxVal = kMinVal - 1; |
bool invalid_convert = false; |
- if (std::isnan(frb_val) || frb_val < kMinLongLong) { |
- frt_val = kMinLongLong; |
- invalid_convert = true; |
- } else if (frb_val > kMaxLongLong) { |
- frt_val = kMaxLongLong; |
+ if (std::isnan(frb_val)) { |
+ frt_val = kMinVal; |
invalid_convert = true; |
} else { |
- switch (fp_condition_reg_ & kFPRoundingModeMask) { |
+ switch (mode) { |
case kRoundToZero: |
- frt_val = (int64_t)frb_val; |
+ frb_val = std::trunc(frb_val); |
break; |
case kRoundToPlusInf: |
- frt_val = (int64_t)std::ceil(frb_val); |
+ frb_val = std::ceil(frb_val); |
break; |
case kRoundToMinusInf: |
- frt_val = (int64_t)std::floor(frb_val); |
+ frb_val = std::floor(frb_val); |
break; |
default: |
- frt_val = (int64_t)frb_val; |
UNIMPLEMENTED(); // Not used by V8. |
break; |
} |
+ if (frb_val < static_cast<double>(kMinVal)) { |
+ frt_val = kMinVal; |
+ invalid_convert = true; |
+ } else if (frb_val >= static_cast<double>(kMaxVal)) { |
+ frt_val = kMaxVal; |
+ invalid_convert = true; |
+ } else { |
+ frt_val = (int64_t)frb_val; |
+ } |
} |
set_d_register(frt, frt_val); |
if (invalid_convert) SetFPSCR(VXCVI); |
return; |
} |
- case FCTIDZ: { |
- int frt = instr->RTValue(); |
- int frb = instr->RBValue(); |
- double frb_val = get_double_from_d_register(frb); |
- int64_t frt_val; |
- int64_t one = 1; // work-around gcc |
- int64_t kMinLongLong = (one << 63); |
- int64_t kMaxLongLong = kMinLongLong - 1; |
- bool invalid_convert = false; |
- |
- if (std::isnan(frb_val) || frb_val < kMinLongLong) { |
- frt_val = kMinLongLong; |
- invalid_convert = true; |
- } else if (frb_val > kMaxLongLong) { |
- frt_val = kMaxLongLong; |
- invalid_convert = true; |
- } else { |
- frt_val = (int64_t)frb_val; |
- } |
- set_d_register(frt, frt_val); |
- if (invalid_convert) SetFPSCR(VXCVI); |
- return; |
- } |
- case FCTIDU: { |
+ case FCTIDU: |
+ case FCTIDUZ: { |
int frt = instr->RTValue(); |
int frb = instr->RBValue(); |
double frb_val = get_double_from_d_register(frb); |
+ int mode = (opcode == FCTIDUZ) |
+ ? kRoundToZero |
+ : (fp_condition_reg_ & kFPRoundingModeMask); |
uint64_t frt_val; |
- uint64_t kMinLongLong = 0; |
- uint64_t kMaxLongLong = kMinLongLong - 1; |
+ uint64_t kMinVal = 0; |
+ uint64_t kMaxVal = kMinVal - 1; |
bool invalid_convert = false; |
- if (std::isnan(frb_val) || frb_val < kMinLongLong) { |
- frt_val = kMinLongLong; |
- invalid_convert = true; |
- } else if (frb_val > kMaxLongLong) { |
- frt_val = kMaxLongLong; |
+ if (std::isnan(frb_val)) { |
+ frt_val = kMinVal; |
invalid_convert = true; |
} else { |
- switch (fp_condition_reg_ & kFPRoundingModeMask) { |
+ switch (mode) { |
case kRoundToZero: |
- frt_val = (uint64_t)frb_val; |
+ frb_val = std::trunc(frb_val); |
break; |
case kRoundToPlusInf: |
- frt_val = (uint64_t)std::ceil(frb_val); |
+ frb_val = std::ceil(frb_val); |
break; |
case kRoundToMinusInf: |
- frt_val = (uint64_t)std::floor(frb_val); |
+ frb_val = std::floor(frb_val); |
break; |
default: |
- frt_val = (uint64_t)frb_val; |
UNIMPLEMENTED(); // Not used by V8. |
break; |
} |
- } |
- set_d_register(frt, frt_val); |
- if (invalid_convert) SetFPSCR(VXCVI); |
- return; |
- } |
- case FCTIDUZ: { |
- int frt = instr->RTValue(); |
- int frb = instr->RBValue(); |
- double frb_val = get_double_from_d_register(frb); |
- uint64_t frt_val; |
- uint64_t kMinLongLong = 0; |
- uint64_t kMaxLongLong = kMinLongLong - 1; |
- bool invalid_convert = false; |
- |
- if (std::isnan(frb_val) || frb_val < kMinLongLong) { |
- frt_val = kMinLongLong; |
- invalid_convert = true; |
- } else if (frb_val > kMaxLongLong) { |
- frt_val = kMaxLongLong; |
- invalid_convert = true; |
- } else { |
- frt_val = (uint64_t)frb_val; |
+ if (frb_val < static_cast<double>(kMinVal)) { |
+ frt_val = kMinVal; |
+ invalid_convert = true; |
+ } else if (frb_val >= static_cast<double>(kMaxVal)) { |
+ frt_val = kMaxVal; |
+ invalid_convert = true; |
+ } else { |
+ frt_val = (uint64_t)frb_val; |
+ } |
} |
set_d_register(frt, frt_val); |
if (invalid_convert) SetFPSCR(VXCVI); |
@@ -3031,40 +3003,44 @@ void Simulator::ExecuteExt4(Instruction* instr) { |
int frt = instr->RTValue(); |
int frb = instr->RBValue(); |
double frb_val = get_double_from_d_register(frb); |
+ int mode = (opcode == FCTIWZ) ? kRoundToZero |
+ : (fp_condition_reg_ & kFPRoundingModeMask); |
int64_t frt_val; |
- if (frb_val > kMaxInt) { |
- frt_val = kMaxInt; |
- } else if (frb_val < kMinInt) { |
- frt_val = kMinInt; |
- } else { |
- if (opcode == FCTIWZ) { |
- frt_val = (int64_t)frb_val; |
- } else { |
- switch (fp_condition_reg_ & kFPRoundingModeMask) { |
- case kRoundToZero: |
- frt_val = (int64_t)frb_val; |
- break; |
- case kRoundToPlusInf: |
- frt_val = (int64_t)std::ceil(frb_val); |
- break; |
- case kRoundToMinusInf: |
- frt_val = (int64_t)std::floor(frb_val); |
- break; |
- case kRoundToNearest: |
- frt_val = (int64_t)lround(frb_val); |
- |
- // Round to even if exactly halfway. (lround rounds up) |
- if (std::fabs(static_cast<double>(frt_val) - frb_val) == 0.5 && |
- (frt_val % 2)) { |
- frt_val += ((frt_val > 0) ? -1 : 1); |
- } |
+ int64_t kMinVal = kMinInt; |
+ int64_t kMaxVal = kMaxInt; |
- break; |
- default: |
- DCHECK(false); |
- frt_val = (int64_t)frb_val; |
- break; |
+ if (std::isnan(frb_val)) { |
+ frt_val = kMinVal; |
+ } else { |
+ switch (mode) { |
+ case kRoundToZero: |
+ frb_val = std::trunc(frb_val); |
+ break; |
+ case kRoundToPlusInf: |
+ frb_val = std::ceil(frb_val); |
+ break; |
+ case kRoundToMinusInf: |
+ frb_val = std::floor(frb_val); |
+ break; |
+ case kRoundToNearest: { |
+ double orig = frb_val; |
+ frb_val = lround(frb_val); |
+ // Round to even if exactly halfway. (lround rounds up) |
+ if (std::fabs(frb_val - orig) == 0.5 && ((int64_t)frb_val % 2)) { |
+ frb_val += ((frb_val > 0) ? -1.0 : 1.0); |
+ } |
+ break; |
} |
+ default: |
+ UNIMPLEMENTED(); // Not used by V8. |
+ break; |
+ } |
+ if (frb_val < kMinVal) { |
+ frt_val = kMinVal; |
+ } else if (frb_val > kMaxVal) { |
+ frt_val = kMaxVal; |
+ } else { |
+ frt_val = (int64_t)frb_val; |
} |
} |
set_d_register(frt, frt_val); |