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:
yangguo@chromium.org 2014-03-07 14:58:41 +00:00
parent fa6d25a602
commit 4f15fd2977
22 changed files with 487 additions and 2 deletions

View File

@ -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)

View File

@ -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) {

View File

@ -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_);

View File

@ -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)

View File

@ -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,

View File

@ -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:

View File

@ -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'],

View File

@ -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:

View File

@ -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

View File

@ -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());

View File

@ -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:

View File

@ -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());

View File

@ -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) {

View File

@ -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.

View File

@ -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)
//---------------------------------------------------------------------------

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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:

View File

@ -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());

View File

@ -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) {

View 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);
}