Commit 51b53dd3 authored by Richard Stotz's avatar Richard Stotz Committed by Commit Bot

[turbofan][wasm][arm] Improved saturated conversions float32 to int32.

Bug: v8:10720
Change-Id: I7a05bfb3c87c4f0f5516608da5d42fdaff466536
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2304572
Commit-Queue: Richard Stotz <rstz@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69001}
parent a6f31733
......@@ -1566,10 +1566,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
SwVfpRegister scratch = temps.AcquireS();
__ vcvt_s32_f32(scratch, i.InputFloatRegister(0));
__ vmov(i.OutputRegister(), scratch);
// Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
// because INT32_MIN allows easier out-of-bounds detection.
__ cmn(i.OutputRegister(), Operand(1));
__ mov(i.OutputRegister(), Operand(INT32_MIN), SBit::LeaveCC, vs);
bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
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.
__ cmn(i.OutputRegister(), Operand(1));
__ mov(i.OutputRegister(), Operand(INT32_MIN), SBit::LeaveCC, vs);
}
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
......@@ -1578,10 +1581,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
SwVfpRegister scratch = temps.AcquireS();
__ vcvt_u32_f32(scratch, i.InputFloatRegister(0));
__ vmov(i.OutputRegister(), scratch);
// Avoid UINT32_MAX as an overflow indicator and use 0 instead,
// because 0 allows easier out-of-bounds detection.
__ cmn(i.OutputRegister(), Operand(1));
__ adc(i.OutputRegister(), i.OutputRegister(), Operand::Zero());
bool set_overflow_to_min_u32 = MiscField::decode(instr->opcode());
if (set_overflow_to_min_u32) {
// Avoid UINT32_MAX as an overflow indicator and use 0 instead,
// because 0 allows easier out-of-bounds detection.
__ cmn(i.OutputRegister(), Operand(1));
__ adc(i.OutputRegister(), i.OutputRegister(), Operand::Zero());
}
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
......
......@@ -1471,8 +1471,6 @@ void InstructionSelector::VisitUint32Mod(Node* node) {
V(RoundUint32ToFloat32, kArmVcvtF32U32) \
V(ChangeInt32ToFloat64, kArmVcvtF64S32) \
V(ChangeUint32ToFloat64, kArmVcvtF64U32) \
V(TruncateFloat32ToInt32, kArmVcvtS32F32) \
V(TruncateFloat32ToUint32, kArmVcvtU32F32) \
V(ChangeFloat64ToInt32, kArmVcvtS32F64) \
V(ChangeFloat64ToUint32, kArmVcvtU32F64) \
V(TruncateFloat64ToUint32, kArmVcvtU32F64) \
......@@ -3017,6 +3015,30 @@ void InstructionSelector::VisitF64x2Pmax(Node* node) {
VisitF64x2PminOrPMax(this, kArmF64x2Pmax, node);
}
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
ArmOperandGenerator g(this);
InstructionCode opcode = kArmVcvtS32F32;
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) {
ArmOperandGenerator g(this);
InstructionCode opcode = kArmVcvtU32F32;
TruncateKind kind = OpParameter<TruncateKind>(node->op());
if (kind == TruncateKind::kSetOverflowToMin) {
opcode |= MiscField::encode(true);
}
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......@@ -3041,6 +3063,7 @@ InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::kFloat32RoundTiesEven |
MachineOperatorBuilder::kFloat64RoundTiesEven;
}
flags |= MachineOperatorBuilder::kSatConversionIsSafe;
return flags;
}
......
......@@ -4192,14 +4192,14 @@ TEST(RunTruncateFloat32ToInt32) {
} 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
#elif V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_ARM
CHECK_FLOAT_EQ(std::numeric_limits<int32_t>::max(), m.Call(i));
#endif
} else {
DCHECK(std::isnan(i));
#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
#elif V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_ARM
CHECK_FLOAT_EQ(0, m.Call(i));
#endif
}
......@@ -4218,7 +4218,7 @@ TEST(RunTruncateFloat32ToInt32) {
DCHECK(std::isnan(i));
#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
#elif V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_ARM
CHECK_FLOAT_EQ(0, m.Call(i));
#endif
}
......
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