Commit 2166bd8c authored by jing.bao's avatar jing.bao Committed by Commit bot

[turbofan] Add TruncateFloat32ToUint32 operator to Turbofan.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#33797}
parent 187b3f28
......@@ -2935,6 +2935,12 @@ void Assembler::vcvt_s32_f32(const SwVfpRegister dst, const SwVfpRegister src,
}
void Assembler::vcvt_u32_f32(const SwVfpRegister dst, const SwVfpRegister src,
VFPConversionMode mode, const Condition cond) {
emit(EncodeVCVT(U32, dst.code(), F32, src.code(), mode, cond));
}
void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
VFPConversionMode mode,
......
......@@ -1133,6 +1133,10 @@ class Assembler : public AssemblerBase {
const SwVfpRegister src,
VFPConversionMode mode = kDefaultRoundToZero,
const Condition cond = al);
void vcvt_u32_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,
......
......@@ -878,6 +878,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVcvtU32F32: {
SwVfpRegister scratch = kScratchDoubleReg.low();
__ vcvt_u32_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));
......
......@@ -81,6 +81,7 @@ namespace compiler {
V(ArmVcvtF64S32) \
V(ArmVcvtF64U32) \
V(ArmVcvtS32F32) \
V(ArmVcvtU32F32) \
V(ArmVcvtS32F64) \
V(ArmVcvtU32F64) \
V(ArmVmovLowU32F64) \
......
......@@ -83,6 +83,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArmVcvtF64S32:
case kArmVcvtF64U32:
case kArmVcvtS32F32:
case kArmVcvtU32F32:
case kArmVcvtS32F64:
case kArmVcvtU32F64:
case kArmVmovLowU32F64:
......
......@@ -946,6 +946,11 @@ void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
VisitRR(this, kArmVcvtU32F32, node);
}
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
VisitRR(this, kArmVcvtS32F64, node);
}
......
......@@ -1100,6 +1100,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArm64Float64ToInt32:
__ Fcvtzs(i.OutputRegister32(), i.InputDoubleRegister(0));
break;
case kArm64Float32ToUint32:
__ Fcvtzu(i.OutputRegister32(), i.InputFloat32Register(0));
break;
case kArm64Float64ToUint32:
__ Fcvtzu(i.OutputRegister32(), i.InputDoubleRegister(0));
break;
......
......@@ -114,6 +114,7 @@ namespace compiler {
V(Arm64Float64ToFloat32) \
V(Arm64Float32ToInt32) \
V(Arm64Float64ToInt32) \
V(Arm64Float32ToUint32) \
V(Arm64Float64ToUint32) \
V(Arm64Float32ToInt64) \
V(Arm64Float64ToInt64) \
......
......@@ -108,6 +108,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArm64Float64ToFloat32:
case kArm64Float32ToInt32:
case kArm64Float64ToInt32:
case kArm64Float32ToUint32:
case kArm64Float64ToUint32:
case kArm64Float32ToInt64:
case kArm64Float64ToInt64:
......
......@@ -1249,6 +1249,11 @@ void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
VisitRR(this, kArm64Float32ToUint32, node);
}
void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
VisitRR(this, kArm64Float64ToUint32, node);
}
......
......@@ -754,6 +754,18 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kSSEFloat32ToInt32:
__ cvttss2si(i.OutputRegister(), i.InputOperand(0));
break;
case kSSEFloat32ToUint32: {
Label success;
__ cvttss2si(i.OutputRegister(), i.InputOperand(0));
__ test(i.OutputRegister(), i.OutputRegister());
__ j(positive, &success);
__ Move(kScratchDoubleReg, static_cast<float>(INT32_MIN));
__ addss(kScratchDoubleReg, i.InputOperand(0));
__ cvttss2si(i.OutputRegister(), kScratchDoubleReg);
__ or_(i.OutputRegister(), Immediate(0x80000000));
__ bind(&success);
break;
}
case kSSEFloat64ToInt32:
__ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
break;
......
......@@ -59,6 +59,7 @@ namespace compiler {
V(SSEFloat32ToFloat64) \
V(SSEFloat64ToFloat32) \
V(SSEFloat32ToInt32) \
V(SSEFloat32ToUint32) \
V(SSEFloat64ToInt32) \
V(SSEFloat64ToUint32) \
V(SSEInt32ToFloat32) \
......
......@@ -62,6 +62,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kSSEFloat32ToFloat64:
case kSSEFloat64ToFloat32:
case kSSEFloat32ToInt32:
case kSSEFloat32ToUint32:
case kSSEFloat64ToInt32:
case kSSEFloat64ToUint32:
case kSSEInt32ToFloat32:
......
......@@ -724,6 +724,11 @@ void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
VisitRO(this, node, kSSEFloat32ToUint32);
}
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
VisitRO(this, node, kSSEFloat64ToInt32);
}
......
......@@ -959,6 +959,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord32(node), VisitChangeFloat64ToUint32(node);
case IrOpcode::kTruncateFloat32ToInt32:
return MarkAsWord32(node), VisitTruncateFloat32ToInt32(node);
case IrOpcode::kTruncateFloat32ToUint32:
return MarkAsWord32(node), VisitTruncateFloat32ToUint32(node);
case IrOpcode::kTryTruncateFloat32ToInt64:
return MarkAsWord64(node), VisitTryTruncateFloat32ToInt64(node);
case IrOpcode::kTryTruncateFloat64ToInt64:
......
......@@ -149,6 +149,7 @@ MachineRepresentation StackSlotRepresentationOf(Operator const* op) {
V(ChangeFloat64ToInt32, Operator::kNoProperties, 1, 0, 1) \
V(ChangeFloat64ToUint32, Operator::kNoProperties, 1, 0, 1) \
V(TruncateFloat32ToInt32, Operator::kNoProperties, 1, 0, 1) \
V(TruncateFloat32ToUint32, 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) \
......
......@@ -215,6 +215,7 @@ class MachineOperatorBuilder final : public ZoneObject {
const Operator* ChangeFloat64ToInt32(); // narrowing
const Operator* ChangeFloat64ToUint32(); // narrowing
const Operator* TruncateFloat32ToInt32();
const Operator* TruncateFloat32ToUint32();
const Operator* TryTruncateFloat32ToInt64();
const Operator* TryTruncateFloat64ToInt64();
const Operator* TryTruncateFloat32ToUint64();
......
......@@ -534,6 +534,11 @@ void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
MipsOperandGenerator g(this);
Node* value = node->InputAt(0);
......
......@@ -841,6 +841,11 @@ void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
Mips64OperandGenerator g(this);
Node* value = node->InputAt(0);
......
......@@ -273,6 +273,7 @@
V(ChangeFloat64ToInt32) \
V(ChangeFloat64ToUint32) \
V(TruncateFloat32ToInt32) \
V(TruncateFloat32ToUint32) \
V(TryTruncateFloat32ToInt64) \
V(TryTruncateFloat64ToInt64) \
V(TryTruncateFloat32ToUint64) \
......
......@@ -1025,6 +1025,11 @@ void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
UNIMPLEMENTED();
}
#if V8_TARGET_ARCH_PPC64
void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
// TODO(mbrandy): inspect input to see if nop is appropriate.
......
......@@ -459,6 +459,9 @@ class RawMachineAssembler {
Node* TruncateFloat32ToInt32(Node* a) {
return AddNode(machine()->TruncateFloat32ToInt32(), a);
}
Node* TruncateFloat32ToUint32(Node* a) {
return AddNode(machine()->TruncateFloat32ToUint32(), a);
}
Node* TryTruncateFloat32ToInt64(Node* a) {
return AddNode(machine()->TryTruncateFloat32ToInt64(), a);
}
......
......@@ -2125,6 +2125,12 @@ Type* Typer::Visitor::TypeTruncateFloat32ToInt32(Node* node) {
}
Type* Typer::Visitor::TypeTruncateFloat32ToUint32(Node* node) {
return Type::Intersect(Type::Unsigned32(), Type::UntaggedIntegral32(),
zone());
}
Type* Typer::Visitor::TypeTryTruncateFloat32ToInt64(Node* node) {
return Type::Internal();
}
......
......@@ -935,6 +935,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kChangeFloat64ToInt32:
case IrOpcode::kChangeFloat64ToUint32:
case IrOpcode::kTruncateFloat32ToInt32:
case IrOpcode::kTruncateFloat32ToUint32:
case IrOpcode::kTryTruncateFloat32ToInt64:
case IrOpcode::kTryTruncateFloat64ToInt64:
case IrOpcode::kTryTruncateFloat32ToUint64:
......
......@@ -1145,14 +1145,12 @@ Node* WasmGraphBuilder::BuildI32UConvertF32(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->ChangeFloat64ToUint32(), f64_trunc);
Node* result = graph()->NewNode(m->TruncateFloat32ToUint32(), trunc);
// Convert the result back to f64. If we end up at a different value than the
// Convert the result back to f32. 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::kExprF64UConvertI32, result);
Node* overflow = Binop(wasm::kExprF64Ne, f64_trunc, check);
Node* check = Unop(wasm::kExprF32UConvertI32, result);
Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
trap_->AddTrapIfTrue(kTrapFloatUnrepresentable, overflow);
return result;
......
......@@ -966,6 +966,15 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ Cvttss2si(i.OutputRegister(), i.InputOperand(0));
}
break;
case kSSEFloat32ToUint32: {
if (instr->InputAt(0)->IsDoubleRegister()) {
__ Cvttss2siq(i.OutputRegister(), i.InputDoubleRegister(0));
} else {
__ Cvttss2siq(i.OutputRegister(), i.InputOperand(0));
}
__ AssertZeroExtended(i.OutputRegister());
break;
}
case kSSEFloat64Cmp:
ASSEMBLE_SSE_BINOP(Ucomisd);
break;
......
......@@ -64,6 +64,7 @@ namespace compiler {
V(SSEFloat32Min) \
V(SSEFloat32ToFloat64) \
V(SSEFloat32ToInt32) \
V(SSEFloat32ToUint32) \
V(SSEFloat32Round) \
V(SSEFloat64Cmp) \
V(SSEFloat64Add) \
......
......@@ -80,6 +80,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kSSEFloat64Min:
case kSSEFloat64ToFloat32:
case kSSEFloat32ToInt32:
case kSSEFloat32ToUint32:
case kSSEFloat64ToInt32:
case kSSEFloat64ToUint32:
case kSSEFloat64ToInt64:
......
......@@ -864,6 +864,12 @@ void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
X64OperandGenerator g(this);
Emit(kSSEFloat32ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
}
void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
X64OperandGenerator g(this);
InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
......
......@@ -688,6 +688,11 @@ void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
X87OperandGenerator g(this);
Emit(kX87Float64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
......
......@@ -790,6 +790,7 @@ class MacroAssembler: public Assembler {
// Move an immediate into an XMM register.
void Move(XMMRegister dst, uint32_t src);
void Move(XMMRegister dst, uint64_t src);
void Move(XMMRegister dst, float src) { Move(dst, bit_cast<uint32_t>(src)); }
void Move(XMMRegister dst, double src) { Move(dst, bit_cast<uint64_t>(src)); }
void Move(Register dst, Smi* source) { Move(dst, Immediate(source)); }
......
......@@ -4135,6 +4135,31 @@ TEST(RunTruncateFloat32ToInt32) {
}
TEST(RunTruncateFloat32ToUint32) {
BufferedRawMachineAssemblerTester<uint32_t> m(MachineType::Float32());
m.Return(m.TruncateFloat32ToUint32(m.Parameter(0)));
{
FOR_UINT32_INPUTS(i) {
float input = static_cast<float>(*i);
// This condition on 'input' is required because
// static_cast<float>(std::numeric_limits<uint32_t>::max()) results in a
// value outside uint32 range.
if (input < static_cast<float>(std::numeric_limits<uint32_t>::max())) {
CHECK_EQ(static_cast<uint32_t>(input), m.Call(input));
}
}
}
{
FOR_FLOAT32_INPUTS(i) {
if (*i <= static_cast<float>(std::numeric_limits<uint32_t>::max()) &&
*i >= static_cast<float>(std::numeric_limits<uint32_t>::min())) {
CheckFloatEq(static_cast<uint32_t>(*i), m.Call(*i));
}
}
}
}
TEST(RunChangeFloat64ToInt32_A) {
BufferedRawMachineAssemblerTester<int32_t> m;
double magic = 11.1;
......
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