[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: {