From: fpizlo@apple.com Date: Sun, 18 Sep 2011 22:29:41 +0000 (+0000) Subject: DFG JIT should inline Math.min, Math.max, and Math.sqrt X-Git-Tag: 070512121124~24188 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4e87ceebde0bf0674295c69027fa21db01925add;p=profile%2Fivi%2Fwebkit-efl.git DFG JIT should inline Math.min, Math.max, and Math.sqrt https://bugs.webkit.org/show_bug.cgi?id=68318 Reviewed by Gavin Barraclough. Adds Math.min, Math.max, and Math.sqrt intrinsics. Adds support for a function to have an intrinsic but not a thunk generator. This is a 7% speed-up on access-nbody, and neutral elsewhere, mainly because we're still not DFG compiling the bulk of the hot code in Kraken audio benchmarks. * create_hash_table: * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::handleMinMax): (JSC::DFG::ByteCodeParser::handleIntrinsic): * dfg/DFGIntrinsic.h: * dfg/DFGNode.h: * dfg/DFGPropagator.cpp: (JSC::DFG::Propagator::propagateNode): (JSC::DFG::Propagator::fixupNode): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::compile): * jit/JITStubs.cpp: (JSC::JITThunks::hostFunctionStub): * runtime/Lookup.cpp: (JSC::setUpStaticFunctionSlot): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@95399 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 744d1a8..24d8cc8 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,32 @@ +2011-09-17 Filip Pizlo + + DFG JIT should inline Math.min, Math.max, and Math.sqrt + https://bugs.webkit.org/show_bug.cgi?id=68318 + + Reviewed by Gavin Barraclough. + + Adds Math.min, Math.max, and Math.sqrt intrinsics. Adds support for + a function to have an intrinsic but not a thunk generator. This is + a 7% speed-up on access-nbody, and neutral elsewhere, mainly because + we're still not DFG compiling the bulk of the hot code in Kraken audio + benchmarks. + + * create_hash_table: + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleMinMax): + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGIntrinsic.h: + * dfg/DFGNode.h: + * dfg/DFGPropagator.cpp: + (JSC::DFG::Propagator::propagateNode): + (JSC::DFG::Propagator::fixupNode): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JITStubs.cpp: + (JSC::JITThunks::hostFunctionStub): + * runtime/Lookup.cpp: + (JSC::setUpStaticFunctionSlot): + 2011-09-18 Nico Weber Remove two files from JavaScriptCore.gypi that were removed in r95240 diff --git a/Source/JavaScriptCore/create_hash_table b/Source/JavaScriptCore/create_hash_table index 3bb9cc2..ab8e8a0 100755 --- a/Source/JavaScriptCore/create_hash_table +++ b/Source/JavaScriptCore/create_hash_table @@ -288,8 +288,15 @@ sub output() { $thunkGenerator = "fromCharCodeThunkGenerator"; } if ($name eq "mathTable") { + if ($key eq "min") { + $intrinsic = "DFG::MinIntrinsic"; + } + if ($key eq "max") { + $intrinsic = "DFG::MaxIntrinsic"; + } if ($key eq "sqrt") { $thunkGenerator = "sqrtThunkGenerator"; + $intrinsic = "DFG::SqrtIntrinsic"; } if ($key eq "pow") { $thunkGenerator = "powThunkGenerator"; diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 1ad4441..a05fa77 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -64,6 +64,9 @@ public: bool parse(); private: + // Helper for min and max. + bool handleMinMax(bool usesResult, int resultOperand, NodeType op, int firstArg, int lastArg); + // Handle intrinsic functions. bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int firstArg, int lastArg); // Parse a single basic block of bytecode instructions. @@ -600,6 +603,30 @@ private: m_currentIndex += OPCODE_LENGTH(name); \ return !m_parseFailed +bool ByteCodeParser::handleMinMax(bool usesResult, int resultOperand, NodeType op, int firstArg, int lastArg) +{ + if (!usesResult) + return true; + + if (lastArg == firstArg) { + set(resultOperand, constantNaN()); + return true; + } + + if (lastArg == firstArg + 1) { + set(resultOperand, getToNumber(firstArg + 1)); + return true; + } + + if (lastArg == firstArg + 2) { + set(resultOperand, addToGraph(op, getToNumber(firstArg + 1), getToNumber(firstArg + 2))); + return true; + } + + // Don't handle >=3 arguments for now. + return false; +} + bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int firstArg, int lastArg) { switch (intrinsic) { @@ -620,6 +647,25 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return true; } + case MinIntrinsic: + return handleMinMax(usesResult, resultOperand, ArithMin, firstArg, lastArg); + + case MaxIntrinsic: + return handleMinMax(usesResult, resultOperand, ArithMax, firstArg, lastArg); + + case SqrtIntrinsic: { + if (!usesResult) + return true; + + if (firstArg == lastArg) { + set(resultOperand, constantNaN()); + return true; + } + + set(resultOperand, addToGraph(ArithSqrt, getToNumber(firstArg + 1))); + return true; + } + default: ASSERT(intrinsic == NoIntrinsic); return false; diff --git a/Source/JavaScriptCore/dfg/DFGIntrinsic.h b/Source/JavaScriptCore/dfg/DFGIntrinsic.h index e18c50e..fefff46 100644 --- a/Source/JavaScriptCore/dfg/DFGIntrinsic.h +++ b/Source/JavaScriptCore/dfg/DFGIntrinsic.h @@ -30,7 +30,10 @@ namespace JSC { namespace DFG { enum Intrinsic { NoIntrinsic, - AbsIntrinsic + AbsIntrinsic, + MinIntrinsic, + MaxIntrinsic, + SqrtIntrinsic }; } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index 0457a54..8cd22b6 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -155,6 +155,9 @@ private: macro(ArithDiv, NodeResultNumber) \ macro(ArithMod, NodeResultNumber) \ macro(ArithAbs, NodeResultNumber) \ + macro(ArithMin, NodeResultNumber) \ + macro(ArithMax, NodeResultNumber) \ + macro(ArithSqrt, NodeResultNumber) \ /* Arithmetic operators call ToNumber on their operands. */\ macro(ValueToNumber, NodeResultNumber | NodeMustGenerate) \ \ diff --git a/Source/JavaScriptCore/dfg/DFGPropagator.cpp b/Source/JavaScriptCore/dfg/DFGPropagator.cpp index a4e5d0f..9632e47 100644 --- a/Source/JavaScriptCore/dfg/DFGPropagator.cpp +++ b/Source/JavaScriptCore/dfg/DFGPropagator.cpp @@ -225,7 +225,9 @@ private: case ArithAdd: case ArithSub: - case ArithMul: { + case ArithMul: + case ArithMin: + case ArithMax: { PredictedType left = m_predictions[node.child1()]; PredictedType right = m_predictions[node.child2()]; @@ -238,7 +240,8 @@ private: break; } - case ArithDiv: { + case ArithDiv: + case ArithSqrt: { changed |= setPrediction(makePrediction(PredictDouble, StrongPrediction)); break; } @@ -405,7 +408,9 @@ private: case ArithAdd: case ArithSub: - case ArithMul: { + case ArithMul: + case ArithMin: + case ArithMax: { PredictedType left = m_predictions[node.child1()]; PredictedType right = m_predictions[node.child2()]; @@ -424,6 +429,18 @@ private: break; } + case ArithAbs: { + PredictedType prediction = m_predictions[node.child1()]; + if (isStrongPrediction(prediction) && (prediction & PredictDouble)) + toDouble(node.child1()); + break; + } + + case ArithSqrt: { + toDouble(node.child1()); + break; + } + default: break; } @@ -730,6 +747,9 @@ private: case ArithMod: case ArithDiv: case ArithAbs: + case ArithMin: + case ArithMax: + case ArithSqrt: setReplacement(pureCSE(node)); break; diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 35d3cd1..7749ce1 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -1083,6 +1083,70 @@ void SpeculativeJIT::compile(Node& node) doubleResult(result.fpr(), m_compileIndex); break; } + + case ArithMin: + case ArithMax: { + if (shouldSpeculateInteger(node.child1(), node.child2())) { + SpeculateIntegerOperand op1(this, node.child1()); + SpeculateIntegerOperand op2(this, node.child2()); + GPRTemporary result(this, op1); + + MacroAssembler::Jump op1Less = m_jit.branch32(op == ArithMin ? MacroAssembler::LessThan : MacroAssembler::GreaterThan, op1.gpr(), op2.gpr()); + m_jit.move(op2.gpr(), result.gpr()); + if (op1.gpr() != result.gpr()) { + MacroAssembler::Jump done = m_jit.jump(); + op1Less.link(&m_jit); + m_jit.move(op1.gpr(), result.gpr()); + done.link(&m_jit); + } else + op1Less.link(&m_jit); + + integerResult(result.gpr(), m_compileIndex); + break; + } + + SpeculateDoubleOperand op1(this, node.child1()); + SpeculateDoubleOperand op2(this, node.child2()); + FPRTemporary result(this, op1); + + MacroAssembler::JumpList done; + + MacroAssembler::Jump op1Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1.fpr(), op2.fpr()); + + // op2 is eather the lesser one or one of then is NaN + MacroAssembler::Jump op2Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleGreaterThan : MacroAssembler::DoubleLessThan, op1.fpr(), op2.fpr()); + + // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding + // op1 + op2 and putting it into result. + m_jit.addDouble(op1.fpr(), op2.fpr(), result.fpr()); + done.append(m_jit.jump()); + + op2Less.link(&m_jit); + m_jit.moveDouble(op2.fpr(), result.fpr()); + + if (op1.fpr() != result.fpr()) { + done.append(m_jit.jump()); + + op1Less.link(&m_jit); + m_jit.moveDouble(op1.fpr(), result.fpr()); + } else + op1Less.link(&m_jit); + + done.link(&m_jit); + + doubleResult(result.fpr(), m_compileIndex); + break; + } + + case ArithSqrt: { + SpeculateDoubleOperand op1(this, node.child1()); + FPRTemporary result(this, op1); + + m_jit.sqrtDouble(op1.fpr(), result.fpr()); + + doubleResult(result.fpr(), m_compileIndex); + break; + } case LogicalNot: { if (isKnownBoolean(node.child1())) { diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index 0d9849b..18e97ef 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -3783,7 +3783,14 @@ NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFu { std::pair entry = m_hostFunctionStubMap->add(function, Weak()); if (!*entry.first->second) { - MacroAssemblerCodeRef code = globalData->canUseJIT() ? generator(globalData) : MacroAssemblerCodeRef(); + MacroAssemblerCodeRef code; + if (generator) { + if (globalData->canUseJIT()) + code = generator(globalData); + else + code = MacroAssemblerCodeRef(); + } else + code = JIT::compileCTINativeCall(globalData, function); entry.first->second.set(*globalData, NativeExecutable::create(*globalData, code, function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), callHostFunctionAsConstructor, intrinsic)); } return entry.first->second.get(); diff --git a/Source/JavaScriptCore/runtime/Lookup.cpp b/Source/JavaScriptCore/runtime/Lookup.cpp index 57c8187..b489599 100644 --- a/Source/JavaScriptCore/runtime/Lookup.cpp +++ b/Source/JavaScriptCore/runtime/Lookup.cpp @@ -81,7 +81,7 @@ void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* JSFunction* function; JSGlobalObject* globalObject = thisObj->globalObject(); #if ENABLE(JIT) - if (entry->generator()) + if (entry->generator() || entry->intrinsic() != DFG::NoIntrinsic) function = JSFunction::create(exec, globalObject, globalObject->functionStructure(), entry->functionLength(), propertyName, exec->globalData().getHostFunction(entry->function(), entry->generator(), entry->intrinsic())); else #endif