[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:
parent
6056b085b2
commit
61741d6295
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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: {
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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(),
|
||||
|
Loading…
Reference in New Issue
Block a user