[turbofan] Add the TruncateFloat32ToInt32 operator to turbofan.
The new operator converts a float32 input to int32 through truncation. I provide implementations of the new operator for x64, ia32, arm, arm64, mips, mips64, and x87. @v8-ppc-ports, can you please take care of the ppc implementation? R=titzer@chromium.org, v8-arm-ports@googlegroups.com, v8-mips-ports@googlegroups.com, weiliang.lin@intel.com Review URL: https://codereview.chromium.org/1583323004 Cr-Commit-Position: refs/heads/master@{#33346}
This commit is contained in:
parent
dc6a593918
commit
fc53eed14b
@ -2923,6 +2923,12 @@ void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
|
||||
}
|
||||
|
||||
|
||||
void Assembler::vcvt_s32_f32(const SwVfpRegister dst, const SwVfpRegister src,
|
||||
VFPConversionMode mode, const Condition cond) {
|
||||
emit(EncodeVCVT(S32, dst.code(), F32, src.code(), mode, cond));
|
||||
}
|
||||
|
||||
|
||||
void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
|
||||
const DwVfpRegister src,
|
||||
VFPConversionMode mode,
|
||||
|
@ -1125,6 +1125,10 @@ class Assembler : public AssemblerBase {
|
||||
const SwVfpRegister src,
|
||||
VFPConversionMode mode = kDefaultRoundToZero,
|
||||
const Condition cond = al);
|
||||
void vcvt_s32_f32(const SwVfpRegister dst,
|
||||
const SwVfpRegister src,
|
||||
VFPConversionMode mode = kDefaultRoundToZero,
|
||||
const Condition cond = al);
|
||||
void vcvt_s32_f64(const SwVfpRegister dst,
|
||||
const DwVfpRegister src,
|
||||
VFPConversionMode mode = kDefaultRoundToZero,
|
||||
|
@ -845,6 +845,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
DCHECK_EQ(LeaveCC, i.OutputSBit());
|
||||
break;
|
||||
}
|
||||
case kArmVcvtS32F32: {
|
||||
SwVfpRegister scratch = kScratchDoubleReg.low();
|
||||
__ vcvt_s32_f32(scratch, i.InputFloat32Register(0));
|
||||
__ vmov(i.OutputRegister(), scratch);
|
||||
DCHECK_EQ(LeaveCC, i.OutputSBit());
|
||||
break;
|
||||
}
|
||||
case kArmVcvtS32F64: {
|
||||
SwVfpRegister scratch = kScratchDoubleReg.low();
|
||||
__ vcvt_s32_f64(scratch, i.InputFloat64Register(0));
|
||||
|
@ -78,6 +78,7 @@ namespace compiler {
|
||||
V(ArmVcvtF64F32) \
|
||||
V(ArmVcvtF64S32) \
|
||||
V(ArmVcvtF64U32) \
|
||||
V(ArmVcvtS32F32) \
|
||||
V(ArmVcvtS32F64) \
|
||||
V(ArmVcvtU32F64) \
|
||||
V(ArmVmovLowU32F64) \
|
||||
|
@ -80,6 +80,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
|
||||
case kArmVcvtF64F32:
|
||||
case kArmVcvtF64S32:
|
||||
case kArmVcvtF64U32:
|
||||
case kArmVcvtS32F32:
|
||||
case kArmVcvtS32F64:
|
||||
case kArmVcvtU32F64:
|
||||
case kArmVmovLowU32F64:
|
||||
|
@ -931,6 +931,11 @@ void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
|
||||
VisitRR(this, kArmVcvtS32F32, node);
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
|
||||
VisitRR(this, kArmVcvtS32F64, node);
|
||||
}
|
||||
|
@ -1042,6 +1042,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
case kArm64Float64ToFloat32:
|
||||
__ Fcvt(i.OutputDoubleRegister().S(), i.InputDoubleRegister(0));
|
||||
break;
|
||||
case kArm64Float32ToInt32:
|
||||
__ Fcvtzs(i.OutputRegister32(), i.InputFloat32Register(0));
|
||||
break;
|
||||
case kArm64Float64ToInt32:
|
||||
__ Fcvtzs(i.OutputRegister32(), i.InputDoubleRegister(0));
|
||||
break;
|
||||
|
@ -110,6 +110,7 @@ namespace compiler {
|
||||
V(Arm64Float64RoundTiesEven) \
|
||||
V(Arm64Float32ToFloat64) \
|
||||
V(Arm64Float64ToFloat32) \
|
||||
V(Arm64Float32ToInt32) \
|
||||
V(Arm64Float64ToInt32) \
|
||||
V(Arm64Float64ToUint32) \
|
||||
V(Arm64Float32ToInt64) \
|
||||
|
@ -106,6 +106,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
|
||||
case kArm64Float32RoundUp:
|
||||
case kArm64Float32ToFloat64:
|
||||
case kArm64Float64ToFloat32:
|
||||
case kArm64Float32ToInt32:
|
||||
case kArm64Float64ToInt32:
|
||||
case kArm64Float64ToUint32:
|
||||
case kArm64Float32ToInt64:
|
||||
|
@ -1229,6 +1229,11 @@ void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
|
||||
VisitRR(this, kArm64Float32ToInt32, node);
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
|
||||
VisitRR(this, kArm64Float64ToInt32, node);
|
||||
}
|
||||
|
@ -739,6 +739,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
case kSSEFloat64ToFloat32:
|
||||
__ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
|
||||
break;
|
||||
case kSSEFloat32ToInt32:
|
||||
__ cvttss2si(i.OutputRegister(), i.InputOperand(0));
|
||||
break;
|
||||
case kSSEFloat64ToInt32:
|
||||
__ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
|
||||
break;
|
||||
|
@ -58,6 +58,7 @@ namespace compiler {
|
||||
V(SSEFloat64Round) \
|
||||
V(SSEFloat32ToFloat64) \
|
||||
V(SSEFloat64ToFloat32) \
|
||||
V(SSEFloat32ToInt32) \
|
||||
V(SSEFloat64ToInt32) \
|
||||
V(SSEFloat64ToUint32) \
|
||||
V(SSEInt32ToFloat64) \
|
||||
|
@ -61,6 +61,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
|
||||
case kSSEFloat64Round:
|
||||
case kSSEFloat32ToFloat64:
|
||||
case kSSEFloat64ToFloat32:
|
||||
case kSSEFloat32ToInt32:
|
||||
case kSSEFloat64ToInt32:
|
||||
case kSSEFloat64ToUint32:
|
||||
case kSSEInt32ToFloat64:
|
||||
|
@ -705,6 +705,11 @@ void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
|
||||
VisitRO(this, node, kSSEFloat32ToInt32);
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
|
||||
VisitRO(this, node, kSSEFloat64ToInt32);
|
||||
}
|
||||
|
@ -956,6 +956,8 @@ void InstructionSelector::VisitNode(Node* node) {
|
||||
return MarkAsWord32(node), VisitChangeFloat64ToInt32(node);
|
||||
case IrOpcode::kChangeFloat64ToUint32:
|
||||
return MarkAsWord32(node), VisitChangeFloat64ToUint32(node);
|
||||
case IrOpcode::kTruncateFloat32ToInt32:
|
||||
return MarkAsWord32(node), VisitTruncateFloat32ToInt32(node);
|
||||
case IrOpcode::kTryTruncateFloat32ToInt64:
|
||||
return MarkAsWord64(node), VisitTryTruncateFloat32ToInt64(node);
|
||||
case IrOpcode::kTryTruncateFloat64ToInt64:
|
||||
|
@ -144,6 +144,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
|
||||
V(ChangeFloat32ToFloat64, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(ChangeFloat64ToInt32, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(ChangeFloat64ToUint32, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(TruncateFloat32ToInt32, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(TryTruncateFloat32ToInt64, Operator::kNoProperties, 1, 0, 2) \
|
||||
V(TryTruncateFloat64ToInt64, Operator::kNoProperties, 1, 0, 2) \
|
||||
V(TryTruncateFloat32ToUint64, Operator::kNoProperties, 1, 0, 2) \
|
||||
|
@ -213,6 +213,7 @@ class MachineOperatorBuilder final : public ZoneObject {
|
||||
const Operator* ChangeFloat32ToFloat64();
|
||||
const Operator* ChangeFloat64ToInt32(); // narrowing
|
||||
const Operator* ChangeFloat64ToUint32(); // narrowing
|
||||
const Operator* TruncateFloat32ToInt32();
|
||||
const Operator* TryTruncateFloat32ToInt64();
|
||||
const Operator* TryTruncateFloat64ToInt64();
|
||||
const Operator* TryTruncateFloat32ToUint64();
|
||||
|
@ -513,6 +513,11 @@ void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
|
||||
VisitRR(this, kMipsTruncWS, node);
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
|
||||
MipsOperandGenerator g(this);
|
||||
Node* value = node->InputAt(0);
|
||||
|
@ -812,6 +812,11 @@ void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
|
||||
VisitRR(this, kMips64TruncWS, node);
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
|
||||
Mips64OperandGenerator g(this);
|
||||
Node* value = node->InputAt(0);
|
||||
|
@ -270,6 +270,7 @@
|
||||
V(ChangeFloat32ToFloat64) \
|
||||
V(ChangeFloat64ToInt32) \
|
||||
V(ChangeFloat64ToUint32) \
|
||||
V(TruncateFloat32ToInt32) \
|
||||
V(TryTruncateFloat32ToInt64) \
|
||||
V(TryTruncateFloat64ToInt64) \
|
||||
V(TryTruncateFloat32ToUint64) \
|
||||
|
@ -432,10 +432,8 @@ class RawMachineAssembler {
|
||||
Node* ChangeFloat64ToUint32(Node* a) {
|
||||
return AddNode(machine()->ChangeFloat64ToUint32(), a);
|
||||
}
|
||||
Node* TruncateFloat32ToInt64(Node* a) {
|
||||
// TODO(ahaas): Remove this function as soon as it is not used anymore in
|
||||
// WebAssembly.
|
||||
return AddNode(machine()->TryTruncateFloat32ToInt64(), a);
|
||||
Node* TruncateFloat32ToInt32(Node* a) {
|
||||
return AddNode(machine()->TruncateFloat32ToInt32(), a);
|
||||
}
|
||||
Node* TryTruncateFloat32ToInt64(Node* a) {
|
||||
return AddNode(machine()->TryTruncateFloat32ToInt64(), a);
|
||||
@ -448,11 +446,6 @@ class RawMachineAssembler {
|
||||
Node* TryTruncateFloat64ToInt64(Node* a) {
|
||||
return AddNode(machine()->TryTruncateFloat64ToInt64(), a);
|
||||
}
|
||||
Node* TruncateFloat32ToUint64(Node* a) {
|
||||
// TODO(ahaas): Remove this function as soon as it is not used anymore in
|
||||
// WebAssembly.
|
||||
return AddNode(machine()->TryTruncateFloat32ToUint64(), a);
|
||||
}
|
||||
Node* TryTruncateFloat32ToUint64(Node* a) {
|
||||
return AddNode(machine()->TryTruncateFloat32ToUint64(), a);
|
||||
}
|
||||
|
@ -2145,6 +2145,11 @@ Type* Typer::Visitor::TypeChangeFloat64ToUint32(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
Type* Typer::Visitor::TypeTruncateFloat32ToInt32(Node* node) {
|
||||
return Type::Intersect(Type::Signed32(), Type::UntaggedIntegral32(), zone());
|
||||
}
|
||||
|
||||
|
||||
Type* Typer::Visitor::TypeTryTruncateFloat32ToInt64(Node* node) {
|
||||
return Type::Internal();
|
||||
}
|
||||
|
@ -924,6 +924,7 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kChangeFloat32ToFloat64:
|
||||
case IrOpcode::kChangeFloat64ToInt32:
|
||||
case IrOpcode::kChangeFloat64ToUint32:
|
||||
case IrOpcode::kTruncateFloat32ToInt32:
|
||||
case IrOpcode::kTryTruncateFloat32ToInt64:
|
||||
case IrOpcode::kTryTruncateFloat64ToInt64:
|
||||
case IrOpcode::kTryTruncateFloat32ToUint64:
|
||||
|
@ -1121,14 +1121,12 @@ Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input) {
|
||||
MachineOperatorBuilder* m = jsgraph()->machine();
|
||||
// Truncation of the input value is needed for the overflow check later.
|
||||
Node* trunc = Unop(wasm::kExprF32Trunc, input);
|
||||
// TODO(titzer): two conversions
|
||||
Node* f64_trunc = graph()->NewNode(m->ChangeFloat32ToFloat64(), trunc);
|
||||
Node* result = graph()->NewNode(m->ChangeFloat64ToInt32(), f64_trunc);
|
||||
Node* result = graph()->NewNode(m->TruncateFloat32ToInt32(), trunc);
|
||||
|
||||
// Convert the result back to f64. If we end up at a different value than the
|
||||
// truncated input value, then there has been an overflow and we trap.
|
||||
Node* check = Unop(wasm::kExprF64SConvertI32, result);
|
||||
Node* overflow = Binop(wasm::kExprF64Ne, f64_trunc, check);
|
||||
Node* check = Unop(wasm::kExprF32SConvertI32, result);
|
||||
Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
|
||||
trap_->AddTrapIfTrue(kTrapFloatUnrepresentable, overflow);
|
||||
|
||||
return result;
|
||||
|
@ -947,6 +947,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
__ Roundss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
|
||||
break;
|
||||
}
|
||||
case kSSEFloat32ToInt32:
|
||||
if (instr->InputAt(0)->IsDoubleRegister()) {
|
||||
__ Cvttss2si(i.OutputRegister(), i.InputDoubleRegister(0));
|
||||
} else {
|
||||
__ Cvttss2si(i.OutputRegister(), i.InputOperand(0));
|
||||
}
|
||||
break;
|
||||
case kSSEFloat64Cmp:
|
||||
ASSEMBLE_SSE_BINOP(Ucomisd);
|
||||
break;
|
||||
|
@ -63,6 +63,7 @@ namespace compiler {
|
||||
V(SSEFloat32Max) \
|
||||
V(SSEFloat32Min) \
|
||||
V(SSEFloat32ToFloat64) \
|
||||
V(SSEFloat32ToInt32) \
|
||||
V(SSEFloat32Round) \
|
||||
V(SSEFloat64Cmp) \
|
||||
V(SSEFloat64Add) \
|
||||
|
@ -79,6 +79,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
|
||||
case kSSEFloat64Max:
|
||||
case kSSEFloat64Min:
|
||||
case kSSEFloat64ToFloat32:
|
||||
case kSSEFloat32ToInt32:
|
||||
case kSSEFloat64ToInt32:
|
||||
case kSSEFloat64ToUint32:
|
||||
case kSSEFloat64ToInt64:
|
||||
|
@ -857,6 +857,12 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
|
||||
X64OperandGenerator g(this);
|
||||
Emit(kSSEFloat32ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
|
||||
X64OperandGenerator g(this);
|
||||
InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
|
||||
|
@ -1005,6 +1005,16 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
__ LoadUint32NoSSE2(i.InputRegister(0));
|
||||
break;
|
||||
}
|
||||
case kX87Float32ToInt32: {
|
||||
if (!instr->InputAt(0)->IsDoubleRegister()) {
|
||||
__ fld_s(i.InputOperand(0));
|
||||
}
|
||||
__ TruncateX87TOSToI(i.OutputRegister(0));
|
||||
if (!instr->InputAt(0)->IsDoubleRegister()) {
|
||||
__ fstp(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kX87Float64ToInt32: {
|
||||
if (!instr->InputAt(0)->IsDoubleRegister()) {
|
||||
__ fld_d(i.InputOperand(0));
|
||||
|
@ -57,6 +57,7 @@ namespace compiler {
|
||||
V(X87Float32ToFloat64) \
|
||||
V(X87Uint32ToFloat64) \
|
||||
V(X87Float64ToInt32) \
|
||||
V(X87Float32ToInt32) \
|
||||
V(X87Float64ToFloat32) \
|
||||
V(X87Float64ToUint32) \
|
||||
V(X87Float64ExtractHighWord32) \
|
||||
|
@ -669,6 +669,12 @@ void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
|
||||
X87OperandGenerator g(this);
|
||||
Emit(kX87Float32ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
|
||||
X87OperandGenerator g(this);
|
||||
Emit(kX87Float64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
||||
|
@ -1384,6 +1384,14 @@ class Assembler : public AssemblerBase {
|
||||
void vcvtqsi2sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
|
||||
vsd(0x2a, dst, src1, src2, kF2, k0F, kW1);
|
||||
}
|
||||
void vcvttss2si(Register dst, XMMRegister src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
vsd(0x2c, idst, xmm0, src, kF3, k0F, kW0);
|
||||
}
|
||||
void vcvttss2si(Register dst, const Operand& src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
vsd(0x2c, idst, xmm0, src, kF3, k0F, kW0);
|
||||
}
|
||||
void vcvttsd2si(Register dst, XMMRegister src) {
|
||||
XMMRegister idst = {dst.code()};
|
||||
vsd(0x2c, idst, xmm0, src, kF2, k0F, kW0);
|
||||
|
@ -918,6 +918,26 @@ void MacroAssembler::Cvtsd2si(Register dst, XMMRegister src) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Cvttss2si(Register dst, XMMRegister src) {
|
||||
if (CpuFeatures::IsSupported(AVX)) {
|
||||
CpuFeatureScope scope(this, AVX);
|
||||
vcvttss2si(dst, src);
|
||||
} else {
|
||||
cvttss2si(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Cvttss2si(Register dst, const Operand& src) {
|
||||
if (CpuFeatures::IsSupported(AVX)) {
|
||||
CpuFeatureScope scope(this, AVX);
|
||||
vcvttss2si(dst, src);
|
||||
} else {
|
||||
cvttss2si(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Cvttsd2si(Register dst, XMMRegister src) {
|
||||
if (CpuFeatures::IsSupported(AVX)) {
|
||||
CpuFeatureScope scope(this, AVX);
|
||||
|
@ -823,6 +823,8 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
void Cvtsd2si(Register dst, XMMRegister src);
|
||||
|
||||
void Cvttss2si(Register dst, XMMRegister src);
|
||||
void Cvttss2si(Register dst, const Operand& src);
|
||||
void Cvttsd2si(Register dst, XMMRegister src);
|
||||
void Cvttsd2si(Register dst, const Operand& src);
|
||||
void Cvttss2siq(Register dst, XMMRegister src);
|
||||
|
@ -92,7 +92,7 @@ class BufferedRawMachineAssemblerTester
|
||||
// parameters from memory. Thereby it is possible to pass 64 bit parameters
|
||||
// to the IR graph.
|
||||
Node* Parameter(size_t index) {
|
||||
CHECK(index >= 0 && index < 4);
|
||||
CHECK(index < 4);
|
||||
return parameter_nodes_[index];
|
||||
}
|
||||
|
||||
|
@ -4124,6 +4124,18 @@ TEST(RunChangeUint32ToFloat64) {
|
||||
}
|
||||
|
||||
|
||||
TEST(RunTruncateFloat32ToInt32) {
|
||||
BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Float32());
|
||||
m.Return(m.TruncateFloat32ToInt32(m.Parameter(0)));
|
||||
FOR_FLOAT32_INPUTS(i) {
|
||||
if (*i <= static_cast<float>(std::numeric_limits<int32_t>::max()) &&
|
||||
*i >= static_cast<float>(std::numeric_limits<int32_t>::min())) {
|
||||
CheckFloatEq(static_cast<int32_t>(*i), m.Call(*i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunChangeFloat64ToInt32_A) {
|
||||
BufferedRawMachineAssemblerTester<int32_t> m;
|
||||
double magic = 11.1;
|
||||
|
Loading…
Reference in New Issue
Block a user