Commit 5fa2a112 authored by mbrandy's avatar mbrandy Committed by Commit bot

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}
parent efc641a7
...@@ -2908,119 +2908,91 @@ void Simulator::ExecuteExt4(Instruction* instr) { ...@@ -2908,119 +2908,91 @@ void Simulator::ExecuteExt4(Instruction* instr) {
set_d_register_from_double(frt, frt_val); set_d_register_from_double(frt, frt_val);
return; return;
} }
case FCTID: { case FCTID:
case FCTIDZ: {
int frt = instr->RTValue(); int frt = instr->RTValue();
int frb = instr->RBValue(); int frb = instr->RBValue();
double frb_val = get_double_from_d_register(frb); double frb_val = get_double_from_d_register(frb);
int mode = (opcode == FCTIDZ) ? kRoundToZero
: (fp_condition_reg_ & kFPRoundingModeMask);
int64_t frt_val; int64_t frt_val;
int64_t one = 1; // work-around gcc int64_t one = 1; // work-around gcc
int64_t kMinLongLong = (one << 63); int64_t kMinVal = (one << 63);
int64_t kMaxLongLong = kMinLongLong - 1; int64_t kMaxVal = kMinVal - 1;
bool invalid_convert = false; bool invalid_convert = false;
if (std::isnan(frb_val) || frb_val < kMinLongLong) { if (std::isnan(frb_val)) {
frt_val = kMinLongLong; frt_val = kMinVal;
invalid_convert = true;
} else if (frb_val > kMaxLongLong) {
frt_val = kMaxLongLong;
invalid_convert = true; invalid_convert = true;
} else { } else {
switch (fp_condition_reg_ & kFPRoundingModeMask) { switch (mode) {
case kRoundToZero: case kRoundToZero:
frt_val = (int64_t)frb_val; frb_val = std::trunc(frb_val);
break; break;
case kRoundToPlusInf: case kRoundToPlusInf:
frt_val = (int64_t)std::ceil(frb_val); frb_val = std::ceil(frb_val);
break; break;
case kRoundToMinusInf: case kRoundToMinusInf:
frt_val = (int64_t)std::floor(frb_val); frb_val = std::floor(frb_val);
break; break;
default: default:
frt_val = (int64_t)frb_val;
UNIMPLEMENTED(); // Not used by V8. UNIMPLEMENTED(); // Not used by V8.
break; 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); set_d_register(frt, frt_val);
if (invalid_convert) SetFPSCR(VXCVI); if (invalid_convert) SetFPSCR(VXCVI);
return; return;
} }
case FCTIDZ: { case FCTIDU:
int frt = instr->RTValue(); case FCTIDUZ: {
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: {
int frt = instr->RTValue(); int frt = instr->RTValue();
int frb = instr->RBValue(); int frb = instr->RBValue();
double frb_val = get_double_from_d_register(frb); double frb_val = get_double_from_d_register(frb);
int mode = (opcode == FCTIDUZ)
? kRoundToZero
: (fp_condition_reg_ & kFPRoundingModeMask);
uint64_t frt_val; uint64_t frt_val;
uint64_t kMinLongLong = 0; uint64_t kMinVal = 0;
uint64_t kMaxLongLong = kMinLongLong - 1; uint64_t kMaxVal = kMinVal - 1;
bool invalid_convert = false; bool invalid_convert = false;
if (std::isnan(frb_val) || frb_val < kMinLongLong) { if (std::isnan(frb_val)) {
frt_val = kMinLongLong; frt_val = kMinVal;
invalid_convert = true;
} else if (frb_val > kMaxLongLong) {
frt_val = kMaxLongLong;
invalid_convert = true; invalid_convert = true;
} else { } else {
switch (fp_condition_reg_ & kFPRoundingModeMask) { switch (mode) {
case kRoundToZero: case kRoundToZero:
frt_val = (uint64_t)frb_val; frb_val = std::trunc(frb_val);
break; break;
case kRoundToPlusInf: case kRoundToPlusInf:
frt_val = (uint64_t)std::ceil(frb_val); frb_val = std::ceil(frb_val);
break; break;
case kRoundToMinusInf: case kRoundToMinusInf:
frt_val = (uint64_t)std::floor(frb_val); frb_val = std::floor(frb_val);
break; break;
default: default:
frt_val = (uint64_t)frb_val;
UNIMPLEMENTED(); // Not used by V8. UNIMPLEMENTED(); // Not used by V8.
break; break;
} }
} if (frb_val < static_cast<double>(kMinVal)) {
set_d_register(frt, frt_val); frt_val = kMinVal;
if (invalid_convert) SetFPSCR(VXCVI); invalid_convert = true;
return; } else if (frb_val >= static_cast<double>(kMaxVal)) {
} frt_val = kMaxVal;
case FCTIDUZ: { invalid_convert = true;
int frt = instr->RTValue(); } else {
int frb = instr->RBValue(); frt_val = (uint64_t)frb_val;
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;
} }
set_d_register(frt, frt_val); set_d_register(frt, frt_val);
if (invalid_convert) SetFPSCR(VXCVI); if (invalid_convert) SetFPSCR(VXCVI);
...@@ -3031,40 +3003,44 @@ void Simulator::ExecuteExt4(Instruction* instr) { ...@@ -3031,40 +3003,44 @@ void Simulator::ExecuteExt4(Instruction* instr) {
int frt = instr->RTValue(); int frt = instr->RTValue();
int frb = instr->RBValue(); int frb = instr->RBValue();
double frb_val = get_double_from_d_register(frb); double frb_val = get_double_from_d_register(frb);
int mode = (opcode == FCTIWZ) ? kRoundToZero
: (fp_condition_reg_ & kFPRoundingModeMask);
int64_t frt_val; int64_t frt_val;
if (frb_val > kMaxInt) { int64_t kMinVal = kMinInt;
frt_val = kMaxInt; int64_t kMaxVal = 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);
}
break; if (std::isnan(frb_val)) {
default: frt_val = kMinVal;
DCHECK(false); } else {
frt_val = (int64_t)frb_val; switch (mode) {
break; 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); set_d_register(frt, frt_val);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment