Commit 32295c1a authored by oliver@apple.com's avatar oliver@apple.com
Browse files

fourthTier: FTL should support double variables

https://bugs.webkit.org/show_bug.cgi?id=113624

Reviewed by Geoffrey Garen.

Made all of the operations that the FTL already supports, also support doubles.
OSR exit already basically had everything it needed, so no changes there. This
mostly just glues together bits of DFG IR to LLVM IR, in a straight-forward way.

* ftl/FTLAbbreviations.h:
(FTL):
(JSC::FTL::doubleType):
(JSC::FTL::constReal):
(JSC::FTL::buildPhi):
(JSC::FTL::addIncoming):
(JSC::FTL::buildFAdd):
(JSC::FTL::buildFSub):
(JSC::FTL::buildFMul):
(JSC::FTL::buildFNeg):
(JSC::FTL::buildSIToFP):
(JSC::FTL::buildUIToFP):
(JSC::FTL::buildBitCast):
(JSC::FTL::buildFCmp):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLCommonValues.cpp:
(JSC::FTL::CommonValues::CommonValues):
* ftl/FTLCommonValues.h:
(CommonValues):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
(JSC::FTL::LowerDFGToLLVM::lower):
(JSC::FTL::LowerDFGToLLVM::compileGetLocal):
(JSC::FTL::LowerDFGToLLVM::compileSetLocal):
(JSC::FTL::LowerDFGToLLVM::compileAdd):
(JSC::FTL::LowerDFGToLLVM::compileArithSub):
(JSC::FTL::LowerDFGToLLVM::compileArithMul):
(JSC::FTL::LowerDFGToLLVM::compileArithNegate):
(JSC::FTL::LowerDFGToLLVM::compileUInt32ToNumber):
(JSC::FTL::LowerDFGToLLVM::compileGetByVal):
(JSC::FTL::LowerDFGToLLVM::compileCompareEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareLess):
(JSC::FTL::LowerDFGToLLVM::lowDouble):
(LowerDFGToLLVM):
(JSC::FTL::LowerDFGToLLVM::lowJSValue):
(JSC::FTL::LowerDFGToLLVM::isCellOrMisc):
(JSC::FTL::LowerDFGToLLVM::unboxDouble):
(JSC::FTL::LowerDFGToLLVM::boxDouble):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::speculateNumber):
(JSC::FTL::LowerDFGToLLVM::speculateRealNumber):
(JSC::FTL::LowerDFGToLLVM::appendOSRExit):
(JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
* ftl/FTLOutput.h:
(JSC::FTL::Output::constDouble):
(Output):
(JSC::FTL::Output::phi):
(JSC::FTL::Output::doubleAdd):
(JSC::FTL::Output::doubleSub):
(JSC::FTL::Output::doubleMul):
(JSC::FTL::Output::doubleNeg):
(JSC::FTL::Output::intToFP):
(JSC::FTL::Output::intToDouble):
(JSC::FTL::Output::unsignedToFP):
(JSC::FTL::Output::unsignedToDouble):
(JSC::FTL::Output::bitCast):
(JSC::FTL::Output::loadDouble):
(JSC::FTL::Output::storeDouble):
(JSC::FTL::Output::doubleEqual):
(JSC::FTL::Output::doubleNotEqualOrUnordered):
(JSC::FTL::Output::doubleLessThan):
(JSC::FTL::Output::doubleLessThanOrEqual):
(JSC::FTL::Output::doubleGreaterThan):
(JSC::FTL::Output::doubleGreaterThanOrEqual):
(JSC::FTL::Output::doubleEqualOrUnordered):
(JSC::FTL::Output::doubleNotEqual):
(JSC::FTL::Output::doubleLessThanOrUnordered):
(JSC::FTL::Output::doubleLessThanOrEqualOrUnordered):
(JSC::FTL::Output::doubleGreaterThanOrUnordered):
(JSC::FTL::Output::doubleGreaterThanOrEqualOrUnordered):
(JSC::FTL::Output::testIsZero64):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153133 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent f72e22e2
2013-04-27 Filip Pizlo <fpizlo@apple.com>
FTL should support double variables
https://bugs.webkit.org/show_bug.cgi?id=113624
Reviewed by Geoffrey Garen.
Made all of the operations that the FTL already supports, also support doubles.
OSR exit already basically had everything it needed, so no changes there. This
mostly just glues together bits of DFG IR to LLVM IR, in a straight-forward way.
* ftl/FTLAbbreviations.h:
(FTL):
(JSC::FTL::doubleType):
(JSC::FTL::constReal):
(JSC::FTL::buildPhi):
(JSC::FTL::addIncoming):
(JSC::FTL::buildFAdd):
(JSC::FTL::buildFSub):
(JSC::FTL::buildFMul):
(JSC::FTL::buildFNeg):
(JSC::FTL::buildSIToFP):
(JSC::FTL::buildUIToFP):
(JSC::FTL::buildBitCast):
(JSC::FTL::buildFCmp):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLCommonValues.cpp:
(JSC::FTL::CommonValues::CommonValues):
* ftl/FTLCommonValues.h:
(CommonValues):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
(JSC::FTL::LowerDFGToLLVM::lower):
(JSC::FTL::LowerDFGToLLVM::compileGetLocal):
(JSC::FTL::LowerDFGToLLVM::compileSetLocal):
(JSC::FTL::LowerDFGToLLVM::compileAdd):
(JSC::FTL::LowerDFGToLLVM::compileArithSub):
(JSC::FTL::LowerDFGToLLVM::compileArithMul):
(JSC::FTL::LowerDFGToLLVM::compileArithNegate):
(JSC::FTL::LowerDFGToLLVM::compileUInt32ToNumber):
(JSC::FTL::LowerDFGToLLVM::compileGetByVal):
(JSC::FTL::LowerDFGToLLVM::compileCompareEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareLess):
(JSC::FTL::LowerDFGToLLVM::lowDouble):
(LowerDFGToLLVM):
(JSC::FTL::LowerDFGToLLVM::lowJSValue):
(JSC::FTL::LowerDFGToLLVM::isCellOrMisc):
(JSC::FTL::LowerDFGToLLVM::unboxDouble):
(JSC::FTL::LowerDFGToLLVM::boxDouble):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::speculateNumber):
(JSC::FTL::LowerDFGToLLVM::speculateRealNumber):
(JSC::FTL::LowerDFGToLLVM::appendOSRExit):
(JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
* ftl/FTLOutput.h:
(JSC::FTL::Output::constDouble):
(Output):
(JSC::FTL::Output::phi):
(JSC::FTL::Output::doubleAdd):
(JSC::FTL::Output::doubleSub):
(JSC::FTL::Output::doubleMul):
(JSC::FTL::Output::doubleNeg):
(JSC::FTL::Output::intToFP):
(JSC::FTL::Output::intToDouble):
(JSC::FTL::Output::unsignedToFP):
(JSC::FTL::Output::unsignedToDouble):
(JSC::FTL::Output::bitCast):
(JSC::FTL::Output::loadDouble):
(JSC::FTL::Output::storeDouble):
(JSC::FTL::Output::doubleEqual):
(JSC::FTL::Output::doubleNotEqualOrUnordered):
(JSC::FTL::Output::doubleLessThan):
(JSC::FTL::Output::doubleLessThanOrEqual):
(JSC::FTL::Output::doubleGreaterThan):
(JSC::FTL::Output::doubleGreaterThanOrEqual):
(JSC::FTL::Output::doubleEqualOrUnordered):
(JSC::FTL::Output::doubleNotEqual):
(JSC::FTL::Output::doubleLessThanOrUnordered):
(JSC::FTL::Output::doubleLessThanOrEqualOrUnordered):
(JSC::FTL::Output::doubleGreaterThanOrUnordered):
(JSC::FTL::Output::doubleGreaterThanOrEqualOrUnordered):
(JSC::FTL::Output::testIsZero64):
2013-04-27 Filip Pizlo <fpizlo@apple.com>
fourthTier: SymbolTable should be thread-safe
......
......@@ -47,6 +47,7 @@ typedef LLVMBasicBlockRef LBasicBlock;
typedef LLVMBuilderRef LBuilder;
typedef LLVMCallConv LCallConv;
typedef LLVMIntPredicate LIntPredicate;
typedef LLVMRealPredicate LRealPredicate;
typedef LLVMLinkage LLinkage;
typedef LLVMModuleRef LModule;
typedef LLVMTypeRef LType;
......@@ -57,6 +58,7 @@ static inline LType int1Type() { return LLVMInt1Type(); }
static inline LType int32Type() { return LLVMInt32Type(); }
static inline LType int64Type() { return LLVMInt64Type(); }
static inline LType intPtrType() { return LLVMInt64Type(); }
static inline LType doubleType() { return LLVMDoubleType(); }
static inline LType pointerType(LType type) { return LLVMPointerType(type, 0); }
......@@ -134,17 +136,58 @@ static inline LValue getParam(LValue function, unsigned index) { return LLVMGetP
enum BitExtension { ZeroExtend, SignExtend };
static inline LValue constInt(LType type, unsigned long long value, BitExtension extension) { return LLVMConstInt(type, value, extension == SignExtend); }
static inline LValue constReal(LType type, double value) { return LLVMConstReal(type, value); }
static inline LValue constIntToPtr(LValue value, LType type) { return LLVMConstIntToPtr(value, type); }
static inline LValue constBitCast(LValue value, LType type) { return LLVMConstBitCast(value, type); }
static inline LBasicBlock appendBasicBlock(LValue function, const char* name = "") { return LLVMAppendBasicBlock(function, name); }
static inline LBasicBlock insertBasicBlock(LBasicBlock beforeBasicBlock, const char* name = "") { return LLVMInsertBasicBlock(beforeBasicBlock, name); }
static inline LValue buildPhi(LBuilder builder, LType type) { return LLVMBuildPhi(builder, type, ""); }
static inline void addIncoming(LValue phi, const LValue* values, const LBasicBlock* blocks, unsigned numPredecessors)
{
LLVMAddIncoming(phi, const_cast<LValue*>(values), const_cast<LBasicBlock*>(blocks), numPredecessors);
}
template<typename ValueVectorType, typename BlockVectorType>
static inline void addIncoming(LValue phi, const ValueVectorType& values, const BlockVectorType& blocks)
{
ASSERT(values.size() == blocks.size());
addIncoming(phi, values.begin(), blocks.begin(), values.size());
}
static inline void addIncoming(LValue phi, LValue value1, LBasicBlock block1)
{
addIncoming(phi, &value1, &block1, 1);
}
static inline void addIncoming(LValue phi, LValue value1, LBasicBlock block1, LValue value2, LBasicBlock block2)
{
LValue values[] = { value1, value2 };
LBasicBlock blocks[] = { block1, block2 };
addIncoming(phi, values, blocks, 2);
}
static inline LValue buildPhi(LBuilder builder, LType type, LValue value1, LBasicBlock block1)
{
LValue result = buildPhi(builder, type);
addIncoming(result, value1, block1);
return result;
}
static inline LValue buildPhi(
LBuilder builder, LType type, LValue value1, LBasicBlock block1, LValue value2,
LBasicBlock block2)
{
LValue result = buildPhi(builder, type);
addIncoming(result, value1, block1, value2, block2);
return result;
}
static inline LValue buildAlloca(LBuilder builder, LType type) { return LLVMBuildAlloca(builder, type, ""); }
static inline LValue buildAdd(LBuilder builder, LValue left, LValue right) { return LLVMBuildAdd(builder, left, right, ""); }
static inline LValue buildSub(LBuilder builder, LValue left, LValue right) { return LLVMBuildSub(builder, left, right, ""); }
static inline LValue buildMul(LBuilder builder, LValue left, LValue right) { return LLVMBuildMul(builder, left, right, ""); }
static inline LValue buildNeg(LBuilder builder, LValue value) { return LLVMBuildNeg(builder, value, ""); }
static inline LValue buildFAdd(LBuilder builder, LValue left, LValue right) { return LLVMBuildFAdd(builder, left, right, ""); }
static inline LValue buildFSub(LBuilder builder, LValue left, LValue right) { return LLVMBuildFSub(builder, left, right, ""); }
static inline LValue buildFMul(LBuilder builder, LValue left, LValue right) { return LLVMBuildFMul(builder, left, right, ""); }
static inline LValue buildFNeg(LBuilder builder, LValue value) { return LLVMBuildFNeg(builder, value, ""); }
static inline LValue buildAnd(LBuilder builder, LValue left, LValue right) { return LLVMBuildAnd(builder, left, right, ""); }
static inline LValue buildOr(LBuilder builder, LValue left, LValue right) { return LLVMBuildOr(builder, left, right, ""); }
static inline LValue buildXor(LBuilder builder, LValue left, LValue right) { return LLVMBuildXor(builder, left, right, ""); }
......@@ -154,10 +197,14 @@ static inline LValue buildLShr(LBuilder builder, LValue left, LValue right) { re
static inline LValue buildLoad(LBuilder builder, LValue pointer) { return LLVMBuildLoad(builder, pointer, ""); }
static inline LValue buildStore(LBuilder builder, LValue value, LValue pointer) { return LLVMBuildStore(builder, value, pointer); }
static inline LValue buildZExt(LBuilder builder, LValue value, LType type) { return LLVMBuildZExt(builder, value, type, ""); }
static inline LValue buildSIToFP(LBuilder builder, LValue value, LType type) { return LLVMBuildSIToFP(builder, value, type, ""); }
static inline LValue buildUIToFP(LBuilder builder, LValue value, LType type) { return LLVMBuildUIToFP(builder, value, type, ""); }
static inline LValue buildIntCast(LBuilder builder, LValue value, LType type) { return LLVMBuildIntCast(builder, value, type, ""); }
static inline LValue buildIntToPtr(LBuilder builder, LValue value, LType type) { return LLVMBuildIntToPtr(builder, value, type, ""); }
static inline LValue buildPtrToInt(LBuilder builder, LValue value, LType type) { return LLVMBuildPtrToInt(builder, value, type, ""); }
static inline LValue buildBitCast(LBuilder builder, LValue value, LType type) { return LLVMBuildBitCast(builder, value, type, ""); }
static inline LValue buildICmp(LBuilder builder, LIntPredicate cond, LValue left, LValue right) { return LLVMBuildICmp(builder, cond, left, right, ""); }
static inline LValue buildFCmp(LBuilder builder, LRealPredicate cond, LValue left, LValue right) { return LLVMBuildFCmp(builder, cond, left, right, ""); }
static inline LValue buildCall(LBuilder builder, LValue function, const LValue* args, unsigned numArgs)
{
return LLVMBuildCall(builder, function, const_cast<LValue*>(args), numArgs, "");
......
......@@ -50,6 +50,9 @@ bool canCompile(Graph& graph)
case UntypedUse:
case Int32Use:
case KnownInt32Use:
case NumberUse:
case KnownNumberUse:
case RealNumberUse:
case BooleanUse:
case CellUse:
case KnownCellUse:
......@@ -90,22 +93,13 @@ bool canCompile(Graph& graph)
case PutByOffset:
case GetGlobalVar:
case PutGlobalVar:
// These are OK.
break;
case ValueAdd:
case ArithAdd:
case ArithSub:
case ArithMul:
if (node->binaryUseKind() == Int32Use)
break;
return false;
case ArithNegate:
if (node->child1().useKind() == Int32Use)
break;
return false;
case UInt32ToNumber:
if (!nodeCanSpeculateInteger(node->arithNodeFlags()))
return false;
// These are OK.
break;
case GetArrayLength:
switch (node->arrayMode().type()) {
......@@ -120,6 +114,7 @@ bool canCompile(Graph& graph)
case GetByVal:
switch (node->arrayMode().type()) {
case Array::Int32:
case Array::Double:
case Array::Contiguous:
break;
default:
......@@ -136,12 +131,16 @@ bool canCompile(Graph& graph)
case CompareEq:
if (node->isBinaryUseKind(Int32Use))
break;
if (node->isBinaryUseKind(NumberUse))
break;
if (node->isBinaryUseKind(ObjectUse))
break;
return false;
case CompareLess:
if (node->isBinaryUseKind(Int32Use))
break;
if (node->isBinaryUseKind(NumberUse))
break;
return false;
case Branch:
if (node->child1().useKind() == BooleanUse)
......
......@@ -36,9 +36,11 @@ CommonValues::CommonValues()
, int32(int32Type())
, int64(int64Type())
, intPtr(intPtrType())
, doubleType(FTL::doubleType())
, ref32(pointerType(int32))
, ref64(pointerType(int64))
, refPtr(pointerType(intPtr))
, refDouble(pointerType(doubleType))
, booleanTrue(constInt(boolean, true, ZeroExtend))
, booleanFalse(constInt(boolean, false, ZeroExtend))
, int32Zero(constInt(int32, 0, SignExtend))
......@@ -50,6 +52,7 @@ CommonValues::CommonValues()
, intPtrFour(constInt(intPtr, 4, SignExtend))
, intPtrEight(constInt(intPtr, 8, SignExtend))
, intPtrPtr(constInt(intPtr, sizeof(void*), SignExtend))
, doubleZero(constReal(doubleType, 0))
, m_module(0)
{
}
......
......@@ -48,9 +48,11 @@ public:
const LType int32;
const LType int64;
const LType intPtr;
const LType doubleType;
const LType ref32;
const LType ref64;
const LType refPtr;
const LType refDouble;
const LValue booleanTrue;
const LValue booleanFalse;
const LValue int32Zero;
......@@ -62,6 +64,7 @@ public:
const LValue intPtrFour;
const LValue intPtrEight;
const LValue intPtrPtr;
const LValue doubleZero;
LModule m_module;
};
......
......@@ -55,9 +55,10 @@ bool compile(State& state, RefPtr<JSC::JITCode>& jitCode, MacroAssemblerCodePtr&
char* error = 0;
LLVMMCJITCompilerOptions options;
memset(&options, 0, sizeof(options));
LLVMInitializeMCJITCompilerOptions(&options, sizeof(options));
options.OptLevel = Options::llvmOptimizationLevel();
options.NoFramePointerElim = true;
options.CodeModel = LLVMCodeModelSmall;
if (LLVMCreateMCJITCompilerForModule(&engine, state.module, &options, sizeof(options), &error)) {
dataLog("FATAL: Could not create LLVM execution engine: ", error, "\n");
......
......@@ -62,6 +62,7 @@ public:
, m_localsBoolean(OperandsLike, state.graph.m_blocks[0]->variablesAtHead)
, m_locals32(OperandsLike, state.graph.m_blocks[0]->variablesAtHead)
, m_locals64(OperandsLike, state.graph.m_blocks[0]->variablesAtHead)
, m_localsDouble(OperandsLike, state.graph.m_blocks[0]->variablesAtHead)
, m_valueSources(OperandsLike, state.graph.m_blocks[0]->variablesAtHead)
, m_lastSetOperand(std::numeric_limits<int>::max())
, m_exitThunkGenerator(state)
......@@ -86,6 +87,7 @@ public:
m_localsBoolean[index] = buildAlloca(m_out.m_builder, m_out.boolean);
m_locals32[index] = buildAlloca(m_out.m_builder, m_out.int32);
m_locals64[index] = buildAlloca(m_out.m_builder, m_out.int64);
m_localsDouble[index] = buildAlloca(m_out.m_builder, m_out.doubleType);
}
m_initialization = appendBasicBlock(m_ftlState.function);
......@@ -422,9 +424,8 @@ private:
if (variable->shouldUnboxIfPossible()) {
if (variable->shouldUseDoubleFormat()) {
// FIXME: implement doubles in FTL.
// https://bugs.webkit.org/show_bug.cgi?id=113624
RELEASE_ASSERT_NOT_REACHED();
m_doubleValues.add(m_node, m_out.get(m_localsDouble.operand(variable->local())));
return;
}
// Locals that are marked shouldUnboxIfPossible() that aren't also forced to
......@@ -456,9 +457,12 @@ private:
if (variable->shouldUnboxIfPossible()) {
if (variable->shouldUseDoubleFormat()) {
// FIXME: implement doubles in FTL.
// https://bugs.webkit.org/show_bug.cgi?id=113624
RELEASE_ASSERT_NOT_REACHED();
LValue value = lowDouble(m_node->child1());
m_out.set(value, m_localsDouble.operand(variable->local()));
if (needsFlushing) {
m_out.storeDouble(value, addressFor(variable->local()));
m_valueSources.operand(variable->local()) = ValueSource(DoubleInJSStack);
}
return;
}
......@@ -552,6 +556,13 @@ private:
break;
}
case NumberUse: {
m_doubleValues.add(
m_node,
m_out.doubleAdd(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
break;
}
default:
RELEASE_ASSERT_NOT_REACHED();
break;
......@@ -576,6 +587,13 @@ private:
break;
}
case NumberUse: {
m_doubleValues.add(
m_node,
m_out.doubleSub(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
break;
}
default:
RELEASE_ASSERT_NOT_REACHED();
break;
......@@ -613,6 +631,13 @@ private:
break;
}
case NumberUse: {
m_doubleValues.add(
m_node,
m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
break;
}
default:
RELEASE_ASSERT_NOT_REACHED();
break;
......@@ -640,6 +665,11 @@ private:
break;
}
case NumberUse: {
m_doubleValues.add(m_node, m_out.doubleNeg(lowDouble(m_node->child1())));
break;
}
default:
RELEASE_ASSERT_NOT_REACHED();
break;
......@@ -693,15 +723,13 @@ private:
void compileUInt32ToNumber()
{
LValue value = lowInt32(m_node->child1());
if (!nodeCanSpeculateInteger(m_node->arithNodeFlags())) {
// FIXME: implement doubles in FTL.
// https://bugs.webkit.org/show_bug.cgi?id=113624
RELEASE_ASSERT_NOT_REACHED();
m_doubleValues.add(m_node, m_out.unsignedToDouble(value));
return;
}
LValue value = lowInt32(m_node->child1());
speculateForward(
Overflow, noValue(), 0, m_out.lessThan(value, m_out.int32Zero),
FormattedValue(ValueFormatUInt32, value));
......@@ -821,6 +849,36 @@ private:
break;
}
case Array::Double: {
if (m_node->arrayMode().isInBounds()) {
if (m_node->arrayMode().isSaneChain()) {
// FIXME: Implement structure transition watchpoints.
// https://bugs.webkit.org/show_bug.cgi?id=113647
}
speculate(
OutOfBounds, noValue(), 0,
m_out.aboveOrEqual(
index, m_out.load32(storage, m_heaps.Butterfly_publicLength)));
LValue result = m_out.loadDouble(m_out.baseIndex(
m_heaps.indexedDoubleProperties,
storage, m_out.zeroExt(index, m_out.intPtr),
m_state.forNode(m_node->child2()).m_value));
if (!m_node->arrayMode().isSaneChain()) {
speculate(
LoadFromHole, noValue(), 0,
m_out.doubleNotEqualOrUnordered(result, result));
}
m_doubleValues.add(m_node, result);
break;
}
RELEASE_ASSERT_NOT_REACHED();
break;
}
default:
RELEASE_ASSERT_NOT_REACHED();
break;
......@@ -874,6 +932,12 @@ private:
return;
}
if (m_node->isBinaryUseKind(NumberUse)) {
m_booleanValues.add(
m_node,
m_out.doubleEqual(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
}
if (m_node->isBinaryUseKind(ObjectUse)) {
m_booleanValues.add(
m_node,
......@@ -893,6 +957,12 @@ private:
return;
}
if (m_node->isBinaryUseKind(NumberUse)) {
m_booleanValues.add(
m_node,
m_out.doubleLessThan(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
}
RELEASE_ASSERT_NOT_REACHED();
}
......@@ -1042,6 +1112,57 @@ private:
return m_out.booleanFalse;
}
LValue lowDouble(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
{
ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || isDouble(edge.useKind()));
if (LValue result = m_doubleValues.get(edge.node()))
return result;
if (LValue intResult = m_int32Values.get(edge.node())) {
LValue result = m_out.intToDouble(intResult);
m_doubleValues.add(edge.node(), result);
return result;
}
if (LValue boxedResult = m_jsValueValues.get(edge.node())) {
LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("Double unboxing int case"));
LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("Double unboxing double case"));
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Double unboxing continuation"));
m_out.branch(isNotInt32(boxedResult), doubleCase, intCase);
LBasicBlock lastNext = m_out.appendTo(intCase, doubleCase);
LValue intToDouble = m_out.intToDouble(unboxInt32(boxedResult));
LBasicBlock intToDoubleBlock = m_out.m_block;
m_out.jump(continuation);
m_out.appendTo(doubleCase, continuation);
FTL_TYPE_CHECK(
jsValueValue(boxedResult), edge, SpecNumber, isCellOrMisc(boxedResult));
LValue unboxedDouble = unboxDouble(boxedResult);
LBasicBlock unboxedDoubleBlock = m_out.m_block;
m_out.jump(continuation);
m_out.appendTo(continuation, lastNext);
LValue result = m_out.phi(
m_out.doubleType,
intToDouble, intToDoubleBlock,
unboxedDouble, unboxedDoubleBlock);
m_doubleValues.add(edge.node(), result);
return result;
}
RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecNumber));
terminate(Uncountable);
return m_out.doubleZero;
}
LValue lowJSValue(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
{
ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse);
......@@ -1061,6 +1182,12 @@ private:
return result;
}
if (LValue unboxedResult = m_doubleValues.get(edge.node())) {
LValue result = boxDouble(unboxedResult);
m_jsValueValues.add(edge.node(), result);
return result;
}
RELEASE_ASSERT_NOT_REACHED();
return 0;
}
......@@ -1088,6 +1215,19 @@ private:
return m_out.add(m_out.zeroExt(value, m_out.int64), m_tagTypeNumber);
}
LValue isCellOrMisc(LValue jsValue)
{
return m_out.testIsZero64(jsValue, m_tagTypeNumber);
}
LValue unboxDouble(LValue jsValue)
{
return m_out.bitCast(m_out.add(jsValue, m_tagTypeNumber), m_out.doubleType);
}
LValue boxDouble(LValue doubleValue)
{
return m_out.sub(m_out.bitCast(doubleValue, m_out.int64), m_tagTypeNumber);
}
LValue isNotCell(LValue jsValue)
{
return m_out.testNonZero64(jsValue, m_tagMask);
......@@ -1117,6 +1257,7 @@ private:
case UntypedUse:
break;
case KnownInt32Use:
case KnownNumberUse:
ASSERT(!m_state.needsTypeCheck(edge));
break;
case Int32Use:
......@@ -1131,6 +1272,12 @@ private:
case ObjectUse:
speculateObject(edge);
break;
case RealNumberUse:
speculateRealNumber(edge);
break;
case NumberUse:
speculateNumber(edge);
break;
default:
RELEASE_ASSERT_NOT_REACHED();
}
......@@ -1165,6 +1312,27 @@ private:
speculateObject(edge, lowCell(edge));
}
void speculateNumber(Edge edge)
{
// Do an early return here because lowDouble() can create a lot of control flow.
if (!m_state.needsTypeCheck(edge))
return;
lowDouble(edge);
}
void speculateRealNumber(Edge edge)
{
// Do an early return here because lowDouble() can create a lot of control flow.
if (!m_state.needsTypeCheck(edge))
return;
LValue value = lowDouble(edge);
FTL_TYPE_CHECK(
doubleValue(value), edge, SpecRealNumber,
m_out.doubleNotEqualOrUnordered(value, value));