PPC: Fix simulator overflow detection for float -> integer conversions.

R=joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=

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

Cr-Commit-Position: refs/heads/master@{#32976}
This commit is contained in:
mbrandy 2015-12-18 12:57:20 -08:00 committed by Commit bot
parent efc641a7be
commit 5fa2a112c2

View File

@ -2908,119 +2908,91 @@ void Simulator::ExecuteExt4(Instruction* instr) {
set_d_register_from_double(frt, frt_val);
return;
}
case FCTID: {
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 {
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;
default:
frt_val = (int64_t)frb_val;
UNIMPLEMENTED(); // Not used by V8.
break;
}
}
set_d_register(frt, frt_val);
if (invalid_convert) SetFPSCR(VXCVI);
return;
}
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 {
frt_val = (int64_t)frb_val;
}
set_d_register(frt, frt_val);
if (invalid_convert) SetFPSCR(VXCVI);
return;
}
case FCTIDU: {
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 {
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;
}
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 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 {
frt_val = (uint64_t)frb_val;
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;
default:
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 = (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;
int64_t kMinVal = kMinInt;
int64_t kMaxVal = kMaxInt;
if (std::isnan(frb_val)) {
frt_val = kMinVal;
} 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);
}
break;
default:
DCHECK(false);
frt_val = (int64_t)frb_val;
break;
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);