From 4f15fd29775000689e1d70a0f64a0ab93bf50549 Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Fri, 7 Mar 2014 14:58:41 +0000 Subject: [PATCH] Reland "Introduce intrinsics for double values in Javascript." This relands r19704 with a fix to the test case. R=svenpanne@chromium.org Review URL: https://codereview.chromium.org/189823003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19723 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/a64/lithium-a64.cc | 15 ++++++++ src/a64/lithium-a64.h | 31 ++++++++++++++++ src/a64/lithium-codegen-a64.cc | 24 ++++++++++++ src/arm/lithium-arm.cc | 14 +++++++ src/arm/lithium-arm.h | 29 +++++++++++++++ src/arm/lithium-codegen-arm.cc | 20 ++++++++++ src/d8.gyp | 2 +- src/full-codegen.cc | 28 ++++++++++++++ src/hydrogen-instructions.h | 61 +++++++++++++++++++++++++++++++ src/hydrogen.cc | 29 +++++++++++++++ src/ia32/lithium-codegen-ia32.cc | 39 ++++++++++++++++++++ src/ia32/lithium-ia32.cc | 14 +++++++ src/ia32/lithium-ia32.h | 29 +++++++++++++++ src/runtime.cc | 29 +++++++++++++++ src/runtime.h | 5 ++- src/x64/assembler-x64.cc | 10 +++++ src/x64/assembler-x64.h | 2 + src/x64/disasm-x64.cc | 5 +++ src/x64/lithium-codegen-x64.cc | 24 ++++++++++++ src/x64/lithium-x64.cc | 14 +++++++ src/x64/lithium-x64.h | 29 +++++++++++++++ test/mjsunit/double-intrinsics.js | 36 ++++++++++++++++++ 22 files changed, 487 insertions(+), 2 deletions(-) create mode 100644 test/mjsunit/double-intrinsics.js diff --git a/src/a64/lithium-a64.cc b/src/a64/lithium-a64.cc index d2025fcb9..ae32e3653 100644 --- a/src/a64/lithium-a64.cc +++ b/src/a64/lithium-a64.cc @@ -1922,6 +1922,21 @@ LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) { } +LInstruction* LChunkBuilder::DoDoubleBits(HDoubleBits* instr) { + HValue* value = instr->value(); + ASSERT(value->representation().IsDouble()); + return DefineAsRegister(new(zone()) LDoubleBits(UseRegister(value))); +} + + +LInstruction* LChunkBuilder::DoConstructDouble(HConstructDouble* instr) { + LOperand* lo = UseRegister(instr->lo()); + LOperand* hi = UseRegister(instr->hi()); + LOperand* temp = TempRegister(); + return DefineAsRegister(new(zone()) LConstructDouble(hi, lo, temp)); +} + + LInstruction* LChunkBuilder::DoReturn(HReturn* instr) { LOperand* context = info()->IsStub() ? UseFixed(instr->context(), cp) diff --git a/src/a64/lithium-a64.h b/src/a64/lithium-a64.h index 1bfbe8582..aa1c23ac3 100644 --- a/src/a64/lithium-a64.h +++ b/src/a64/lithium-a64.h @@ -84,6 +84,7 @@ class LCodeGen; V(ConstantI) \ V(ConstantS) \ V(ConstantT) \ + V(ConstructDouble) \ V(Context) \ V(DateField) \ V(DebugBreak) \ @@ -91,6 +92,7 @@ class LCodeGen; V(Deoptimize) \ V(DivByPowerOf2I) \ V(DivI) \ + V(DoubleBits) \ V(DoubleToIntOrSmi) \ V(Drop) \ V(Dummy) \ @@ -1014,6 +1016,35 @@ class LClampTToUint8 V8_FINAL : public LTemplateInstruction<1, 1, 2> { }; +class LDoubleBits V8_FINAL : public LTemplateInstruction<1, 1, 0> { + public: + explicit LDoubleBits(LOperand* value) { + inputs_[0] = value; + } + + LOperand* value() { return inputs_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(DoubleBits, "double-bits") + DECLARE_HYDROGEN_ACCESSOR(DoubleBits) +}; + + +class LConstructDouble V8_FINAL : public LTemplateInstruction<1, 2, 1> { + public: + LConstructDouble(LOperand* hi, LOperand* lo, LOperand* temp) { + inputs_[0] = hi; + inputs_[1] = lo; + temps_[0] = temp; + } + + LOperand* hi() { return inputs_[0]; } + LOperand* lo() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(ConstructDouble, "construct-double") +}; + + class LClassOfTestAndBranch V8_FINAL : public LControlInstruction<1, 2> { public: LClassOfTestAndBranch(LOperand* value, LOperand* temp1, LOperand* temp2) { diff --git a/src/a64/lithium-codegen-a64.cc b/src/a64/lithium-codegen-a64.cc index e35aa2eb6..d3b33147c 100644 --- a/src/a64/lithium-codegen-a64.cc +++ b/src/a64/lithium-codegen-a64.cc @@ -2224,6 +2224,30 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { } +void LCodeGen::DoDoubleBits(LDoubleBits* instr) { + DoubleRegister value_reg = ToDoubleRegister(instr->value()); + Register result_reg = ToRegister(instr->result()); + if (instr->hydrogen()->bits() == HDoubleBits::HIGH) { + __ Fmov(result_reg, value_reg); + __ Mov(result_reg, Operand(result_reg, LSR, 32)); + } else { + __ Fmov(result_reg.W(), value_reg.S()); + } +} + + +void LCodeGen::DoConstructDouble(LConstructDouble* instr) { + Register hi_reg = ToRegister(instr->hi()); + Register lo_reg = ToRegister(instr->lo()); + Register temp = ToRegister(instr->temp()); + DoubleRegister result_reg = ToDoubleRegister(instr->result()); + + __ And(temp, lo_reg, Operand(0xffffffff)); + __ Orr(temp, temp, Operand(hi_reg, LSL, 32)); + __ Fmov(result_reg, temp); +} + + void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { Handle class_name = instr->hydrogen()->class_name(); Label* true_label = instr->TrueLabel(chunk_); diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index c5e6b0486..63109f59a 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -1982,6 +1982,20 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { } +LInstruction* LChunkBuilder::DoDoubleBits(HDoubleBits* instr) { + HValue* value = instr->value(); + ASSERT(value->representation().IsDouble()); + return DefineAsRegister(new(zone()) LDoubleBits(UseRegister(value))); +} + + +LInstruction* LChunkBuilder::DoConstructDouble(HConstructDouble* instr) { + LOperand* lo = UseRegister(instr->lo()); + LOperand* hi = UseRegister(instr->hi()); + return DefineAsRegister(new(zone()) LConstructDouble(hi, lo)); +} + + LInstruction* LChunkBuilder::DoReturn(HReturn* instr) { LOperand* context = info()->IsStub() ? UseFixed(instr->context(), cp) diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 6217f5419..a304258dc 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -80,6 +80,7 @@ class LCodeGen; V(ConstantI) \ V(ConstantS) \ V(ConstantT) \ + V(ConstructDouble) \ V(Context) \ V(DateField) \ V(DebugBreak) \ @@ -87,6 +88,7 @@ class LCodeGen; V(Deoptimize) \ V(DivByPowerOf2I) \ V(DivI) \ + V(DoubleBits) \ V(DoubleToI) \ V(DoubleToSmi) \ V(Drop) \ @@ -2439,6 +2441,33 @@ class LClampTToUint8 V8_FINAL : public LTemplateInstruction<1, 1, 1> { }; +class LDoubleBits V8_FINAL : public LTemplateInstruction<1, 1, 0> { + public: + explicit LDoubleBits(LOperand* value) { + inputs_[0] = value; + } + + LOperand* value() { return inputs_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(DoubleBits, "double-bits") + DECLARE_HYDROGEN_ACCESSOR(DoubleBits) +}; + + +class LConstructDouble V8_FINAL : public LTemplateInstruction<1, 2, 0> { + public: + LConstructDouble(LOperand* hi, LOperand* lo) { + inputs_[0] = hi; + inputs_[1] = lo; + } + + LOperand* hi() { return inputs_[0]; } + LOperand* lo() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(ConstructDouble, "construct-double") +}; + + class LAllocate V8_FINAL : public LTemplateInstruction<1, 2, 2> { public: LAllocate(LOperand* context, diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 6b38fd13b..a95bb5e85 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -5276,6 +5276,26 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { } +void LCodeGen::DoDoubleBits(LDoubleBits* instr) { + DwVfpRegister value_reg = ToDoubleRegister(instr->value()); + Register result_reg = ToRegister(instr->result()); + if (instr->hydrogen()->bits() == HDoubleBits::HIGH) { + __ VmovHigh(result_reg, value_reg); + } else { + __ VmovLow(result_reg, value_reg); + } +} + + +void LCodeGen::DoConstructDouble(LConstructDouble* instr) { + Register hi_reg = ToRegister(instr->hi()); + Register lo_reg = ToRegister(instr->lo()); + DwVfpRegister result_reg = ToDoubleRegister(instr->result()); + __ VmovHigh(result_reg, hi_reg); + __ VmovLow(result_reg, lo_reg); +} + + void LCodeGen::DoAllocate(LAllocate* instr) { class DeferredAllocate V8_FINAL : public LDeferredCode { public: diff --git a/src/d8.gyp b/src/d8.gyp index 0e51baaac..98ec04fc8 100644 --- a/src/d8.gyp +++ b/src/d8.gyp @@ -31,7 +31,7 @@ 'console%': '', # Enable support for Intel VTune. Supported on ia32/x64 only 'v8_enable_vtunejit%': 0, - 'v8_enable_i18n_support%': 1, + 'v8_enable_i18n_support%': 0, 'v8_toolset_for_d8%': 'target', }, 'includes': ['../build/toolchain.gypi', '../build/features.gypi'], diff --git a/src/full-codegen.cc b/src/full-codegen.cc index 96410747a..d116bae58 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -939,6 +939,34 @@ void FullCodeGenerator::EmitDebugBreakInOptimizedCode(CallRuntime* expr) { } +void FullCodeGenerator::EmitDoubleHi(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + ASSERT(args->length() == 1); + VisitForStackValue(args->at(0)); + masm()->CallRuntime(Runtime::kDoubleHi, 1); + context()->Plug(result_register()); +} + + +void FullCodeGenerator::EmitDoubleLo(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + ASSERT(args->length() == 1); + VisitForStackValue(args->at(0)); + masm()->CallRuntime(Runtime::kDoubleLo, 1); + context()->Plug(result_register()); +} + + +void FullCodeGenerator::EmitConstructDouble(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + ASSERT(args->length() == 2); + VisitForStackValue(args->at(0)); + VisitForStackValue(args->at(1)); + masm()->CallRuntime(Runtime::kConstructDouble, 2); + context()->Plug(result_register()); +} + + void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { switch (expr->op()) { case Token::COMMA: diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index da586d2b4..4c54c1a33 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -102,12 +102,14 @@ class LChunkBuilder; V(CompareObjectEqAndBranch) \ V(CompareMap) \ V(Constant) \ + V(ConstructDouble) \ V(Context) \ V(DateField) \ V(DebugBreak) \ V(DeclareGlobals) \ V(Deoptimize) \ V(Div) \ + V(DoubleBits) \ V(DummyUse) \ V(EnterInlined) \ V(EnvironmentMarker) \ @@ -1820,6 +1822,65 @@ class HClampToUint8 V8_FINAL : public HUnaryOperation { }; +class HDoubleBits V8_FINAL : public HUnaryOperation { + public: + enum Bits { HIGH, LOW }; + DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits); + + virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { + return Representation::Double(); + } + + DECLARE_CONCRETE_INSTRUCTION(DoubleBits) + + Bits bits() { return bits_; } + + protected: + virtual bool DataEquals(HValue* other) V8_OVERRIDE { + return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits(); + } + + private: + HDoubleBits(HValue* value, Bits bits) + : HUnaryOperation(value), bits_(bits) { + set_representation(Representation::Integer32()); + SetFlag(kUseGVN); + } + + virtual bool IsDeletable() const V8_OVERRIDE { return true; } + + Bits bits_; +}; + + +class HConstructDouble V8_FINAL : public HTemplateInstruction<2> { + public: + DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*); + + virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { + return Representation::Integer32(); + } + + DECLARE_CONCRETE_INSTRUCTION(ConstructDouble) + + HValue* hi() { return OperandAt(0); } + HValue* lo() { return OperandAt(1); } + + protected: + virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } + + private: + explicit HConstructDouble(HValue* hi, HValue* lo) { + set_representation(Representation::Double()); + SetFlag(kUseGVN); + SetOperandAt(0, hi); + SetOperandAt(1, lo); + } + + virtual bool IsDeletable() const V8_OVERRIDE { return true; } +}; + + enum RemovableSimulate { REMOVABLE_SIMULATE, FIXED_SIMULATE diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 5324ef39c..25fc74973 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -10509,6 +10509,35 @@ void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) { } +void HOptimizedGraphBuilder::GenerateDoubleLo(CallRuntime* call) { + ASSERT_EQ(1, call->arguments()->length()); + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); + HValue* value = Pop(); + HInstruction* result = NewUncasted(value, HDoubleBits::LOW); + return ast_context()->ReturnInstruction(result, call->id()); +} + + +void HOptimizedGraphBuilder::GenerateDoubleHi(CallRuntime* call) { + ASSERT_EQ(1, call->arguments()->length()); + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); + HValue* value = Pop(); + HInstruction* result = NewUncasted(value, HDoubleBits::HIGH); + return ast_context()->ReturnInstruction(result, call->id()); +} + + +void HOptimizedGraphBuilder::GenerateConstructDouble(CallRuntime* call) { + ASSERT_EQ(2, call->arguments()->length()); + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); + CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); + HValue* lo = Pop(); + HValue* hi = Pop(); + HInstruction* result = NewUncasted(hi, lo); + return ast_context()->ReturnInstruction(result, call->id()); +} + + // Construct a RegExp exec result with two in-object properties. void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { ASSERT_EQ(3, call->arguments()->length()); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 827add373..cbad03060 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -5766,6 +5766,45 @@ void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) { } +void LCodeGen::DoDoubleBits(LDoubleBits* instr) { + CpuFeatureScope scope(masm(), SSE2); + XMMRegister value_reg = ToDoubleRegister(instr->value()); + Register result_reg = ToRegister(instr->result()); + if (instr->hydrogen()->bits() == HDoubleBits::HIGH) { + if (CpuFeatures::IsSupported(SSE4_1)) { + CpuFeatureScope scope2(masm(), SSE4_1); + __ pextrd(result_reg, value_reg, 1); + } else { + XMMRegister xmm_scratch = double_scratch0(); + __ pshufd(xmm_scratch, value_reg, 1); + __ movd(result_reg, xmm_scratch); + } + } else { + __ movd(result_reg, value_reg); + } +} + + +void LCodeGen::DoConstructDouble(LConstructDouble* instr) { + Register hi_reg = ToRegister(instr->hi()); + Register lo_reg = ToRegister(instr->lo()); + XMMRegister result_reg = ToDoubleRegister(instr->result()); + CpuFeatureScope scope(masm(), SSE2); + + if (CpuFeatures::IsSupported(SSE4_1)) { + CpuFeatureScope scope2(masm(), SSE4_1); + __ movd(result_reg, lo_reg); + __ pinsrd(result_reg, hi_reg, 1); + } else { + XMMRegister xmm_scratch = double_scratch0(); + __ movd(result_reg, hi_reg); + __ psllq(result_reg, 32); + __ movd(xmm_scratch, lo_reg); + __ orps(result_reg, xmm_scratch); + } +} + + void LCodeGen::DoAllocate(LAllocate* instr) { class DeferredAllocate V8_FINAL : public LDeferredCode { public: diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 4ff765b87..b513f85c0 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -1990,6 +1990,20 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { } +LInstruction* LChunkBuilder::DoDoubleBits(HDoubleBits* instr) { + HValue* value = instr->value(); + ASSERT(value->representation().IsDouble()); + return DefineAsRegister(new(zone()) LDoubleBits(UseRegister(value))); +} + + +LInstruction* LChunkBuilder::DoConstructDouble(HConstructDouble* instr) { + LOperand* lo = UseRegister(instr->lo()); + LOperand* hi = UseRegister(instr->hi()); + return DefineAsRegister(new(zone()) LConstructDouble(hi, lo)); +} + + LInstruction* LChunkBuilder::DoReturn(HReturn* instr) { LOperand* context = info()->IsStub() ? UseFixed(instr->context(), esi) : NULL; LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count()); diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 07c941ae0..03144b2a5 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -82,6 +82,7 @@ class LCodeGen; V(ConstantI) \ V(ConstantS) \ V(ConstantT) \ + V(ConstructDouble) \ V(Context) \ V(DateField) \ V(DebugBreak) \ @@ -89,6 +90,7 @@ class LCodeGen; V(Deoptimize) \ V(DivByPowerOf2I) \ V(DivI) \ + V(DoubleBits) \ V(DoubleToI) \ V(DoubleToSmi) \ V(Drop) \ @@ -2468,6 +2470,33 @@ class LCheckNonSmi V8_FINAL : public LTemplateInstruction<0, 1, 0> { }; +class LDoubleBits V8_FINAL : public LTemplateInstruction<1, 1, 0> { + public: + explicit LDoubleBits(LOperand* value) { + inputs_[0] = value; + } + + LOperand* value() { return inputs_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(DoubleBits, "double-bits") + DECLARE_HYDROGEN_ACCESSOR(DoubleBits) +}; + + +class LConstructDouble V8_FINAL : public LTemplateInstruction<1, 2, 0> { + public: + LConstructDouble(LOperand* hi, LOperand* lo) { + inputs_[0] = hi; + inputs_[1] = lo; + } + + LOperand* hi() { return inputs_[0]; } + LOperand* lo() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(ConstructDouble, "construct-double") +}; + + class LAllocate V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: LAllocate(LOperand* context, LOperand* size, LOperand* temp) { diff --git a/src/runtime.cc b/src/runtime.cc index 5fe69c26b..c0c87a457 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -7665,6 +7665,35 @@ RUNTIME_UNARY_MATH(log) #undef RUNTIME_UNARY_MATH +RUNTIME_FUNCTION(MaybeObject*, Runtime_DoubleHi) { + SealHandleScope shs(isolate); + ASSERT(args.length() == 1); + CONVERT_DOUBLE_ARG_CHECKED(x, 0); + uint64_t integer = double_to_uint64(x); + integer = (integer >> 32) & 0xFFFFFFFFu; + return isolate->heap()->NumberFromDouble(static_cast(integer)); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_DoubleLo) { + SealHandleScope shs(isolate); + ASSERT(args.length() == 1); + CONVERT_DOUBLE_ARG_CHECKED(x, 0); + return isolate->heap()->NumberFromDouble( + static_cast(double_to_uint64(x) & 0xFFFFFFFFu)); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_ConstructDouble) { + SealHandleScope shs(isolate); + ASSERT(args.length() == 2); + CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]); + CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]); + uint64_t result = (static_cast(hi) << 32) | lo; + return isolate->heap()->AllocateHeapNumber(uint64_to_double(result)); +} + + // Cube root approximation, refer to: http://metamerist.com/cbrt/cbrt.htm // Using initial approximation adapted from Kahan's cbrt and 4 iterations // of Newton's method. diff --git a/src/runtime.h b/src/runtime.h index ff874afaf..480edaf23 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -656,7 +656,10 @@ namespace internal { F(RegExpExec, 4, 1) \ F(RegExpConstructResult, 3, 1) \ F(GetFromCache, 2, 1) \ - F(NumberToString, 1, 1) + F(NumberToString, 1, 1) \ + F(DoubleHi, 1, 1) \ + F(DoubleLo, 1, 1) \ + F(ConstructDouble, 2, 1) //--------------------------------------------------------------------------- diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc index e77842597..63f0533cd 100644 --- a/src/x64/assembler-x64.cc +++ b/src/x64/assembler-x64.cc @@ -2798,6 +2798,16 @@ void Assembler::movss(const Operand& src, XMMRegister dst) { } +void Assembler::psllq(XMMRegister reg, byte imm8) { + EnsureSpace ensure_space(this); + emit(0x66); + emit(0x0F); + emit(0x73); + emit_sse_operand(rsi, reg); // rsi == 6 + emit(imm8); +} + + void Assembler::cvttss2si(Register dst, const Operand& src) { EnsureSpace ensure_space(this); emit(0xF3); diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h index d81cb7410..b1b50c047 100644 --- a/src/x64/assembler-x64.h +++ b/src/x64/assembler-x64.h @@ -1381,6 +1381,8 @@ class Assembler : public AssemblerBase { void movapd(XMMRegister dst, XMMRegister src); + void psllq(XMMRegister reg, byte imm8); + void cvttsd2si(Register dst, const Operand& src); void cvttsd2si(Register dst, XMMRegister src); void cvttsd2siq(Register dst, XMMRegister src); diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc index f0f399ec0..b870eae85 100644 --- a/src/x64/disasm-x64.cc +++ b/src/x64/disasm-x64.cc @@ -1089,6 +1089,11 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { } else if (opcode == 0x50) { AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop)); current += PrintRightXMMOperand(current); + } else if (opcode == 0x73) { + current += 1; + ASSERT(regop == 6); + AppendToBuffer("psllq,%s,%d", NameOfXMMRegister(rm), *current & 0x7f); + current += 1; } else { const char* mnemonic = "?"; if (opcode == 0x54) { diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 5e84347e1..4dc9d4a34 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -5069,6 +5069,30 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { } +void LCodeGen::DoDoubleBits(LDoubleBits* instr) { + XMMRegister value_reg = ToDoubleRegister(instr->value()); + Register result_reg = ToRegister(instr->result()); + if (instr->hydrogen()->bits() == HDoubleBits::HIGH) { + __ movq(result_reg, value_reg); + __ shr(result_reg, Immediate(32)); + } else { + __ movd(result_reg, value_reg); + } +} + + +void LCodeGen::DoConstructDouble(LConstructDouble* instr) { + Register hi_reg = ToRegister(instr->hi()); + Register lo_reg = ToRegister(instr->lo()); + XMMRegister result_reg = ToDoubleRegister(instr->result()); + XMMRegister xmm_scratch = double_scratch0(); + __ movd(result_reg, hi_reg); + __ psllq(result_reg, 32); + __ movd(xmm_scratch, lo_reg); + __ orps(result_reg, xmm_scratch); +} + + void LCodeGen::DoAllocate(LAllocate* instr) { class DeferredAllocate V8_FINAL : public LDeferredCode { public: diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index d01234567..27001abb7 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -1870,6 +1870,20 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { } +LInstruction* LChunkBuilder::DoDoubleBits(HDoubleBits* instr) { + HValue* value = instr->value(); + ASSERT(value->representation().IsDouble()); + return DefineAsRegister(new(zone()) LDoubleBits(UseRegister(value))); +} + + +LInstruction* LChunkBuilder::DoConstructDouble(HConstructDouble* instr) { + LOperand* lo = UseRegister(instr->lo()); + LOperand* hi = UseRegister(instr->hi()); + return DefineAsRegister(new(zone()) LConstructDouble(hi, lo)); +} + + LInstruction* LChunkBuilder::DoReturn(HReturn* instr) { LOperand* context = info()->IsStub() ? UseFixed(instr->context(), rsi) : NULL; LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count()); diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index 29cfc5fcc..c6a6850b9 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -80,6 +80,7 @@ class LCodeGen; V(ConstantI) \ V(ConstantS) \ V(ConstantT) \ + V(ConstructDouble) \ V(Context) \ V(DateField) \ V(DebugBreak) \ @@ -87,6 +88,7 @@ class LCodeGen; V(Deoptimize) \ V(DivByPowerOf2I) \ V(DivI) \ + V(DoubleBits) \ V(DoubleToI) \ V(DoubleToSmi) \ V(Drop) \ @@ -2372,6 +2374,33 @@ class LCheckNonSmi V8_FINAL : public LTemplateInstruction<0, 1, 0> { }; +class LDoubleBits V8_FINAL : public LTemplateInstruction<1, 1, 0> { + public: + explicit LDoubleBits(LOperand* value) { + inputs_[0] = value; + } + + LOperand* value() { return inputs_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(DoubleBits, "double-bits") + DECLARE_HYDROGEN_ACCESSOR(DoubleBits) +}; + + +class LConstructDouble V8_FINAL : public LTemplateInstruction<1, 2, 0> { + public: + LConstructDouble(LOperand* hi, LOperand* lo) { + inputs_[0] = hi; + inputs_[1] = lo; + } + + LOperand* hi() { return inputs_[0]; } + LOperand* lo() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(ConstructDouble, "construct-double") +}; + + class LAllocate V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: LAllocate(LOperand* context, LOperand* size, LOperand* temp) { diff --git a/test/mjsunit/double-intrinsics.js b/test/mjsunit/double-intrinsics.js new file mode 100644 index 000000000..16d653893 --- /dev/null +++ b/test/mjsunit/double-intrinsics.js @@ -0,0 +1,36 @@ +// Copyright 2014 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 + +function assertDoubleBits(hi, lo, x) { + hi = hi | 0; + lo = lo | 0; + assertEquals(x, %_ConstructDouble(hi, lo)); + assertEquals(hi, %_DoubleHi(x)); + assertEquals(lo, %_DoubleLo(x)); + assertEquals(x, %_ConstructDouble(%_DoubleHi(x), %_DoubleLo(x))); +} + + +var tests = [0x7ff00000, 0x00000000, Infinity, + 0xfff00000, 0x00000000, -Infinity, + 0x80000000, 0x00000000, -0, + 0x400921fb, 0x54442d18, Math.PI, + 0xc00921fb, 0x54442d18, -Math.PI, + 0x4005bf0a, 0x8b145769, Math.E, + 0xc005bf0a, 0x8b145769, -Math.E, + 0xbfe80000, 0x00000000, -0.75]; + + +for (var i = 0; i < tests.length; i += 3) { + assertDoubleBits(tests[i], tests[i + 1], tests[i + 2]); +} + +%OptimizeFunctionOnNextCall(assertDoubleBits); + +for (var i = 0; i < tests.length; i += 3) { + assertDoubleBits(tests[i], tests[i + 1], tests[i + 2]); + assertOptimized(assertDoubleBits); +} -- 2.34.1