[mips][turbofan] Fix CheckedFloat64ToInt64 on mips64

This CL applies kSetOverflowToMin in TruncateFloat32ToInt32,
TruncateFloat32ToUint32, and TruncateFloat64ToInt64, allowing
EffectControlLinearizer to request truncating to INT32_MIN
or INT64_MIN in case of overflow.

Port: d4b29d7525

Bug: v8:11121

Change-Id: I1ef794e89641d0be6e9be9bdb99fd7737f465821
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2537417
Reviewed-by: Zhao Jiazhong <zhaojiazhong-hf@loongson.cn>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Auto-Submit: Liu yu <liuyu@loongson.cn>
Cr-Commit-Position: refs/heads/master@{#71516}
This commit is contained in:
Liu Yu 2020-11-30 14:14:59 +08:00 committed by Commit Bot
parent 6056b085b2
commit 61741d6295
6 changed files with 78 additions and 25 deletions

View File

@ -1501,9 +1501,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ mfc1(i.OutputRegister(), scratch);
// Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
// because INT32_MIN allows easier out-of-bounds detection.
bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
if (set_overflow_to_min_i32) {
__ Addu(kScratchReg, i.OutputRegister(), 1);
__ Slt(kScratchReg2, kScratchReg, i.OutputRegister());
__ Movn(i.OutputRegister(), kScratchReg, kScratchReg2);
}
break;
}
case kMipsTruncUwD: {
@ -1516,8 +1519,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ Trunc_uw_s(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
// Avoid UINT32_MAX as an overflow indicator and use 0 instead,
// because 0 allows easier out-of-bounds detection.
bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
if (set_overflow_to_min_i32) {
__ Addu(kScratchReg, i.OutputRegister(), 1);
__ Movz(i.OutputRegister(), zero_reg, kScratchReg);
}
break;
}
case kMipsFloat64ExtractLowWord32:

View File

@ -996,11 +996,25 @@ void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
VisitRR(this, kMipsTruncWS, node);
MipsOperandGenerator g(this);
InstructionCode opcode = kMipsTruncWS;
TruncateKind kind = OpParameter<TruncateKind>(node->op());
if (kind == TruncateKind::kSetOverflowToMin) {
opcode |= MiscField::encode(true);
}
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
VisitRR(this, kMipsTruncUwS, node);
MipsOperandGenerator g(this);
InstructionCode opcode = kMipsTruncUwS;
TruncateKind kind = OpParameter<TruncateKind>(node->op());
if (kind == TruncateKind::kSetOverflowToMin) {
opcode |= MiscField::encode(true);
}
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {

View File

@ -1555,13 +1555,16 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kMips64TruncWS: {
FPURegister scratch = kScratchDoubleReg;
bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
__ trunc_w_s(scratch, i.InputDoubleRegister(0));
__ mfc1(i.OutputRegister(), scratch);
if (set_overflow_to_min_i32) {
// Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
// because INT32_MIN allows easier out-of-bounds detection.
__ addiu(kScratchReg, i.OutputRegister(), 1);
__ slt(kScratchReg2, kScratchReg, i.OutputRegister());
__ Movn(i.OutputRegister(), kScratchReg, kScratchReg2);
}
break;
}
case kMips64TruncLS: {
@ -1597,7 +1600,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
Register tmp_fcsr = kScratchReg;
Register result = kScratchReg2;
bool set_overflow_to_min_i64 = MiscField::decode(instr->opcode());
bool load_status = instr->OutputCount() > 1;
DCHECK_IMPLIES(set_overflow_to_min_i64, i.OutputCount() == 1);
if (load_status) {
// Save FCSR.
__ cfc1(tmp_fcsr, FCSR);
@ -1618,6 +1623,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
// Restore FCSR
__ ctc1(tmp_fcsr, FCSR);
}
if (set_overflow_to_min_i64) {
// Avoid INT64_MAX as an overflow indicator and use INT64_MIN instead,
// because INT64_MIN allows easier out-of-bounds detection.
__ Daddu(kScratchReg, i.OutputRegister(), 1);
__ slt(kScratchReg2, kScratchReg, i.OutputRegister());
__ Movn(i.OutputRegister(), kScratchReg, kScratchReg2);
}
break;
}
case kMips64TruncUwD: {
@ -1627,11 +1639,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kMips64TruncUwS: {
FPURegister scratch = kScratchDoubleReg;
bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
__ Trunc_uw_s(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
if (set_overflow_to_min_i32) {
// Avoid UINT32_MAX as an overflow indicator and use 0 instead,
// because 0 allows easier out-of-bounds detection.
__ addiu(kScratchReg, i.OutputRegister(), 1);
__ Movz(i.OutputRegister(), zero_reg, kScratchReg);
}
break;
}
case kMips64TruncUlS: {

View File

@ -1227,11 +1227,23 @@ void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
VisitRR(this, kMips64TruncWS, node);
Mips64OperandGenerator g(this);
InstructionCode opcode = kMips64TruncWS;
TruncateKind kind = OpParameter<TruncateKind>(node->op());
if (kind == TruncateKind::kSetOverflowToMin) {
opcode |= MiscField::encode(true);
}
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
VisitRR(this, kMips64TruncUwS, node);
Mips64OperandGenerator g(this);
InstructionCode opcode = kMips64TruncUwS;
TruncateKind kind = OpParameter<TruncateKind>(node->op());
if (kind == TruncateKind::kSetOverflowToMin) {
opcode |= MiscField::encode(true);
}
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
@ -1314,7 +1326,13 @@ void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) {
}
void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) {
VisitRR(this, kMips64TruncLD, node);
Mips64OperandGenerator g(this);
InstructionCode opcode = kMips64TruncLD;
TruncateKind kind = OpParameter<TruncateKind>(node->op());
if (kind == TruncateKind::kSetOverflowToMin) {
opcode |= MiscField::encode(true);
}
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {

View File

@ -4189,12 +4189,16 @@ TEST(RunTruncateFloat32ToInt32) {
if (i < upper_bound && i >= lower_bound) {
CHECK_FLOAT_EQ(static_cast<int32_t>(i), m.Call(i));
} else if (i < lower_bound) {
#if (V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64) && !_MIPS_ARCH_MIPS32R6 && \
!_MIPS_ARCH_MIPS64R6
CHECK_FLOAT_EQ(std::numeric_limits<int32_t>::max(), m.Call(i));
#else
CHECK_FLOAT_EQ(std::numeric_limits<int32_t>::min(), m.Call(i));
#endif
} else if (i >= upper_bound) {
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
CHECK_FLOAT_EQ(std::numeric_limits<int32_t>::min(), m.Call(i));
#elif V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_S390X || \
V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
#else
CHECK_FLOAT_EQ(std::numeric_limits<int32_t>::max(), m.Call(i));
#endif
} else {

View File

@ -28259,10 +28259,6 @@ TEST(FastApiCalls) {
CallAndCheck<uint64_t>(0, Behavior::kNoException,
expected_path_for_64bit_test, v8_num(-0.0));
// TODO(v8:11121): Currently the tests below are successful only for
// non-mips64 because they fall down the fast path due to incorrect
// behaviour of CheckedFloat64ToInt64 on mips64 (see the
// linked issue for details). Please port the arm64 fix from v8:11121.
// TODO(mslekova): We deopt for unsafe integers, but ultimately we want to
// stay on the fast path.
CallAndCheck<int64_t>(std::numeric_limits<int64_t>::min(),