[turbofan] Add the RoundInt32ToFloat32 operator to turbofan.

The new operator converts an int32 input to float32. If the input cannot
be represented exactly in float32, the value is rounded using the
round-ties-even rounding mode (the default rounding mode).

I provide implementations of the new operator for x64, ia32, arm, arm64,
mips, mips64, ppc, and ppc64.

R=titzer@chromium.org, v8-arm-ports@googlegroups.com, v8-mips-ports@googlegroups.com, v8-ppc-ports@googlegroups.com

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

Cr-Commit-Position: refs/heads/master@{#33347}
This commit is contained in:
ahaas 2016-01-16 05:11:40 -08:00 committed by Commit bot
parent fc53eed14b
commit e06f7d784e
38 changed files with 154 additions and 3 deletions

View File

@ -831,6 +831,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVcvtF32S32: {
SwVfpRegister scratch = kScratchDoubleReg.low();
__ vmov(scratch, i.InputRegister(0));
__ vcvt_f32_s32(i.OutputFloat32Register(), scratch);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVcvtF64S32: {
SwVfpRegister scratch = kScratchDoubleReg.low();
__ vmov(scratch, i.InputRegister(0));

View File

@ -76,6 +76,7 @@ namespace compiler {
V(ArmVrintnF64) \
V(ArmVcvtF32F64) \
V(ArmVcvtF64F32) \
V(ArmVcvtF32S32) \
V(ArmVcvtF64S32) \
V(ArmVcvtF64U32) \
V(ArmVcvtS32F32) \

View File

@ -78,6 +78,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArmVrintnF64:
case kArmVcvtF32F64:
case kArmVcvtF64F32:
case kArmVcvtF32S32:
case kArmVcvtF64S32:
case kArmVcvtF64U32:
case kArmVcvtS32F32:

View File

@ -921,6 +921,11 @@ void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
}
void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
VisitRR(this, kArmVcvtF32S32, node);
}
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
VisitRR(this, kArmVcvtF64S32, node);
}

View File

@ -1096,6 +1096,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ Cset(i.OutputRegister(1), ne);
}
break;
case kArm64Int32ToFloat32:
__ Scvtf(i.OutputFloat32Register(), i.InputRegister32(0));
break;
case kArm64Int32ToFloat64:
__ Scvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
break;

View File

@ -117,6 +117,7 @@ namespace compiler {
V(Arm64Float64ToInt64) \
V(Arm64Float32ToUint64) \
V(Arm64Float64ToUint64) \
V(Arm64Int32ToFloat32) \
V(Arm64Int32ToFloat64) \
V(Arm64Int64ToFloat32) \
V(Arm64Int64ToFloat64) \

View File

@ -113,6 +113,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArm64Float64ToInt64:
case kArm64Float32ToUint64:
case kArm64Float64ToUint64:
case kArm64Int32ToFloat32:
case kArm64Int32ToFloat64:
case kArm64Int64ToFloat32:
case kArm64Int64ToFloat64:

View File

@ -1219,6 +1219,11 @@ void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
}
void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
VisitRR(this, kArm64Int32ToFloat32, node);
}
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
VisitRR(this, kArm64Int32ToFloat64, node);
}

View File

@ -752,6 +752,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ add(i.OutputRegister(), Immediate(0x80000000));
break;
}
case kSSEInt32ToFloat32:
__ cvtsi2ss(i.OutputDoubleRegister(), i.InputOperand(0));
break;
case kSSEInt32ToFloat64:
__ cvtsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
break;

View File

@ -61,6 +61,7 @@ namespace compiler {
V(SSEFloat32ToInt32) \
V(SSEFloat64ToInt32) \
V(SSEFloat64ToUint32) \
V(SSEInt32ToFloat32) \
V(SSEInt32ToFloat64) \
V(SSEUint32ToFloat64) \
V(SSEFloat64ExtractLowWord32) \

View File

@ -64,6 +64,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kSSEFloat32ToInt32:
case kSSEFloat64ToInt32:
case kSSEFloat64ToUint32:
case kSSEInt32ToFloat32:
case kSSEInt32ToFloat64:
case kSSEUint32ToFloat64:
case kSSEFloat64ExtractLowWord32:

View File

@ -695,6 +695,11 @@ void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
}
void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
VisitRO(this, node, kSSEInt32ToFloat32);
}
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
VisitRO(this, node, kSSEInt32ToFloat64);
}

View File

@ -978,6 +978,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord32(node), VisitTruncateInt64ToInt32(node);
case IrOpcode::kRoundInt64ToFloat32:
return MarkAsFloat32(node), VisitRoundInt64ToFloat32(node);
case IrOpcode::kRoundInt32ToFloat32:
return MarkAsFloat32(node), VisitRoundInt32ToFloat32(node);
case IrOpcode::kRoundInt64ToFloat64:
return MarkAsFloat64(node), VisitRoundInt64ToFloat64(node);
case IrOpcode::kBitcastFloat32ToInt32:

View File

@ -150,6 +150,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
V(TryTruncateFloat32ToUint64, Operator::kNoProperties, 1, 0, 2) \
V(TryTruncateFloat64ToUint64, Operator::kNoProperties, 1, 0, 2) \
V(ChangeInt32ToFloat64, Operator::kNoProperties, 1, 0, 1) \
V(RoundInt32ToFloat32, Operator::kNoProperties, 1, 0, 1) \
V(RoundInt64ToFloat32, Operator::kNoProperties, 1, 0, 1) \
V(RoundInt64ToFloat64, Operator::kNoProperties, 1, 0, 1) \
V(RoundUint64ToFloat32, Operator::kNoProperties, 1, 0, 1) \

View File

@ -228,6 +228,7 @@ class MachineOperatorBuilder final : public ZoneObject {
const Operator* TruncateFloat64ToFloat32();
const Operator* TruncateFloat64ToInt32(TruncationMode);
const Operator* TruncateInt64ToInt32();
const Operator* RoundInt32ToFloat32();
const Operator* RoundInt64ToFloat32();
const Operator* RoundInt64ToFloat64();
const Operator* RoundUint64ToFloat32();

View File

@ -503,6 +503,11 @@ void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
}
void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
VisitRR(this, kMipsCvtSW, node);
}
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
VisitRR(this, kMipsCvtDW, node);
}

View File

@ -802,6 +802,11 @@ void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
}
void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
VisitRR(this, kMips64CvtSW, node);
}
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
VisitRR(this, kMips64CvtDW, node);
}

View File

@ -282,6 +282,7 @@
V(TruncateFloat64ToFloat32) \
V(TruncateFloat64ToInt32) \
V(TruncateInt64ToInt32) \
V(RoundInt32ToFloat32) \
V(RoundInt64ToFloat32) \
V(RoundInt64ToFloat64) \
V(RoundUint64ToFloat32) \

View File

@ -1194,6 +1194,11 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
DCHECK_EQ(LeaveRC, i.OutputRCBit());
break;
#endif
case kPPC_Int32ToFloat32:
__ ConvertIntToFloat(i.OutputDoubleRegister(), i.InputRegister(0),
kScratchReg);
DCHECK_EQ(LeaveRC, i.OutputRCBit());
break;
case kPPC_Int32ToDouble:
__ ConvertIntToDouble(i.InputRegister(0), i.OutputDoubleRegister());
DCHECK_EQ(LeaveRC, i.OutputRCBit());

View File

@ -82,6 +82,7 @@ namespace compiler {
V(PPC_Int64ToDouble) \
V(PPC_Uint64ToFloat32) \
V(PPC_Uint64ToDouble) \
V(PPC_Int32ToFloat32) \
V(PPC_Int32ToDouble) \
V(PPC_Uint32ToDouble) \
V(PPC_Float32ToDouble) \

View File

@ -81,6 +81,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kPPC_Int64ToDouble:
case kPPC_Uint64ToFloat32:
case kPPC_Uint64ToDouble:
case kPPC_Int32ToFloat32:
case kPPC_Int32ToDouble:
case kPPC_Uint32ToDouble:
case kPPC_Float32ToDouble:

View File

@ -940,6 +940,11 @@ void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
}
void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
VisitRR(this, kPPC_Int32ToFloat32, node);
}
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
VisitRR(this, kPPC_Int32ToDouble, node);
}

View File

@ -472,6 +472,9 @@ class RawMachineAssembler {
Node* TruncateInt64ToInt32(Node* a) {
return AddNode(machine()->TruncateInt64ToInt32(), a);
}
Node* RoundInt32ToFloat32(Node* a) {
return AddNode(machine()->RoundInt32ToFloat32(), a);
}
Node* RoundInt64ToFloat32(Node* a) {
return AddNode(machine()->RoundInt64ToFloat32(), a);
}

View File

@ -2205,6 +2205,11 @@ Type* Typer::Visitor::TypeTruncateInt64ToInt32(Node* node) {
}
Type* Typer::Visitor::TypeRoundInt32ToFloat32(Node* node) {
return Type::Intersect(Type::PlainNumber(), Type::UntaggedFloat32(), zone());
}
Type* Typer::Visitor::TypeRoundInt64ToFloat32(Node* node) {
return Type::Intersect(Type::PlainNumber(), Type::UntaggedFloat32(), zone());
}

View File

@ -907,6 +907,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kFloat64LessThan:
case IrOpcode::kFloat64LessThanOrEqual:
case IrOpcode::kTruncateInt64ToInt32:
case IrOpcode::kRoundInt32ToFloat32:
case IrOpcode::kRoundInt64ToFloat32:
case IrOpcode::kRoundInt64ToFloat64:
case IrOpcode::kRoundUint64ToFloat64:

View File

@ -696,9 +696,7 @@ Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input) {
op = m->ChangeUint32ToFloat64();
break;
case wasm::kExprF32SConvertI32:
op = m->ChangeInt32ToFloat64(); // TODO(titzer): two conversions
input = graph()->NewNode(op, input);
op = m->TruncateFloat64ToFloat32();
op = m->RoundInt32ToFloat32();
break;
case wasm::kExprF32UConvertI32:
op = m->ChangeUint32ToFloat64();

View File

@ -1204,6 +1204,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ Cvtlsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
}
break;
case kSSEInt32ToFloat32:
if (instr->InputAt(0)->IsRegister()) {
__ Cvtlsi2ss(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Cvtlsi2ss(i.OutputDoubleRegister(), i.InputOperand(0));
}
break;
case kSSEInt64ToFloat32:
if (instr->InputAt(0)->IsRegister()) {
__ Cvtqsi2ss(i.OutputDoubleRegister(), i.InputRegister(0));

View File

@ -85,6 +85,7 @@ namespace compiler {
V(SSEFloat32ToUint64) \
V(SSEFloat64ToUint64) \
V(SSEInt32ToFloat64) \
V(SSEInt32ToFloat32) \
V(SSEInt64ToFloat32) \
V(SSEInt64ToFloat64) \
V(SSEUint64ToFloat32) \

View File

@ -87,6 +87,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kSSEFloat64ToUint64:
case kSSEFloat32ToUint64:
case kSSEInt32ToFloat64:
case kSSEInt32ToFloat32:
case kSSEInt64ToFloat32:
case kSSEInt64ToFloat64:
case kSSEUint64ToFloat32:

View File

@ -1052,6 +1052,12 @@ void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
}
void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
X64OperandGenerator g(this);
Emit(kSSEInt32ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
}
void InstructionSelector::VisitRoundInt64ToFloat32(Node* node) {
X64OperandGenerator g(this);
Emit(kSSEInt64ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));

View File

@ -655,6 +655,11 @@ void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
}
void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
X87OperandGenerator g(this);
Emit(kX87Int32ToFloat64, g.DefineAsFixed(node, stX_0),

View File

@ -2000,6 +2000,15 @@ void Assembler::cvtsd2si(Register dst, XMMRegister src) {
}
void Assembler::cvtsi2ss(XMMRegister dst, const Operand& src) {
EnsureSpace ensure_space(this);
EMIT(0xF3);
EMIT(0x0F);
EMIT(0x2A);
emit_sse_operand(dst, src);
}
void Assembler::cvtsi2sd(XMMRegister dst, const Operand& src) {
EnsureSpace ensure_space(this);
EMIT(0xF2);

View File

@ -960,6 +960,8 @@ class Assembler : public AssemblerBase {
}
void cvtsd2si(Register dst, XMMRegister src);
void cvtsi2ss(XMMRegister dst, Register src) { cvtsi2ss(dst, Operand(src)); }
void cvtsi2ss(XMMRegister dst, const Operand& src);
void cvtsi2sd(XMMRegister dst, Register src) { cvtsi2sd(dst, Operand(src)); }
void cvtsi2sd(XMMRegister dst, const Operand& src);
void cvtss2sd(XMMRegister dst, const Operand& src);

View File

@ -3179,6 +3179,17 @@ void Assembler::cvtlsi2sd(XMMRegister dst, Register src) {
}
void Assembler::cvtlsi2ss(XMMRegister dst, const Operand& src) {
DCHECK(!IsEnabled(AVX));
EnsureSpace ensure_space(this);
emit(0xF3);
emit_optional_rex_32(dst, src);
emit(0x0F);
emit(0x2A);
emit_sse_operand(dst, src);
}
void Assembler::cvtlsi2ss(XMMRegister dst, Register src) {
EnsureSpace ensure_space(this);
emit(0xF3);

View File

@ -1025,6 +1025,7 @@ class Assembler : public AssemblerBase {
void cvttss2si(Register dst, const Operand& src);
void cvttss2si(Register dst, XMMRegister src);
void cvtlsi2ss(XMMRegister dst, const Operand& src);
void cvtlsi2ss(XMMRegister dst, Register src);
void andps(XMMRegister dst, XMMRegister src);
@ -1370,6 +1371,13 @@ class Assembler : public AssemblerBase {
void vcvtlsi2sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
vsd(0x2a, dst, src1, src2, kF2, k0F, kW0);
}
void vcvtlsi2ss(XMMRegister dst, XMMRegister src1, Register src2) {
XMMRegister isrc2 = {src2.code()};
vsd(0x2a, dst, src1, isrc2, kF3, k0F, kW0);
}
void vcvtlsi2ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
vsd(0x2a, dst, src1, src2, kF3, k0F, kW0);
}
void vcvtqsi2ss(XMMRegister dst, XMMRegister src1, Register src2) {
XMMRegister isrc2 = {src2.code()};
vsd(0x2a, dst, src1, isrc2, kF3, k0F, kW1);

View File

@ -823,6 +823,30 @@ void MacroAssembler::Cvtlsi2sd(XMMRegister dst, const Operand& src) {
}
void MacroAssembler::Cvtlsi2ss(XMMRegister dst, Register src) {
if (CpuFeatures::IsSupported(AVX)) {
CpuFeatureScope scope(this, AVX);
vxorps(dst, dst, dst);
vcvtlsi2ss(dst, dst, src);
} else {
xorps(dst, dst);
cvtlsi2ss(dst, src);
}
}
void MacroAssembler::Cvtlsi2ss(XMMRegister dst, const Operand& src) {
if (CpuFeatures::IsSupported(AVX)) {
CpuFeatureScope scope(this, AVX);
vxorps(dst, dst, dst);
vcvtlsi2ss(dst, dst, src);
} else {
xorps(dst, dst);
cvtlsi2ss(dst, src);
}
}
void MacroAssembler::Cvtqsi2ss(XMMRegister dst, Register src) {
if (CpuFeatures::IsSupported(AVX)) {
CpuFeatureScope scope(this, AVX);

View File

@ -812,6 +812,8 @@ class MacroAssembler: public Assembler {
void Cvtlsi2sd(XMMRegister dst, Register src);
void Cvtlsi2sd(XMMRegister dst, const Operand& src);
void Cvtlsi2ss(XMMRegister dst, Register src);
void Cvtlsi2ss(XMMRegister dst, const Operand& src);
void Cvtqsi2ss(XMMRegister dst, Register src);
void Cvtqsi2ss(XMMRegister dst, const Operand& src);

View File

@ -6013,6 +6013,13 @@ TEST(RunBitcastFloat32ToInt32) {
}
TEST(RunRoundInt32ToFloat32) {
BufferedRawMachineAssemblerTester<float> m(MachineType::Int32());
m.Return(m.RoundInt32ToFloat32(m.Parameter(0)));
FOR_INT32_INPUTS(i) { CHECK_EQ(static_cast<float>(*i), m.Call(*i)); }
}
TEST(RunBitcastInt32ToFloat32) {
int32_t input = 1;
float output = 0.0;