[JSC] Commute FDiv-by-constant into FMul-by-reciprocal when it is safe
https://bugs.webkit.org/show_bug.cgi?id=156871
Patch by Benjamin Poulain <bpoulain@webkit.org> on 2016-04-21
Reviewed by Filip Pizlo.
FMul is significantly faster than FDiv.
For example, on Haswell, FMul has a latency of 5, a throughput of 1
while FDiv has latency 10-24, throughput 8-18.
Fortunately for us, Sunspider and Kraken have plenty of division
by a simple power of 2 constant. Those are just exponent operations
and can be easily reversed to use FMul instead of FDiv.
LLVM does something similar in InstCombine.
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
* jit/JITDivGenerator.cpp:
(JSC::JITDivGenerator::loadOperand):
(JSC::JITDivGenerator::generateFastPath):
* jit/SnippetOperand.h:
(JSC::SnippetOperand::asConstNumber):
* runtime/MathCommon.h:
(JSC::safeReciprocalForDivByConst):
* tests/stress/floating-point-div-to-mul.js: Added.
(opaqueDivBy2):
(opaqueDivBy3):
(opaqueDivBy4):
(opaqueDivBySafeMaxMinusOne):
(opaqueDivBySafeMax):
(opaqueDivBySafeMaxPlusOne):
(opaqueDivBySafeMin):
(opaqueDivBySafeMinMinusOne):
(i.catch):
(i.result.opaqueDivBySafeMin.valueOf):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@199866 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
index 49a92c58..c263cd8 100644
--- a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
@@ -36,6 +36,7 @@
#include "DFGPredictionPropagationPhase.h"
#include "DFGVariableAccessDataDump.h"
#include "JSCInlines.h"
+#include "MathCommon.h"
#include "RegExpConstructor.h"
#include "StringPrototype.h"
#include <cstdlib>
@@ -192,6 +193,25 @@
}
break;
+ case ArithDiv:
+ // Transform
+ // ArithDiv(x, constant)
+ // Into
+ // ArithMul(x, 1 / constant)
+ // if the operation has the same result.
+ if (m_node->isBinaryUseKind(DoubleRepUse)
+ && m_node->child2()->isNumberConstant()) {
+
+ if (Optional<double> reciprocal = safeReciprocalForDivByConst(m_node->child2()->asNumber())) {
+ Node* reciprocalNode = m_insertionSet.insertConstant(m_nodeIndex, m_node->origin, jsDoubleNumber(*reciprocal), DoubleConstant);
+ m_node->setOp(ArithMul);
+ m_node->child2() = Edge(reciprocalNode, DoubleRepUse);
+ m_changed = true;
+ break;
+ }
+ }
+ break;
+
case ValueRep:
case Int52Rep:
case DoubleRep: {