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
This commit is contained in:
parent
fa6d25a602
commit
4f15fd2977
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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<String> class_name = instr->hydrogen()->class_name();
|
||||
Label* true_label = instr->TrueLabel(chunk_);
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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'],
|
||||
|
@ -939,6 +939,34 @@ void FullCodeGenerator::EmitDebugBreakInOptimizedCode(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitDoubleHi(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* 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<Expression*>* 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<Expression*>* 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:
|
||||
|
@ -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
|
||||
|
@ -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<HDoubleBits>(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<HDoubleBits>(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<HConstructDouble>(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());
|
||||
|
@ -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:
|
||||
|
@ -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());
|
||||
|
@ -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) {
|
||||
|
@ -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<int32_t>(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<int32_t>(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<uint64_t>(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.
|
||||
|
@ -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)
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
@ -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());
|
||||
|
@ -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) {
|
||||
|
36
test/mjsunit/double-intrinsics.js
Normal file
36
test/mjsunit/double-intrinsics.js
Normal file
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user