diff --git a/src/compiler/arm/code-generator-arm.cc b/src/compiler/arm/code-generator-arm.cc index f47eafebf5..7f761640b2 100644 --- a/src/compiler/arm/code-generator-arm.cc +++ b/src/compiler/arm/code-generator-arm.cc @@ -617,6 +617,27 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { DCHECK_EQ(LeaveCC, i.OutputSBit()); break; } + case kArmVmovLowU32F64: + __ VmovLow(i.OutputRegister(), i.InputFloat64Register(0)); + DCHECK_EQ(LeaveCC, i.OutputSBit()); + break; + case kArmVmovLowF64U32: + __ VmovLow(i.OutputFloat64Register(), i.InputRegister(1)); + DCHECK_EQ(LeaveCC, i.OutputSBit()); + break; + case kArmVmovHighU32F64: + __ VmovHigh(i.OutputRegister(), i.InputFloat64Register(0)); + DCHECK_EQ(LeaveCC, i.OutputSBit()); + break; + case kArmVmovHighF64U32: + __ VmovHigh(i.OutputFloat64Register(), i.InputRegister(1)); + DCHECK_EQ(LeaveCC, i.OutputSBit()); + break; + case kArmVmovF64U32U32: + __ vmov(i.OutputFloat64Register(), i.InputRegister(0), + i.InputRegister(1)); + DCHECK_EQ(LeaveCC, i.OutputSBit()); + break; case kArmLdrb: __ ldrb(i.OutputRegister(), i.InputOffset()); DCHECK_EQ(LeaveCC, i.OutputSBit()); diff --git a/src/compiler/arm/instruction-codes-arm.h b/src/compiler/arm/instruction-codes-arm.h index ecd0b2d70b..6e9e1e5978 100644 --- a/src/compiler/arm/instruction-codes-arm.h +++ b/src/compiler/arm/instruction-codes-arm.h @@ -63,6 +63,11 @@ namespace compiler { V(ArmVcvtF64U32) \ V(ArmVcvtS32F64) \ V(ArmVcvtU32F64) \ + V(ArmVmovLowU32F64) \ + V(ArmVmovLowF64U32) \ + V(ArmVmovHighU32F64) \ + V(ArmVmovHighF64U32) \ + V(ArmVmovF64U32U32) \ V(ArmVldrF32) \ V(ArmVstrF32) \ V(ArmVldrF64) \ diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc index e08226d5f3..d16c3e7e3b 100644 --- a/src/compiler/arm/instruction-selector-arm.cc +++ b/src/compiler/arm/instruction-selector-arm.cc @@ -1394,6 +1394,52 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { } +void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) { + ArmOperandGenerator g(this); + Emit(kArmVmovLowU32F64, g.DefineAsRegister(node), + g.UseRegister(node->InputAt(0))); +} + + +void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) { + ArmOperandGenerator g(this); + Emit(kArmVmovHighU32F64, g.DefineAsRegister(node), + g.UseRegister(node->InputAt(0))); +} + + +void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) { + ArmOperandGenerator g(this); + Node* left = node->InputAt(0); + Node* right = node->InputAt(1); + if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 && + CanCover(node, left)) { + left = left->InputAt(1); + Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right), + g.UseRegister(left)); + return; + } + Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left), + g.UseRegister(right)); +} + + +void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) { + ArmOperandGenerator g(this); + Node* left = node->InputAt(0); + Node* right = node->InputAt(1); + if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 && + CanCover(node, left)) { + left = left->InputAt(1); + Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left), + g.UseRegister(right)); + return; + } + Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left), + g.UseRegister(right)); +} + + // static MachineOperatorBuilder::Flags InstructionSelector::SupportedMachineOperatorFlags() { diff --git a/src/compiler/arm64/code-generator-arm64.cc b/src/compiler/arm64/code-generator-arm64.cc index b3c7230807..0f19cbddff 100644 --- a/src/compiler/arm64/code-generator-arm64.cc +++ b/src/compiler/arm64/code-generator-arm64.cc @@ -693,6 +693,29 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { case kArm64Uint32ToFloat64: __ Ucvtf(i.OutputDoubleRegister(), i.InputRegister32(0)); break; + case kArm64Float64ExtractLowWord32: + __ Fmov(i.OutputRegister32(), i.InputFloat32Register(0)); + break; + case kArm64Float64ExtractHighWord32: + __ Fmov(i.OutputRegister(), i.InputFloat64Register(0)); + __ Lsr(i.OutputRegister(), i.OutputRegister(), 32); + break; + case kArm64Float64InsertLowWord32: { + UseScratchRegisterScope scope(masm()); + Register tmp = scope.AcquireX(); + __ Fmov(tmp, i.InputFloat64Register(0)); + __ Bfi(tmp, i.InputRegister(1), 0, 32); + __ Fmov(i.OutputFloat64Register(), tmp); + break; + } + case kArm64Float64InsertHighWord32: { + UseScratchRegisterScope scope(masm()); + Register tmp = scope.AcquireX(); + __ Fmov(tmp.W(), i.InputFloat32Register(0)); + __ Bfi(tmp, i.InputRegister(1), 32, 32); + __ Fmov(i.OutputFloat64Register(), tmp); + break; + } case kArm64Ldrb: __ Ldrb(i.OutputRegister(), i.MemoryOperand()); break; diff --git a/src/compiler/arm64/instruction-codes-arm64.h b/src/compiler/arm64/instruction-codes-arm64.h index 863451f7c5..bbac27873c 100644 --- a/src/compiler/arm64/instruction-codes-arm64.h +++ b/src/compiler/arm64/instruction-codes-arm64.h @@ -94,6 +94,10 @@ namespace compiler { V(Arm64Float64ToUint32) \ V(Arm64Int32ToFloat64) \ V(Arm64Uint32ToFloat64) \ + V(Arm64Float64ExtractLowWord32) \ + V(Arm64Float64ExtractHighWord32) \ + V(Arm64Float64InsertLowWord32) \ + V(Arm64Float64InsertHighWord32) \ V(Arm64LdrS) \ V(Arm64StrS) \ V(Arm64LdrD) \ diff --git a/src/compiler/arm64/instruction-selector-arm64.cc b/src/compiler/arm64/instruction-selector-arm64.cc index 1a071cd2d8..a27bd88733 100644 --- a/src/compiler/arm64/instruction-selector-arm64.cc +++ b/src/compiler/arm64/instruction-selector-arm64.cc @@ -1576,6 +1576,40 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { } +void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) { + Arm64OperandGenerator g(this); + Emit(kArm64Float64ExtractLowWord32, g.DefineAsRegister(node), + g.UseRegister(node->InputAt(0))); +} + + +void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) { + Arm64OperandGenerator g(this); + Emit(kArm64Float64ExtractHighWord32, g.DefineAsRegister(node), + g.UseRegister(node->InputAt(0))); +} + + +void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) { + // TODO(arm64): Some AArch64 specialist should be able to improve this. + Arm64OperandGenerator g(this); + Node* left = node->InputAt(0); + Node* right = node->InputAt(1); + Emit(kArm64Float64InsertLowWord32, g.DefineAsRegister(node), + g.UseRegister(left), g.UseRegister(right)); +} + + +void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) { + // TODO(arm64): Some AArch64 specialist should be able to improve this. + Arm64OperandGenerator g(this); + Node* left = node->InputAt(0); + Node* right = node->InputAt(1); + Emit(kArm64Float64InsertHighWord32, g.DefineAsRegister(node), + g.UseRegister(left), g.UseRegister(right)); +} + + // static MachineOperatorBuilder::Flags InstructionSelector::SupportedMachineOperatorFlags() { diff --git a/src/compiler/ia32/code-generator-ia32.cc b/src/compiler/ia32/code-generator-ia32.cc index d86151e616..fcea57f93e 100644 --- a/src/compiler/ia32/code-generator-ia32.cc +++ b/src/compiler/ia32/code-generator-ia32.cc @@ -24,8 +24,8 @@ class IA32OperandConverter : public InstructionOperandConverter { IA32OperandConverter(CodeGenerator* gen, Instruction* instr) : InstructionOperandConverter(gen, instr) {} - Operand InputOperand(size_t index) { - return ToOperand(instr_->InputAt(index)); + Operand InputOperand(size_t index, int extra = 0) { + return ToOperand(instr_->InputAt(index), extra); } Immediate InputImmediate(size_t index) { @@ -531,6 +531,29 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { case kSSEUint32ToFloat64: __ LoadUint32(i.OutputDoubleRegister(), i.InputOperand(0)); break; + case kSSEFloat64ExtractLowWord32: + if (instr->InputAt(0)->IsDoubleStackSlot()) { + __ mov(i.OutputRegister(), i.InputOperand(0)); + } else { + __ movd(i.OutputRegister(), i.InputDoubleRegister(0)); + } + break; + case kSSEFloat64ExtractHighWord32: + if (instr->InputAt(0)->IsDoubleStackSlot()) { + __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2)); + } else { + __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1); + } + break; + case kSSEFloat64InsertLowWord32: + __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0); + break; + case kSSEFloat64InsertHighWord32: + __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1); + break; + case kSSEFloat64LoadLowWord32: + __ movd(i.OutputDoubleRegister(), i.InputOperand(0)); + break; case kAVXFloat64Add: { CpuFeatureScope avx_scope(masm(), AVX); __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), diff --git a/src/compiler/ia32/instruction-codes-ia32.h b/src/compiler/ia32/instruction-codes-ia32.h index ec9fd188fc..b5a5225adc 100644 --- a/src/compiler/ia32/instruction-codes-ia32.h +++ b/src/compiler/ia32/instruction-codes-ia32.h @@ -46,6 +46,11 @@ namespace compiler { V(SSEFloat64ToUint32) \ V(SSEInt32ToFloat64) \ V(SSEUint32ToFloat64) \ + V(SSEFloat64ExtractLowWord32) \ + V(SSEFloat64ExtractHighWord32) \ + V(SSEFloat64InsertLowWord32) \ + V(SSEFloat64InsertHighWord32) \ + V(SSEFloat64LoadLowWord32) \ V(AVXFloat64Add) \ V(AVXFloat64Sub) \ V(AVXFloat64Mul) \ diff --git a/src/compiler/ia32/instruction-selector-ia32.cc b/src/compiler/ia32/instruction-selector-ia32.cc index 8a352e2997..54184302c5 100644 --- a/src/compiler/ia32/instruction-selector-ia32.cc +++ b/src/compiler/ia32/instruction-selector-ia32.cc @@ -1068,6 +1068,43 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { } +void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) { + IA32OperandGenerator g(this); + Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node), + g.Use(node->InputAt(0))); +} + + +void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) { + IA32OperandGenerator g(this); + Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node), + g.Use(node->InputAt(0))); +} + + +void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) { + IA32OperandGenerator g(this); + Node* left = node->InputAt(0); + Node* right = node->InputAt(1); + Float64Matcher mleft(left); + if (mleft.HasValue() && (bit_cast(mleft.Value()) >> 32) == 0u) { + Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right)); + return; + } + Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node), + g.UseRegister(left), g.Use(right)); +} + + +void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) { + IA32OperandGenerator g(this); + Node* left = node->InputAt(0); + Node* right = node->InputAt(1); + Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node), + g.UseRegister(left), g.Use(right)); +} + + // static MachineOperatorBuilder::Flags InstructionSelector::SupportedMachineOperatorFlags() { diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index bffe6f7694..97fa9214f6 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc @@ -699,6 +699,12 @@ MachineType InstructionSelector::GetMachineType(Node* node) { case IrOpcode::kFloat64LessThan: case IrOpcode::kFloat64LessThanOrEqual: return kMachBool; + case IrOpcode::kFloat64ExtractLowWord32: + case IrOpcode::kFloat64ExtractHighWord32: + return kMachInt32; + case IrOpcode::kFloat64InsertLowWord32: + case IrOpcode::kFloat64InsertHighWord32: + return kMachFloat64; default: V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d", node->opcode(), node->op()->mnemonic(), node->id()); @@ -903,6 +909,14 @@ void InstructionSelector::VisitNode(Node* node) { return MarkAsDouble(node), VisitFloat64RoundTruncate(node); case IrOpcode::kFloat64RoundTiesAway: return MarkAsDouble(node), VisitFloat64RoundTiesAway(node); + case IrOpcode::kFloat64ExtractLowWord32: + return VisitFloat64ExtractLowWord32(node); + case IrOpcode::kFloat64ExtractHighWord32: + return VisitFloat64ExtractHighWord32(node); + case IrOpcode::kFloat64InsertLowWord32: + return MarkAsDouble(node), VisitFloat64InsertLowWord32(node); + case IrOpcode::kFloat64InsertHighWord32: + return MarkAsDouble(node), VisitFloat64InsertHighWord32(node); case IrOpcode::kLoadStackPointer: return VisitLoadStackPointer(node); case IrOpcode::kCheckedLoad: { diff --git a/src/compiler/js-intrinsic-lowering.cc b/src/compiler/js-intrinsic-lowering.cc index 87e74b73d9..0d3b3e642e 100644 --- a/src/compiler/js-intrinsic-lowering.cc +++ b/src/compiler/js-intrinsic-lowering.cc @@ -31,6 +31,12 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) { return ReduceInlineIsInstanceType(node, JS_ARRAY_TYPE); case Runtime::kInlineIsFunction: return ReduceInlineIsInstanceType(node, JS_FUNCTION_TYPE); + case Runtime::kInlineOptimizedConstructDouble: + return ReduceInlineOptimizedConstructDouble(node); + case Runtime::kInlineOptimizedDoubleLo: + return ReduceInlineOptimizedDoubleLo(node); + case Runtime::kInlineOptimizedDoubleHi: + return ReduceInlineOptimizedDoubleHi(node); case Runtime::kInlineIsRegExp: return ReduceInlineIsInstanceType(node, JS_REGEXP_TYPE); case Runtime::kInlineValueOf: @@ -92,6 +98,30 @@ Reduction JSIntrinsicLowering::ReduceInlineIsNonNegativeSmi(Node* node) { } +Reduction JSIntrinsicLowering::ReduceInlineOptimizedConstructDouble( + Node* node) { + Node* high = NodeProperties::GetValueInput(node, 0); + Node* low = NodeProperties::GetValueInput(node, 1); + Node* value = + graph()->NewNode(machine()->Float64InsertHighWord32(), + graph()->NewNode(machine()->Float64InsertLowWord32(), + jsgraph()->Constant(0), low), + high); + NodeProperties::ReplaceWithValue(node, value); + return Replace(value); +} + + +Reduction JSIntrinsicLowering::ReduceInlineOptimizedDoubleLo(Node* node) { + return Change(node, machine()->Float64ExtractLowWord32()); +} + + +Reduction JSIntrinsicLowering::ReduceInlineOptimizedDoubleHi(Node* node) { + return Change(node, machine()->Float64ExtractHighWord32()); +} + + Reduction JSIntrinsicLowering::ReduceInlineIsInstanceType( Node* node, InstanceType instance_type) { // if (%_IsSmi(value)) { diff --git a/src/compiler/js-intrinsic-lowering.h b/src/compiler/js-intrinsic-lowering.h index d19c0f6121..d728c273f6 100644 --- a/src/compiler/js-intrinsic-lowering.h +++ b/src/compiler/js-intrinsic-lowering.h @@ -31,6 +31,9 @@ class JSIntrinsicLowering FINAL : public Reducer { Reduction ReduceInlineIsSmi(Node* node); Reduction ReduceInlineIsNonNegativeSmi(Node* node); Reduction ReduceInlineIsInstanceType(Node* node, InstanceType instance_type); + Reduction ReduceInlineOptimizedConstructDouble(Node* node); + Reduction ReduceInlineOptimizedDoubleLo(Node* node); + Reduction ReduceInlineOptimizedDoubleHi(Node* node); Reduction ReduceInlineValueOf(Node* node); Reduction Change(Node* node, const Operator* op); diff --git a/src/compiler/machine-operator-reducer.cc b/src/compiler/machine-operator-reducer.cc index 5630bc8ef0..ba0b7a1893 100644 --- a/src/compiler/machine-operator-reducer.cc +++ b/src/compiler/machine-operator-reducer.cc @@ -433,6 +433,10 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { if (m.IsChangeFloat32ToFloat64()) return Replace(m.node()->InputAt(0)); break; } + case IrOpcode::kFloat64InsertLowWord32: + return ReduceFloat64InsertLowWord32(node); + case IrOpcode::kFloat64InsertHighWord32: + return ReduceFloat64InsertHighWord32(node); case IrOpcode::kStore: return ReduceStore(node); default: @@ -975,6 +979,32 @@ Reduction MachineOperatorReducer::ReduceWord32Or(Node* node) { } +Reduction MachineOperatorReducer::ReduceFloat64InsertLowWord32(Node* node) { + DCHECK_EQ(IrOpcode::kFloat64InsertLowWord32, node->opcode()); + Float64Matcher mlhs(node->InputAt(0)); + Uint32Matcher mrhs(node->InputAt(1)); + if (mlhs.HasValue() && mrhs.HasValue()) { + return ReplaceFloat64(bit_cast( + (bit_cast(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF00000000)) | + mrhs.Value())); + } + return NoChange(); +} + + +Reduction MachineOperatorReducer::ReduceFloat64InsertHighWord32(Node* node) { + DCHECK_EQ(IrOpcode::kFloat64InsertHighWord32, node->opcode()); + Float64Matcher mlhs(node->InputAt(0)); + Uint32Matcher mrhs(node->InputAt(1)); + if (mlhs.HasValue() && mrhs.HasValue()) { + return ReplaceFloat64(bit_cast( + (bit_cast(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF)) | + (static_cast(mrhs.Value()) << 32))); + } + return NoChange(); +} + + CommonOperatorBuilder* MachineOperatorReducer::common() const { return jsgraph()->common(); } diff --git a/src/compiler/machine-operator-reducer.h b/src/compiler/machine-operator-reducer.h index f7c3bd7cfd..7c41f143e2 100644 --- a/src/compiler/machine-operator-reducer.h +++ b/src/compiler/machine-operator-reducer.h @@ -78,6 +78,8 @@ class MachineOperatorReducer FINAL : public Reducer { Reduction ReduceWord32Sar(Node* node); Reduction ReduceWord32And(Node* node); Reduction ReduceWord32Or(Node* node); + Reduction ReduceFloat64InsertLowWord32(Node* node); + Reduction ReduceFloat64InsertHighWord32(Node* node); Graph* graph() const; JSGraph* jsgraph() const { return jsgraph_; } diff --git a/src/compiler/machine-operator.cc b/src/compiler/machine-operator.cc index 2522a8e15d..6122eb1440 100644 --- a/src/compiler/machine-operator.cc +++ b/src/compiler/machine-operator.cc @@ -130,6 +130,10 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) { V(Float64Equal, Operator::kCommutative, 2, 0, 1) \ V(Float64LessThan, Operator::kNoProperties, 2, 0, 1) \ V(Float64LessThanOrEqual, Operator::kNoProperties, 2, 0, 1) \ + V(Float64ExtractLowWord32, Operator::kNoProperties, 1, 0, 1) \ + V(Float64ExtractHighWord32, Operator::kNoProperties, 1, 0, 1) \ + V(Float64InsertLowWord32, Operator::kNoProperties, 2, 0, 1) \ + V(Float64InsertHighWord32, Operator::kNoProperties, 2, 0, 1) \ V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1) diff --git a/src/compiler/machine-operator.h b/src/compiler/machine-operator.h index 42f313019f..e92f3c64f6 100644 --- a/src/compiler/machine-operator.h +++ b/src/compiler/machine-operator.h @@ -177,6 +177,12 @@ class MachineOperatorBuilder FINAL : public ZoneObject { bool HasFloat64RoundTruncate() { return flags_ & kFloat64RoundTruncate; } bool HasFloat64RoundTiesAway() { return flags_ & kFloat64RoundTiesAway; } + // Floating point bit representation. + const Operator* Float64ExtractLowWord32(); + const Operator* Float64ExtractHighWord32(); + const Operator* Float64InsertLowWord32(); + const Operator* Float64InsertHighWord32(); + // load [base + index] const Operator* Load(LoadRepresentation rep); @@ -226,10 +232,10 @@ class MachineOperatorBuilder FINAL : public ZoneObject { #undef PSEUDO_OP_LIST private: - Zone* zone_; - const MachineOperatorGlobalCache& cache_; - const MachineType word_; - const Flags flags_; + Zone* const zone_; + MachineOperatorGlobalCache const& cache_; + MachineType const word_; + Flags const flags_; DISALLOW_COPY_AND_ASSIGN(MachineOperatorBuilder); }; diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index 6e9e1fb8f9..5343c2f1c2 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -252,6 +252,10 @@ V(Float64Ceil) \ V(Float64RoundTruncate) \ V(Float64RoundTiesAway) \ + V(Float64ExtractLowWord32) \ + V(Float64ExtractHighWord32) \ + V(Float64InsertLowWord32) \ + V(Float64InsertHighWord32) \ V(LoadStackPointer) \ V(CheckedLoad) \ V(CheckedStore) diff --git a/src/compiler/raw-machine-assembler.h b/src/compiler/raw-machine-assembler.h index 04b1dc6f57..693f2fc87b 100644 --- a/src/compiler/raw-machine-assembler.h +++ b/src/compiler/raw-machine-assembler.h @@ -393,6 +393,20 @@ class RawMachineAssembler : public GraphBuilder { return NewNode(machine()->Float64RoundTiesAway(), a); } + // Float64 bit operations. + Node* Float64ExtractLowWord32(Node* a) { + return NewNode(machine()->Float64ExtractLowWord32(), a); + } + Node* Float64ExtractHighWord32(Node* a) { + return NewNode(machine()->Float64ExtractHighWord32(), a); + } + Node* Float64InsertLowWord32(Node* a, Node* b) { + return NewNode(machine()->Float64InsertLowWord32(), a, b); + } + Node* Float64InsertHighWord32(Node* a, Node* b) { + return NewNode(machine()->Float64InsertHighWord32(), a, b); + } + // Parameters. Node* Parameter(size_t index); diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index 9e0b450166..a757248a99 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -273,13 +273,19 @@ class RepresentationSelector { SetOutput(node, kMachAnyTagged); } + // Helper for binops of the R x L -> O variety. + void VisitBinop(Node* node, MachineTypeUnion left_use, + MachineTypeUnion right_use, MachineTypeUnion output) { + DCHECK_EQ(2, node->InputCount()); + ProcessInput(node, 0, left_use); + ProcessInput(node, 1, right_use); + SetOutput(node, output); + } + // Helper for binops of the I x I -> O variety. void VisitBinop(Node* node, MachineTypeUnion input_use, MachineTypeUnion output) { - DCHECK_EQ(2, node->InputCount()); - ProcessInput(node, 0, input_use); - ProcessInput(node, 1, input_use); - SetOutput(node, output); + VisitBinop(node, input_use, input_use, output); } // Helper for unops of the I -> O variety. @@ -1033,6 +1039,12 @@ class RepresentationSelector { case IrOpcode::kFloat64LessThan: case IrOpcode::kFloat64LessThanOrEqual: return VisitFloat64Cmp(node); + case IrOpcode::kFloat64ExtractLowWord32: + case IrOpcode::kFloat64ExtractHighWord32: + return VisitUnop(node, kMachFloat64, kMachInt32); + case IrOpcode::kFloat64InsertLowWord32: + case IrOpcode::kFloat64InsertHighWord32: + return VisitBinop(node, kMachFloat64, kMachInt32, kMachFloat64); case IrOpcode::kLoadStackPointer: return VisitLeaf(node, kMachPtr); case IrOpcode::kStateValues: diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 25597eec65..e11730e6e5 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -1506,6 +1506,11 @@ Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) { case Runtime::kInlineIsFunction: case Runtime::kInlineIsRegExp: return Bounds(Type::None(zone()), Type::Boolean(zone())); + case Runtime::kInlineOptimizedDoubleLo: + case Runtime::kInlineOptimizedDoubleHi: + return Bounds(Type::None(zone()), Type::Signed32()); + case Runtime::kInlineOptimizedConstructDouble: + return Bounds(Type::None(zone()), Type::Number()); default: break; } @@ -2098,6 +2103,26 @@ Bounds Typer::Visitor::TypeFloat64RoundTiesAway(Node* node) { } +Bounds Typer::Visitor::TypeFloat64ExtractLowWord32(Node* node) { + return Bounds(Type::Signed32()); +} + + +Bounds Typer::Visitor::TypeFloat64ExtractHighWord32(Node* node) { + return Bounds(Type::Signed32()); +} + + +Bounds Typer::Visitor::TypeFloat64InsertLowWord32(Node* node) { + return Bounds(Type::Number()); +} + + +Bounds Typer::Visitor::TypeFloat64InsertHighWord32(Node* node) { + return Bounds(Type::Number()); +} + + Bounds Typer::Visitor::TypeLoadStackPointer(Node* node) { return Bounds(Type::Internal()); } diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index b502621d50..77e13e7d6a 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -805,13 +805,17 @@ void Verifier::Visitor::Check(Node* node) { case IrOpcode::kChangeFloat32ToFloat64: case IrOpcode::kChangeFloat64ToInt32: case IrOpcode::kChangeFloat64ToUint32: + case IrOpcode::kFloat64ExtractLowWord32: + case IrOpcode::kFloat64ExtractHighWord32: + case IrOpcode::kFloat64InsertLowWord32: + case IrOpcode::kFloat64InsertHighWord32: case IrOpcode::kLoadStackPointer: case IrOpcode::kCheckedLoad: case IrOpcode::kCheckedStore: // TODO(rossberg): Check. break; } -} +} // NOLINT(readability/fn_size) void Verifier::Run(Graph* graph, Typing typing) { diff --git a/src/compiler/x64/code-generator-x64.cc b/src/compiler/x64/code-generator-x64.cc index 8bb0d6c936..b808e4e893 100644 --- a/src/compiler/x64/code-generator-x64.cc +++ b/src/compiler/x64/code-generator-x64.cc @@ -18,6 +18,9 @@ namespace compiler { #define __ masm()-> +#define kScratchDoubleReg xmm0 + + // Adds X64 specific methods for decoding operands. class X64OperandConverter : public InstructionOperandConverter { public: @@ -28,8 +31,8 @@ class X64OperandConverter : public InstructionOperandConverter { return ToImmediate(instr_->InputAt(index)); } - Operand InputOperand(size_t index) { - return ToOperand(instr_->InputAt(index)); + Operand InputOperand(size_t index, int extra = 0) { + return ToOperand(instr_->InputAt(index), extra); } Operand OutputOperand() { return ToOperand(instr_->Output()); } @@ -808,6 +811,41 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { } __ cvtqsi2sd(i.OutputDoubleRegister(), kScratchRegister); break; + case kSSEFloat64ExtractLowWord32: + if (instr->InputAt(0)->IsDoubleStackSlot()) { + __ movl(i.OutputRegister(), i.InputOperand(0)); + } else { + __ movd(i.OutputRegister(), i.InputDoubleRegister(0)); + } + break; + case kSSEFloat64ExtractHighWord32: + if (instr->InputAt(0)->IsDoubleStackSlot()) { + __ movl(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2)); + } else { + __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1); + } + break; + case kSSEFloat64InsertLowWord32: + if (instr->InputAt(1)->IsRegister()) { + __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 0); + } else { + __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0); + } + break; + case kSSEFloat64InsertHighWord32: + if (instr->InputAt(1)->IsRegister()) { + __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 1); + } else { + __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1); + } + break; + case kSSEFloat64LoadLowWord32: + if (instr->InputAt(0)->IsRegister()) { + __ movd(i.OutputDoubleRegister(), i.InputRegister(0)); + } else { + __ movd(i.OutputDoubleRegister(), i.InputOperand(0)); + } + break; case kAVXFloat64Add: ASSEMBLE_AVX_DOUBLE_BINOP(vaddsd); break; @@ -1014,7 +1052,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ASSEMBLE_CHECKED_STORE_FLOAT(movsd); break; } -} +} // NOLINT(readability/fn_size) // Assembles branches after this instruction. diff --git a/src/compiler/x64/instruction-codes-x64.h b/src/compiler/x64/instruction-codes-x64.h index 77e3e52158..6af32b0191 100644 --- a/src/compiler/x64/instruction-codes-x64.h +++ b/src/compiler/x64/instruction-codes-x64.h @@ -62,6 +62,11 @@ namespace compiler { V(SSEFloat64ToUint32) \ V(SSEInt32ToFloat64) \ V(SSEUint32ToFloat64) \ + V(SSEFloat64ExtractLowWord32) \ + V(SSEFloat64ExtractHighWord32) \ + V(SSEFloat64InsertLowWord32) \ + V(SSEFloat64InsertHighWord32) \ + V(SSEFloat64LoadLowWord32) \ V(AVXFloat64Add) \ V(AVXFloat64Sub) \ V(AVXFloat64Mul) \ diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc index 5c63f63301..b00eee16da 100644 --- a/src/compiler/x64/instruction-selector-x64.cc +++ b/src/compiler/x64/instruction-selector-x64.cc @@ -1371,6 +1371,43 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { } +void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) { + X64OperandGenerator g(this); + Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node), + g.Use(node->InputAt(0))); +} + + +void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) { + X64OperandGenerator g(this); + Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node), + g.Use(node->InputAt(0))); +} + + +void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) { + X64OperandGenerator g(this); + Node* left = node->InputAt(0); + Node* right = node->InputAt(1); + Float64Matcher mleft(left); + if (mleft.HasValue() && (bit_cast(mleft.Value()) >> 32) == 0u) { + Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right)); + return; + } + Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node), + g.UseRegister(left), g.Use(right)); +} + + +void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) { + X64OperandGenerator g(this); + Node* left = node->InputAt(0); + Node* right = node->InputAt(1); + Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node), + g.UseRegister(left), g.Use(right)); +} + + // static MachineOperatorBuilder::Flags InstructionSelector::SupportedMachineOperatorFlags() { diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc index 4be27ceeab..05d1bdd4f2 100644 --- a/src/ia32/assembler-ia32.cc +++ b/src/ia32/assembler-ia32.cc @@ -2217,6 +2217,24 @@ void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) { } +void Assembler::punpckldq(XMMRegister dst, XMMRegister src) { + EnsureSpace ensure_space(this); + EMIT(0x66); + EMIT(0x0F); + EMIT(0x62); + emit_sse_operand(dst, src); +} + + +void Assembler::punpckhdq(XMMRegister dst, XMMRegister src) { + EnsureSpace ensure_space(this); + EMIT(0x66); + EMIT(0x0F); + EMIT(0x6A); + emit_sse_operand(dst, src); +} + + void Assembler::cmpltsd(XMMRegister dst, XMMRegister src) { EnsureSpace ensure_space(this); EMIT(0xF2); diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h index ea5a7e2593..41b83481b2 100644 --- a/src/ia32/assembler-ia32.h +++ b/src/ia32/assembler-ia32.h @@ -1018,6 +1018,9 @@ class Assembler : public AssemblerBase { void cmpltsd(XMMRegister dst, XMMRegister src); void pcmpeqd(XMMRegister dst, XMMRegister src); + void punpckldq(XMMRegister dst, XMMRegister src); + void punpckhdq(XMMRegister dst, XMMRegister src); + void movdqa(XMMRegister dst, const Operand& src); void movdqa(const Operand& dst, XMMRegister src); void movdqu(XMMRegister dst, const Operand& src); diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc index 576c7393cc..08ffdde5b4 100644 --- a/src/ia32/disasm-ia32.cc +++ b/src/ia32/disasm-ia32.cc @@ -1554,6 +1554,20 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector out_buffer, NameOfXMMRegister(rm), static_cast(imm8)); data += 2; + } else if (*data == 0x62) { + data++; + int mod, regop, rm; + get_modrm(*data, &mod, ®op, &rm); + AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop), + NameOfXMMRegister(rm)); + data++; + } else if (*data == 0x6A) { + data++; + int mod, regop, rm; + get_modrm(*data, &mod, ®op, &rm); + AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop), + NameOfXMMRegister(rm)); + data++; } else if (*data == 0x76) { data++; int mod, regop, rm; diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index 81c765e7db..3c0061f3e5 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -2441,6 +2441,41 @@ void MacroAssembler::Move(XMMRegister dst, uint64_t src) { } +void MacroAssembler::Pextrd(Register dst, XMMRegister src, int8_t imm8) { + if (imm8 == 0) { + movd(dst, src); + return; + } + DCHECK_EQ(1, imm8); + if (CpuFeatures::IsSupported(SSE4_1)) { + CpuFeatureScope sse_scope(this, SSE4_1); + pextrd(dst, src, imm8); + return; + } + pshufd(xmm0, src, 1); + movd(dst, src); +} + + +void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) { + DCHECK(imm8 == 0 || imm8 == 1); + if (CpuFeatures::IsSupported(SSE4_1)) { + CpuFeatureScope sse_scope(this, SSE4_1); + pinsrd(dst, src, imm8); + return; + } + movd(xmm0, src); + if (imm8 == 1) { + punpckldq(dst, xmm0); + } else { + DCHECK_EQ(0, imm8); + psrlq(dst, 32); + punpckldq(xmm0, dst); + movaps(dst, xmm0); + } +} + + void MacroAssembler::SetCounter(StatsCounter* counter, int value) { if (FLAG_native_code_counters && counter->Enabled()) { mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value)); diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index 2f1354bbf9..8c135f2b60 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -813,6 +813,13 @@ class MacroAssembler: public Assembler { void Push(Register src) { push(src); } void Pop(Register dst) { pop(dst); } + // Non-SSE2 instructions. + void Pextrd(Register dst, XMMRegister src, int8_t imm8); + void Pinsrd(XMMRegister dst, Register src, int8_t imm8) { + Pinsrd(dst, Operand(src), imm8); + } + void Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8); + // Emit call to the code we are currently generating. void CallSelf() { Handle self(reinterpret_cast(CodeObject().location())); diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc index 697a6fa822..5b09bc2042 100644 --- a/src/x64/assembler-x64.cc +++ b/src/x64/assembler-x64.cc @@ -2529,6 +2529,16 @@ void Assembler::movd(XMMRegister dst, Register src) { } +void Assembler::movd(XMMRegister dst, const Operand& src) { + EnsureSpace ensure_space(this); + emit(0x66); + emit_optional_rex_32(dst, src); + emit(0x0F); + emit(0x6E); + emit_sse_operand(dst, src); +} + + void Assembler::movd(Register dst, XMMRegister src) { EnsureSpace ensure_space(this); emit(0x66); @@ -2632,6 +2642,45 @@ void Assembler::extractps(Register dst, XMMRegister src, byte imm8) { } +void Assembler::pextrd(Register dst, XMMRegister src, int8_t imm8) { + DCHECK(IsEnabled(SSE4_1)); + EnsureSpace ensure_space(this); + emit(0x66); + emit_optional_rex_32(src, dst); + emit(0x0F); + emit(0x3A); + emit(0x16); + emit_sse_operand(src, dst); + emit(imm8); +} + + +void Assembler::pinsrd(XMMRegister dst, Register src, int8_t imm8) { + DCHECK(IsEnabled(SSE4_1)); + EnsureSpace ensure_space(this); + emit(0x66); + emit_optional_rex_32(dst, src); + emit(0x0F); + emit(0x3A); + emit(0x22); + emit_sse_operand(dst, src); + emit(imm8); +} + + +void Assembler::pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) { + DCHECK(IsEnabled(SSE4_1)); + EnsureSpace ensure_space(this); + emit(0x66); + emit_optional_rex_32(dst, src); + emit(0x0F); + emit(0x3A); + emit(0x22); + emit_sse_operand(dst, src); + emit(imm8); +} + + void Assembler::movsd(const Operand& dst, XMMRegister src) { EnsureSpace ensure_space(this); emit(0xF2); // double @@ -3246,6 +3295,26 @@ void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) { } +void Assembler::punpckldq(XMMRegister dst, XMMRegister src) { + EnsureSpace ensure_space(this); + emit(0x66); + emit_optional_rex_32(dst, src); + emit(0x0F); + emit(0x62); + emit_sse_operand(dst, src); +} + + +void Assembler::punpckhdq(XMMRegister dst, XMMRegister src) { + EnsureSpace ensure_space(this); + emit(0x66); + emit_optional_rex_32(dst, src); + emit(0x0F); + emit(0x6A); + emit_sse_operand(dst, src); +} + + // AVX instructions void Assembler::vfmasd(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2) { diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h index 96715d1394..9c52b77268 100644 --- a/src/x64/assembler-x64.h +++ b/src/x64/assembler-x64.h @@ -1064,6 +1064,7 @@ class Assembler : public AssemblerBase { // SSE2 instructions void movd(XMMRegister dst, Register src); + void movd(XMMRegister dst, const Operand& src); void movd(Register dst, XMMRegister src); void movq(XMMRegister dst, Register src); void movq(Register dst, XMMRegister src); @@ -1132,9 +1133,17 @@ class Assembler : public AssemblerBase { void movmskpd(Register dst, XMMRegister src); + void punpckldq(XMMRegister dst, XMMRegister src); + void punpckhdq(XMMRegister dst, XMMRegister src); + // SSE 4.1 instruction void extractps(Register dst, XMMRegister src, byte imm8); + void pextrd(Register dst, XMMRegister src, int8_t imm8); + + void pinsrd(XMMRegister dst, Register src, int8_t imm8); + void pinsrd(XMMRegister dst, const Operand& src, int8_t imm8); + enum RoundingMode { kRoundToNearest = 0x0, kRoundDown = 0x1, diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc index bed99d101a..ba33da779c 100644 --- a/src/x64/disasm-x64.cc +++ b/src/x64/disasm-x64.cc @@ -1179,6 +1179,19 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { current += PrintRightXMMOperand(current); AppendToBuffer(",%d", (*current) & 3); current += 1; + } else if (third_byte == 0x16) { + get_modrm(*current, &mod, ®op, &rm); + AppendToBuffer("pextrd "); // reg/m32, xmm, imm8 + current += PrintRightOperand(current); + AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3); + current += 1; + } else if (third_byte == 0x22) { + get_modrm(*current, &mod, ®op, &rm); + AppendToBuffer("pinsrd "); // xmm, reg/m32, imm8 + AppendToBuffer(" %s,", NameOfXMMRegister(regop)); + current += PrintRightOperand(current); + AppendToBuffer(",%d", (*current) & 3); + current += 1; } else { UnimplementedInstruction(); } @@ -1229,12 +1242,12 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { current += PrintRightXMMOperand(current); } else if (opcode == 0x72) { current += 1; - AppendToBuffer("%s,%s,%d", (regop == 6) ? "pslld" : "psrld", + AppendToBuffer("%s %s,%d", (regop == 6) ? "pslld" : "psrld", NameOfXMMRegister(rm), *current & 0x7f); current += 1; } else if (opcode == 0x73) { current += 1; - AppendToBuffer("%s,%s,%d", (regop == 6) ? "psllq" : "psrlq", + AppendToBuffer("%s %s,%d", (regop == 6) ? "psllq" : "psrlq", NameOfXMMRegister(rm), *current & 0x7f); current += 1; } else { @@ -1251,6 +1264,10 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { mnemonic = "comisd"; } else if (opcode == 0x76) { mnemonic = "pcmpeqd"; + } else if (opcode == 0x62) { + mnemonic = "punpckldq"; + } else if (opcode == 0x6A) { + mnemonic = "punpckhdq"; } else { UnimplementedInstruction(); } diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 8e4448d46f..e4203618fc 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -2832,6 +2832,59 @@ void MacroAssembler::Call(Handle code_object, } +void MacroAssembler::Pextrd(Register dst, XMMRegister src, int8_t imm8) { + if (imm8 == 0) { + movd(dst, src); + return; + } + DCHECK_EQ(1, imm8); + if (CpuFeatures::IsSupported(SSE4_1)) { + CpuFeatureScope sse_scope(this, SSE4_1); + pextrd(dst, src, imm8); + return; + } + movq(dst, src); + shrq(dst, Immediate(32)); +} + + +void MacroAssembler::Pinsrd(XMMRegister dst, Register src, int8_t imm8) { + if (CpuFeatures::IsSupported(SSE4_1)) { + CpuFeatureScope sse_scope(this, SSE4_1); + pinsrd(dst, src, imm8); + return; + } + movd(xmm0, src); + if (imm8 == 1) { + punpckldq(dst, xmm0); + } else { + DCHECK_EQ(0, imm8); + psrlq(dst, 32); + punpckldq(xmm0, dst); + movaps(dst, xmm0); + } +} + + +void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) { + DCHECK(imm8 == 0 || imm8 == 1); + if (CpuFeatures::IsSupported(SSE4_1)) { + CpuFeatureScope sse_scope(this, SSE4_1); + pinsrd(dst, src, imm8); + return; + } + movd(xmm0, src); + if (imm8 == 1) { + punpckldq(dst, xmm0); + } else { + DCHECK_EQ(0, imm8); + psrlq(dst, 32); + punpckldq(xmm0, dst); + movaps(dst, xmm0); + } +} + + void MacroAssembler::Pushad() { Push(rax); Push(rcx); diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index 47651e2620..1eb7f6effe 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -922,6 +922,11 @@ class MacroAssembler: public Assembler { Call(self, RelocInfo::CODE_TARGET); } + // Non-SSE2 instructions. + void Pextrd(Register dst, XMMRegister src, int8_t imm8); + void Pinsrd(XMMRegister dst, Register src, int8_t imm8); + void Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8); + // Non-x64 instructions. // Push/pop all general purpose registers. // Does not push rsp/rbp nor any of the assembler's special purpose registers diff --git a/test/cctest/compiler/test-run-machops.cc b/test/cctest/compiler/test-run-machops.cc index a7b1768d2a..4e30bec9c3 100644 --- a/test/cctest/compiler/test-run-machops.cc +++ b/test/cctest/compiler/test-run-machops.cc @@ -4647,6 +4647,72 @@ TEST(RunFloat32Constant) { } +TEST(RunFloat64ExtractLowWord32) { + uint64_t input = 0; + RawMachineAssemblerTester m; + m.Return(m.Float64ExtractLowWord32(m.LoadFromPointer(&input, kMachFloat64))); + FOR_FLOAT64_INPUTS(i) { + input = bit_cast(*i); + int32_t expected = bit_cast(static_cast(input)); + CHECK_EQ(expected, m.Call()); + } +} + + +TEST(RunFloat64ExtractHighWord32) { + uint64_t input = 0; + RawMachineAssemblerTester m; + m.Return(m.Float64ExtractHighWord32(m.LoadFromPointer(&input, kMachFloat64))); + FOR_FLOAT64_INPUTS(i) { + input = bit_cast(*i); + int32_t expected = bit_cast(static_cast(input >> 32)); + CHECK_EQ(expected, m.Call()); + } +} + + +TEST(RunFloat64InsertLowWord32) { + uint64_t input = 0; + uint64_t result = 0; + RawMachineAssemblerTester m(kMachInt32); + m.StoreToPointer( + &result, kMachFloat64, + m.Float64InsertLowWord32(m.LoadFromPointer(&input, kMachFloat64), + m.Parameter(0))); + m.Return(m.Int32Constant(0)); + FOR_FLOAT64_INPUTS(i) { + FOR_INT32_INPUTS(j) { + input = bit_cast(*i); + uint64_t expected = (input & ~(V8_UINT64_C(0xFFFFFFFF))) | + (static_cast(bit_cast(*j))); + CHECK_EQ(0, m.Call(*j)); + CHECK_EQ(expected, result); + } + } +} + + +TEST(RunFloat64InsertHighWord32) { + uint64_t input = 0; + uint64_t result = 0; + RawMachineAssemblerTester m(kMachInt32); + m.StoreToPointer( + &result, kMachFloat64, + m.Float64InsertHighWord32(m.LoadFromPointer(&input, kMachFloat64), + m.Parameter(0))); + m.Return(m.Int32Constant(0)); + FOR_FLOAT64_INPUTS(i) { + FOR_INT32_INPUTS(j) { + input = bit_cast(*i); + uint64_t expected = (input & ~(V8_UINT64_C(0xFFFFFFFF) << 32)) | + (static_cast(bit_cast(*j)) << 32); + CHECK_EQ(0, m.Call(*j)); + CHECK_EQ(expected, result); + } + } +} + + static double two_30 = 1 << 30; // 2^30 is a smi boundary. static double two_52 = two_30 * (1 << 22); // 2^52 is a precision boundary. static double kValues[] = {0.1, diff --git a/test/cctest/test-disasm-ia32.cc b/test/cctest/test-disasm-ia32.cc index a2eaa15ed3..215ca76c1d 100644 --- a/test/cctest/test-disasm-ia32.cc +++ b/test/cctest/test-disasm-ia32.cc @@ -451,6 +451,11 @@ TEST(DisasmIa320) { __ psrlq(xmm0, 17); __ psrlq(xmm0, xmm1); __ por(xmm0, xmm1); + + __ pcmpeqd(xmm1, xmm0); + + __ punpckldq(xmm1, xmm6); + __ punpckhdq(xmm7, xmm5); } // cmov. diff --git a/test/cctest/test-disasm-x64.cc b/test/cctest/test-disasm-x64.cc index 6cd58ec209..3b78b640ae 100644 --- a/test/cctest/test-disasm-x64.cc +++ b/test/cctest/test-disasm-x64.cc @@ -446,6 +446,9 @@ TEST(DisasmX64) { __ psrlq(xmm0, 6); __ pcmpeqd(xmm1, xmm0); + + __ punpckldq(xmm1, xmm11); + __ punpckhdq(xmm8, xmm15); } // cmov. @@ -472,6 +475,10 @@ TEST(DisasmX64) { if (CpuFeatures::IsSupported(SSE4_1)) { CpuFeatureScope scope(&assm, SSE4_1); __ extractps(rax, xmm1, 0); + __ pextrd(rbx, xmm15, 0); + __ pextrd(r12, xmm0, 1); + __ pinsrd(xmm9, r9, 0); + __ pinsrd(xmm5, rax, 1); } } diff --git a/test/mjsunit/asm/construct-double.js b/test/mjsunit/asm/construct-double.js new file mode 100644 index 0000000000..8bb5000082 --- /dev/null +++ b/test/mjsunit/asm/construct-double.js @@ -0,0 +1,33 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +var stdlib = this; +var foreign = {}; +var heap = new ArrayBuffer(64 * 1024); + + +var m = (function(stdlib, foreign, heap) { + "use asm"; + function cd1(i, j) { + i = i|0; + j = j|0; + return +%_ConstructDouble(i, j); + } + function cd2(i) { + i = i|0; + return +%_ConstructDouble(0, i); + } + return { cd1: cd1, cd2: cd2 }; +})(stdlib, foreign, heap); + +assertEquals(0.0, m.cd1(0, 0)); +assertEquals(%ConstructDouble(0, 1), m.cd2(1)); +for (var i = -2147483648; i < 2147483648; i += 3999773) { + assertEquals(%ConstructDouble(0, i), m.cd2(i)); + for (var j = -2147483648; j < 2147483648; j += 3999773) { + assertEquals(%ConstructDouble(i, j), m.cd1(i, j)); + } +} diff --git a/test/mjsunit/asm/double-hi.js b/test/mjsunit/asm/double-hi.js new file mode 100644 index 0000000000..5a5f942f7b --- /dev/null +++ b/test/mjsunit/asm/double-hi.js @@ -0,0 +1,40 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +var stdlib = this; +var foreign = {}; +var heap = new ArrayBuffer(64 * 1024); + + +var m = (function(stdlib, foreign, heap) { + "use asm"; + function hi1(i) { + i = +i; + return %_DoubleHi(i)|0; + } + function hi2(i, j) { + i = +i; + j = +j; + return %_DoubleHi(i)+%_DoubleHi(j)|0; + } + return { hi1: hi1, hi2: hi2 }; +})(stdlib, foreign, heap); + +assertEquals(0, m.hi1(0.0)); +assertEquals(-2147483648, m.hi1(-0.0)); +assertEquals(2146435072, m.hi1(Infinity)); +assertEquals(-1048576, m.hi1(-Infinity)); +assertEquals(0, m.hi2(0.0, 0.0)); +assertEquals(-2147483648, m.hi2(0.0, -0.0)); +assertEquals(-2147483648, m.hi2(-0.0, 0.0)); +assertEquals(0, m.hi2(-0.0, -0.0)); +for (var i = -2147483648; i < 2147483648; i += 3999773) { + assertEquals(%_DoubleHi(i), m.hi1(i)); + assertEquals(i, m.hi1(%ConstructDouble(i, 0))); + assertEquals(i, m.hi1(%ConstructDouble(i, i))); + assertEquals(i+i|0, m.hi2(%ConstructDouble(i, 0), %ConstructDouble(i, 0))); + assertEquals(i+i|0, m.hi2(%ConstructDouble(i, i), %ConstructDouble(i, i))); +} diff --git a/test/mjsunit/asm/double-lo.js b/test/mjsunit/asm/double-lo.js new file mode 100644 index 0000000000..39d5b5268f --- /dev/null +++ b/test/mjsunit/asm/double-lo.js @@ -0,0 +1,40 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +var stdlib = this; +var foreign = {}; +var heap = new ArrayBuffer(64 * 1024); + + +var m = (function(stdlib, foreign, heap) { + "use asm"; + function lo1(i) { + i = +i; + return %_DoubleLo(i)|0; + } + function lo2(i, j) { + i = +i; + j = +j; + return %_DoubleLo(i)+%_DoubleLo(j)|0; + } + return { lo1: lo1, lo2: lo2 }; +})(stdlib, foreign, heap); + +assertEquals(0, m.lo1(0.0)); +assertEquals(0, m.lo1(-0.0)); +assertEquals(0, m.lo1(Infinity)); +assertEquals(0, m.lo1(-Infinity)); +assertEquals(0, m.lo2(0.0, 0.0)); +assertEquals(0, m.lo2(0.0, -0.0)); +assertEquals(0, m.lo2(-0.0, 0.0)); +assertEquals(0, m.lo2(-0.0, -0.0)); +for (var i = -2147483648; i < 2147483648; i += 3999773) { + assertEquals(%_DoubleLo(i), m.lo1(i)); + assertEquals(i, m.lo1(%ConstructDouble(0, i))); + assertEquals(i, m.lo1(%ConstructDouble(i, i))); + assertEquals(i+i|0, m.lo2(%ConstructDouble(0, i), %ConstructDouble(0, i))); + assertEquals(i+i|0, m.lo2(%ConstructDouble(i, i), %ConstructDouble(i, i))); +} diff --git a/test/unittests/compiler/js-intrinsic-lowering-unittest.cc b/test/unittests/compiler/js-intrinsic-lowering-unittest.cc index 20d5c069fe..7060a90cf7 100644 --- a/test/unittests/compiler/js-intrinsic-lowering-unittest.cc +++ b/test/unittests/compiler/js-intrinsic-lowering-unittest.cc @@ -41,6 +41,61 @@ class JSIntrinsicLoweringTest : public GraphTest { }; +// ----------------------------------------------------------------------------- +// %_ConstructDouble + + +TEST_F(JSIntrinsicLoweringTest, InlineOptimizedConstructDouble) { + Node* const input0 = Parameter(0); + Node* const input1 = Parameter(1); + Node* const context = Parameter(2); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce(graph()->NewNode( + javascript()->CallRuntime(Runtime::kInlineOptimizedConstructDouble, 2), + input0, input1, context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64InsertHighWord32( + IsFloat64InsertLowWord32( + IsNumberConstant(BitEq(0.0)), input1), + input0)); +} + + +// ----------------------------------------------------------------------------- +// %_DoubleLo + + +TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce(graph()->NewNode( + javascript()->CallRuntime(Runtime::kInlineOptimizedDoubleLo, 1), input, + context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64ExtractLowWord32(input)); +} + + +// ----------------------------------------------------------------------------- +// %_DoubleHi + + +TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleHi) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce(graph()->NewNode( + javascript()->CallRuntime(Runtime::kInlineOptimizedDoubleHi, 1), input, + context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64ExtractHighWord32(input)); +} + + // ----------------------------------------------------------------------------- // %_IsSmi diff --git a/test/unittests/compiler/machine-operator-reducer-unittest.cc b/test/unittests/compiler/machine-operator-reducer-unittest.cc index e41b015061..11c679cb29 100644 --- a/test/unittests/compiler/machine-operator-reducer-unittest.cc +++ b/test/unittests/compiler/machine-operator-reducer-unittest.cc @@ -1435,6 +1435,46 @@ TEST_F(MachineOperatorReducerTest, Float64MulWithMinusOne) { } +// ----------------------------------------------------------------------------- +// Float64InsertLowWord32 + + +TEST_F(MachineOperatorReducerTest, Float64InsertLowWord32WithConstant) { + TRACED_FOREACH(double, x, kFloat64Values) { + TRACED_FOREACH(uint32_t, y, kUint32Values) { + Reduction const r = + Reduce(graph()->NewNode(machine()->Float64InsertLowWord32(), + Float64Constant(x), Uint32Constant(y))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsFloat64Constant(BitEq(bit_cast( + (bit_cast(x) & V8_UINT64_C(0xFFFFFFFF00000000)) | y)))); + } + } +} + + +// ----------------------------------------------------------------------------- +// Float64InsertHighWord32 + + +TEST_F(MachineOperatorReducerTest, Float64InsertHighWord32WithConstant) { + TRACED_FOREACH(double, x, kFloat64Values) { + TRACED_FOREACH(uint32_t, y, kUint32Values) { + Reduction const r = + Reduce(graph()->NewNode(machine()->Float64InsertHighWord32(), + Float64Constant(x), Uint32Constant(y))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFloat64Constant(BitEq(bit_cast( + (bit_cast(x) & V8_UINT64_C(0xFFFFFFFF)) | + (static_cast(y) << 32))))); + } + } +} + + // ----------------------------------------------------------------------------- // Store diff --git a/test/unittests/compiler/machine-operator-unittest.cc b/test/unittests/compiler/machine-operator-unittest.cc index 6e0df2ab44..dc649e178e 100644 --- a/test/unittests/compiler/machine-operator-unittest.cc +++ b/test/unittests/compiler/machine-operator-unittest.cc @@ -206,7 +206,11 @@ const PureOperator kPureOperators[] = { PURE(Float64Equal, 2, 0, 1), PURE(Float64LessThan, 2, 0, 1), PURE(Float64LessThanOrEqual, 2, 0, 1), PURE(LoadStackPointer, 0, 0, 1), PURE(Float64Floor, 1, 0, 1), PURE(Float64Ceil, 1, 0, 1), - PURE(Float64RoundTruncate, 1, 0, 1), PURE(Float64RoundTiesAway, 1, 0, 1) + PURE(Float64RoundTruncate, 1, 0, 1), PURE(Float64RoundTiesAway, 1, 0, 1), + PURE(Float64ExtractLowWord32, 1, 0, 1), + PURE(Float64ExtractHighWord32, 1, 0, 1), + PURE(Float64InsertLowWord32, 2, 0, 1), + PURE(Float64InsertHighWord32, 2, 0, 1) #undef PURE }; diff --git a/test/unittests/compiler/node-test-utils.cc b/test/unittests/compiler/node-test-utils.cc index 7272314585..55771da928 100644 --- a/test/unittests/compiler/node-test-utils.cc +++ b/test/unittests/compiler/node-test-utils.cc @@ -1591,6 +1591,8 @@ IS_BINOP_MATCHER(Int32LessThan) IS_BINOP_MATCHER(Uint32LessThan) IS_BINOP_MATCHER(Uint32LessThanOrEqual) IS_BINOP_MATCHER(Float64Sub) +IS_BINOP_MATCHER(Float64InsertLowWord32) +IS_BINOP_MATCHER(Float64InsertHighWord32) #undef IS_BINOP_MATCHER @@ -1614,6 +1616,8 @@ IS_UNOP_MATCHER(Float64Floor) IS_UNOP_MATCHER(Float64Ceil) IS_UNOP_MATCHER(Float64RoundTruncate) IS_UNOP_MATCHER(Float64RoundTiesAway) +IS_UNOP_MATCHER(Float64ExtractLowWord32) +IS_UNOP_MATCHER(Float64ExtractHighWord32) IS_UNOP_MATCHER(NumberToInt32) IS_UNOP_MATCHER(NumberToUint32) IS_UNOP_MATCHER(ObjectIsSmi) diff --git a/test/unittests/compiler/node-test-utils.h b/test/unittests/compiler/node-test-utils.h index 2f28a94d1d..c1d580c56b 100644 --- a/test/unittests/compiler/node-test-utils.h +++ b/test/unittests/compiler/node-test-utils.h @@ -210,6 +210,12 @@ Matcher IsFloat64Floor(const Matcher& input_matcher); Matcher IsFloat64Ceil(const Matcher& input_matcher); Matcher IsFloat64RoundTruncate(const Matcher& input_matcher); Matcher IsFloat64RoundTiesAway(const Matcher& input_matcher); +Matcher IsFloat64ExtractLowWord32(const Matcher& input_matcher); +Matcher IsFloat64ExtractHighWord32(const Matcher& input_matcher); +Matcher IsFloat64InsertLowWord32(const Matcher& lhs_matcher, + const Matcher& rhs_matcher); +Matcher IsFloat64InsertHighWord32(const Matcher& lhs_matcher, + const Matcher& rhs_matcher); Matcher IsToNumber(const Matcher& base_matcher, const Matcher& context_matcher, const Matcher& effect_matcher,