Commit 929434af authored by fpizlo@apple.com's avatar fpizlo@apple.com

FTL should support UntypedUse versions of Compare nodes

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

Reviewed by Oliver Hunt.
        
This adds UntypedUse versions of all comparisons except CompareStrictEq, which is
sufficiently different that I thought I'd do it in another patch.
        
This also extends our ability to abstract over comparison kind and removes a bunch of
copy-paste code.

* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompare):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileCompareEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareLess):
(JSC::FTL::LowerDFGToLLVM::compileCompareLessEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareGreater):
(JSC::FTL::LowerDFGToLLVM::compileCompareGreaterEq):
(JSC::FTL::LowerDFGToLLVM::compare):
(JSC::FTL::LowerDFGToLLVM::nonSpeculativeCompare):
* ftl/FTLOutput.h:
(JSC::FTL::Output::icmp):
(JSC::FTL::Output::equal):
(JSC::FTL::Output::notEqual):
(JSC::FTL::Output::above):
(JSC::FTL::Output::aboveOrEqual):
(JSC::FTL::Output::below):
(JSC::FTL::Output::belowOrEqual):
(JSC::FTL::Output::greaterThan):
(JSC::FTL::Output::greaterThanOrEqual):
(JSC::FTL::Output::lessThan):
(JSC::FTL::Output::lessThanOrEqual):
(JSC::FTL::Output::fcmp):
(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):
* tests/stress/untyped-equality.js: Added.
(foo):
* tests/stress/untyped-less-than.js: Added.
(foo):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@160294 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 3e55f651
2013-12-08 Filip Pizlo <fpizlo@apple.com>
FTL should support UntypedUse versions of Compare nodes
https://bugs.webkit.org/show_bug.cgi?id=125426
Reviewed by Oliver Hunt.
This adds UntypedUse versions of all comparisons except CompareStrictEq, which is
sufficiently different that I thought I'd do it in another patch.
This also extends our ability to abstract over comparison kind and removes a bunch of
copy-paste code.
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompare):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileCompareEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareLess):
(JSC::FTL::LowerDFGToLLVM::compileCompareLessEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareGreater):
(JSC::FTL::LowerDFGToLLVM::compileCompareGreaterEq):
(JSC::FTL::LowerDFGToLLVM::compare):
(JSC::FTL::LowerDFGToLLVM::nonSpeculativeCompare):
* ftl/FTLOutput.h:
(JSC::FTL::Output::icmp):
(JSC::FTL::Output::equal):
(JSC::FTL::Output::notEqual):
(JSC::FTL::Output::above):
(JSC::FTL::Output::aboveOrEqual):
(JSC::FTL::Output::below):
(JSC::FTL::Output::belowOrEqual):
(JSC::FTL::Output::greaterThan):
(JSC::FTL::Output::greaterThanOrEqual):
(JSC::FTL::Output::lessThan):
(JSC::FTL::Output::lessThanOrEqual):
(JSC::FTL::Output::fcmp):
(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):
* tests/stress/untyped-equality.js: Added.
(foo):
* tests/stress/untyped-less-than.js: Added.
(foo):
2013-12-07 Filip Pizlo <fpizlo@apple.com>
Fold typedArray.length if typedArray is constant
......
......@@ -486,6 +486,7 @@ private:
void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node* node, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
{
ASSERT(node->isBinaryUseKind(UntypedUse));
JSValueOperand arg1(this, node->child1());
JSValueOperand arg2(this, node->child2());
GPRReg arg1GPR = arg1.gpr();
......
......@@ -179,6 +179,17 @@ inline CapabilityLevel canCompile(Node* node)
}
break;
case CompareEq:
if (node->isBinaryUseKind(Int32Use))
break;
if (node->isBinaryUseKind(MachineIntUse))
break;
if (node->isBinaryUseKind(NumberUse))
break;
if (node->isBinaryUseKind(ObjectUse))
break;
if (node->isBinaryUseKind(UntypedUse))
break;
return CannotCompile;
case CompareStrictEq:
if (node->isBinaryUseKind(Int32Use))
break;
......@@ -199,6 +210,8 @@ inline CapabilityLevel canCompile(Node* node)
break;
if (node->isBinaryUseKind(NumberUse))
break;
if (node->isBinaryUseKind(UntypedUse))
break;
return CannotCompile;
case Switch:
switch (node->switchData()->kind) {
......
......@@ -67,6 +67,7 @@ namespace JSC { namespace FTL {
macro(P_JITOperation_EStSS, functionType(intPtr, intPtr, intPtr, intPtr, intPtr)) \
macro(P_JITOperation_EStZ, functionType(intPtr, intPtr, intPtr, int32)) \
macro(S_JITOperation_EJ, functionType(intPtr, intPtr, int64)) \
macro(S_JITOperation_EJJ, functionType(intPtr, intPtr, int64, int64)) \
macro(V_JITOperation_EJJJ, functionType(voidType, intPtr, int64, int64, int64)) \
macro(V_JITOperation_EOZD, functionType(voidType, intPtr, intPtr, int32, doubleType)) \
macro(V_JITOperation_EOZJ, functionType(voidType, intPtr, intPtr, int32, int64)) \
......
......@@ -2396,6 +2396,11 @@ private:
return;
}
if (m_node->isBinaryUseKind(UntypedUse)) {
nonSpeculativeCompare(LLVMIntEQ, operationCompareEq);
return;
}
RELEASE_ASSERT_NOT_REACHED();
}
......@@ -2464,106 +2469,22 @@ private:
void compileCompareLess()
{
if (m_node->isBinaryUseKind(Int32Use)) {
setBoolean(
m_out.lessThan(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
return;
}
if (m_node->isBinaryUseKind(MachineIntUse)) {
Int52Kind kind;
LValue left = lowWhicheverInt52(m_node->child1(), kind);
LValue right = lowInt52(m_node->child2(), kind);
setBoolean(m_out.lessThan(left, right));
return;
}
if (m_node->isBinaryUseKind(NumberUse)) {
setBoolean(
m_out.doubleLessThan(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
return;
}
RELEASE_ASSERT_NOT_REACHED();
compare(LLVMIntSLT, LLVMRealOLT, operationCompareLess);
}
void compileCompareLessEq()
{
if (m_node->isBinaryUseKind(Int32Use)) {
setBoolean(
m_out.lessThanOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
return;
}
if (m_node->isBinaryUseKind(MachineIntUse)) {
Int52Kind kind;
LValue left = lowWhicheverInt52(m_node->child1(), kind);
LValue right = lowInt52(m_node->child2(), kind);
setBoolean(m_out.lessThanOrEqual(left, right));
return;
}
if (m_node->isBinaryUseKind(NumberUse)) {
setBoolean(
m_out.doubleLessThanOrEqual(
lowDouble(m_node->child1()), lowDouble(m_node->child2())));
return;
}
RELEASE_ASSERT_NOT_REACHED();
compare(LLVMIntSLE, LLVMRealOLE, operationCompareLessEq);
}
void compileCompareGreater()
{
if (m_node->isBinaryUseKind(Int32Use)) {
setBoolean(
m_out.greaterThan(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
return;
}
if (m_node->isBinaryUseKind(MachineIntUse)) {
Int52Kind kind;
LValue left = lowWhicheverInt52(m_node->child1(), kind);
LValue right = lowInt52(m_node->child2(), kind);
setBoolean(m_out.greaterThan(left, right));
return;
}
if (m_node->isBinaryUseKind(NumberUse)) {
setBoolean(
m_out.doubleGreaterThan(
lowDouble(m_node->child1()), lowDouble(m_node->child2())));
return;
}
RELEASE_ASSERT_NOT_REACHED();
compare(LLVMIntSGT, LLVMRealOGT, operationCompareGreater);
}
void compileCompareGreaterEq()
{
if (m_node->isBinaryUseKind(Int32Use)) {
setBoolean(
m_out.greaterThanOrEqual(
lowInt32(m_node->child1()), lowInt32(m_node->child2())));
return;
}
if (m_node->isBinaryUseKind(MachineIntUse)) {
Int52Kind kind;
LValue left = lowWhicheverInt52(m_node->child1(), kind);
LValue right = lowInt52(m_node->child2(), kind);
setBoolean(m_out.greaterThanOrEqual(left, right));
return;
}
if (m_node->isBinaryUseKind(NumberUse)) {
setBoolean(
m_out.doubleGreaterThanOrEqual(
lowDouble(m_node->child1()), lowDouble(m_node->child2())));
return;
}
RELEASE_ASSERT_NOT_REACHED();
compare(LLVMIntSGE, LLVMRealOGE, operationCompareGreaterEq);
}
void compileLogicalNot()
......@@ -2800,6 +2721,69 @@ private:
m_state.forNode(edge).m_value);
}
void compare(
LIntPredicate intCondition, LRealPredicate realCondition,
S_JITOperation_EJJ helperFunction)
{
if (m_node->isBinaryUseKind(Int32Use)) {
LValue left = lowInt32(m_node->child1());
LValue right = lowInt32(m_node->child2());
setBoolean(m_out.icmp(intCondition, left, right));
return;
}
if (m_node->isBinaryUseKind(MachineIntUse)) {
Int52Kind kind;
LValue left = lowWhicheverInt52(m_node->child1(), kind);
LValue right = lowInt52(m_node->child2(), kind);
setBoolean(m_out.icmp(intCondition, left, right));
return;
}
if (m_node->isBinaryUseKind(NumberUse)) {
LValue left = lowDouble(m_node->child1());
LValue right = lowDouble(m_node->child2());
setBoolean(m_out.fcmp(realCondition, left, right));
return;
}
if (m_node->isBinaryUseKind(UntypedUse)) {
nonSpeculativeCompare(intCondition, helperFunction);
return;
}
RELEASE_ASSERT_NOT_REACHED();
}
void nonSpeculativeCompare(LIntPredicate intCondition, S_JITOperation_EJJ helperFunction)
{
LValue left = lowJSValue(m_node->child1());
LValue right = lowJSValue(m_node->child2());
LBasicBlock leftIsInt = FTL_NEW_BLOCK(m_out, ("CompareEq untyped left is int"));
LBasicBlock fastPath = FTL_NEW_BLOCK(m_out, ("CompareEq untyped fast path"));
LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("CompareEq untyped slow path"));
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareEq untyped continuation"));
m_out.branch(isNotInt32(left), slowPath, leftIsInt);
LBasicBlock lastNext = m_out.appendTo(leftIsInt, fastPath);
m_out.branch(isNotInt32(right), slowPath, fastPath);
m_out.appendTo(fastPath, slowPath);
ValueFromBlock fastResult = m_out.anchor(
m_out.icmp(intCondition, unboxInt32(left), unboxInt32(right)));
m_out.jump(continuation);
m_out.appendTo(slowPath, continuation);
ValueFromBlock slowResult = m_out.anchor(m_out.notNull(vmCall(
m_out.operation(helperFunction), m_callFrame, left, right)));
m_out.jump(continuation);
m_out.appendTo(continuation, lastNext);
setBoolean(m_out.phi(m_out.boolean, fastResult, slowResult));
}
LValue allocateCell(LValue allocator, LValue structure, LBasicBlock slowPath)
{
LBasicBlock success = FTL_NEW_BLOCK(m_out, ("object allocation success"));
......
......@@ -314,29 +314,31 @@ public:
void storePtr(LValue value, LValue base, const AbstractField& field) { storePtr(value, address(base, field)); }
void storeDouble(LValue value, LValue base, const AbstractField& field) { storeDouble(value, address(base, field)); }
LValue equal(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntEQ, left, right); }
LValue notEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntNE, left, right); }
LValue above(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntUGT, left, right); }
LValue aboveOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntUGE, left, right); }
LValue below(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntULT, left, right); }
LValue belowOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntULE, left, right); }
LValue greaterThan(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSGT, left, right); }
LValue greaterThanOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSGE, left, right); }
LValue lessThan(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSLT, left, right); }
LValue lessThanOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSLE, left, right); }
LValue doubleEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOEQ, left, right); }
LValue doubleNotEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUNE, left, right); }
LValue doubleLessThan(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOLT, left, right); }
LValue doubleLessThanOrEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOLE, left, right); }
LValue doubleGreaterThan(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOGT, left, right); }
LValue doubleGreaterThanOrEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOGE, left, right); }
LValue doubleEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUEQ, left, right); }
LValue doubleNotEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealONE, left, right); }
LValue doubleLessThanOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealULT, left, right); }
LValue doubleLessThanOrEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealULE, left, right); }
LValue doubleGreaterThanOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUGT, left, right); }
LValue doubleGreaterThanOrEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUGE, left, right); }
LValue icmp(LIntPredicate cond, LValue left, LValue right) { return buildICmp(m_builder, cond, left, right); }
LValue equal(LValue left, LValue right) { return icmp(LLVMIntEQ, left, right); }
LValue notEqual(LValue left, LValue right) { return icmp(LLVMIntNE, left, right); }
LValue above(LValue left, LValue right) { return icmp(LLVMIntUGT, left, right); }
LValue aboveOrEqual(LValue left, LValue right) { return icmp(LLVMIntUGE, left, right); }
LValue below(LValue left, LValue right) { return icmp(LLVMIntULT, left, right); }
LValue belowOrEqual(LValue left, LValue right) { return icmp(LLVMIntULE, left, right); }
LValue greaterThan(LValue left, LValue right) { return icmp(LLVMIntSGT, left, right); }
LValue greaterThanOrEqual(LValue left, LValue right) { return icmp(LLVMIntSGE, left, right); }
LValue lessThan(LValue left, LValue right) { return icmp(LLVMIntSLT, left, right); }
LValue lessThanOrEqual(LValue left, LValue right) { return icmp(LLVMIntSLE, left, right); }
LValue fcmp(LRealPredicate cond, LValue left, LValue right) { return buildFCmp(m_builder, cond, left, right); }
LValue doubleEqual(LValue left, LValue right) { return fcmp(LLVMRealOEQ, left, right); }
LValue doubleNotEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUNE, left, right); }
LValue doubleLessThan(LValue left, LValue right) { return fcmp(LLVMRealOLT, left, right); }
LValue doubleLessThanOrEqual(LValue left, LValue right) { return fcmp(LLVMRealOLE, left, right); }
LValue doubleGreaterThan(LValue left, LValue right) { return fcmp(LLVMRealOGT, left, right); }
LValue doubleGreaterThanOrEqual(LValue left, LValue right) { return fcmp(LLVMRealOGE, left, right); }
LValue doubleEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUEQ, left, right); }
LValue doubleNotEqual(LValue left, LValue right) { return fcmp(LLVMRealONE, left, right); }
LValue doubleLessThanOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealULT, left, right); }
LValue doubleLessThanOrEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealULE, left, right); }
LValue doubleGreaterThanOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUGT, left, right); }
LValue doubleGreaterThanOrEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUGE, left, right); }
LValue isZero8(LValue value) { return equal(value, int8Zero); }
LValue notZero8(LValue value) { return notEqual(value, int8Zero); }
......
function foo(a, b) {
return a == b;
}
noInline(foo);
var data = [
[5, 6.5, false],
["foo", "bar", false],
[true, false, false],
["42", 42, true],
[1.2, 1.2, true]
];
for (var i = 0; i < 100000; ++i) {
var test = data[i % data.length];
var result = foo(test[0], test[1]);
if (result != test[2])
throw "Error: bad result for " + test + ": " + result;
}
function foo(a, b) {
return a < b;
}
noInline(foo);
var data = [
[5, 6.5, true],
["foo", "bar", false],
[true, false, false],
[false, true, true],
["42", 42, false],
[1.2, 1.2, false],
["-1", 1, true],
[-1, "1", true]
];
for (var i = 0; i < 100000; ++i) {
var test = data[i % data.length];
var result = foo(test[0], test[1]);
if (result != test[2])
throw "Error: bad result for " + test + ": " + result;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment