summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp b/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp
new file mode 100644
index 000000000..f55533a61
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGArithNodeFlagsInferencePhase.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGGraph.h"
+#include "DFGPhase.h"
+
+namespace JSC { namespace DFG {
+
+class ArithNodeFlagsInferencePhase : public Phase {
+public:
+ ArithNodeFlagsInferencePhase(Graph& graph)
+ : Phase(graph, "arithmetic node flags inference")
+ {
+ }
+
+ void run()
+ {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ m_count = 0;
+#endif
+ do {
+ m_changed = false;
+
+ // Up here we start with a backward pass because we suspect that to be
+ // more profitable.
+ propagateBackward();
+ if (!m_changed)
+ break;
+
+ m_changed = false;
+ propagateForward();
+ } while (m_changed);
+ }
+
+private:
+ bool isNotNegZero(NodeIndex nodeIndex)
+ {
+ if (!m_graph.isNumberConstant(nodeIndex))
+ return false;
+ double value = m_graph.valueOfNumberConstant(nodeIndex);
+ return !value && 1.0 / value < 0.0;
+ }
+
+ bool isNotZero(NodeIndex nodeIndex)
+ {
+ if (!m_graph.isNumberConstant(nodeIndex))
+ return false;
+ return !!m_graph.valueOfNumberConstant(nodeIndex);
+ }
+
+ void propagate(Node& node)
+ {
+ if (!node.shouldGenerate())
+ return;
+
+ NodeType op = node.op;
+ ArithNodeFlags flags = 0;
+
+ if (node.hasArithNodeFlags())
+ flags = node.rawArithNodeFlags();
+
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog(" %s @%u: %s ", Graph::opName(op), m_compileIndex, arithNodeFlagsAsString(flags));
+#endif
+
+ flags &= NodeUsedAsMask;
+
+ bool changed = false;
+
+ switch (op) {
+ case ValueToInt32:
+ case BitAnd:
+ case BitOr:
+ case BitXor:
+ case BitLShift:
+ case BitRShift:
+ case BitURShift: {
+ // These operations are perfectly happy with truncated integers,
+ // so we don't want to propagate anything.
+ break;
+ }
+
+ case UInt32ToNumber: {
+ changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+ break;
+ }
+
+ case ArithAdd:
+ case ValueAdd: {
+ if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
+ flags &= ~NodeNeedsNegZero;
+
+ changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+ changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
+ break;
+ }
+
+ case ArithSub: {
+ if (isNotZero(node.child1().index()) || isNotZero(node.child2().index()))
+ flags &= ~NodeNeedsNegZero;
+
+ changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+ changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
+ break;
+ }
+
+ case ArithMul:
+ case ArithDiv: {
+ // As soon as a multiply happens, we can easily end up in the part
+ // of the double domain where the point at which you do truncation
+ // can change the outcome. So, ArithMul always checks for overflow
+ // no matter what, and always forces its inputs to check as well.
+
+ flags |= NodeUsedAsNumber | NodeNeedsNegZero;
+ changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+ changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
+ break;
+ }
+
+ case ArithMin:
+ case ArithMax: {
+ flags |= NodeUsedAsNumber;
+ changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+ changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
+ break;
+ }
+
+ case ArithAbs: {
+ flags &= ~NodeNeedsNegZero;
+ changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+ break;
+ }
+
+ case PutByVal: {
+ changed |= m_graph[node.child1()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
+ changed |= m_graph[node.child2()].mergeArithNodeFlags(flags | NodeUsedAsNumber);
+ changed |= m_graph[node.child3()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
+ break;
+ }
+
+ case GetByVal: {
+ changed |= m_graph[node.child1()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
+ changed |= m_graph[node.child2()].mergeArithNodeFlags(flags | NodeUsedAsNumber);
+ break;
+ }
+
+ default:
+ flags |= NodeUsedAsNumber | NodeNeedsNegZero;
+ if (op & NodeHasVarArgs) {
+ for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
+ changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeArithNodeFlags(flags);
+ } else {
+ if (!node.child1())
+ break;
+ changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+ if (!node.child2())
+ break;
+ changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
+ if (!node.child3())
+ break;
+ changed |= m_graph[node.child3()].mergeArithNodeFlags(flags);
+ }
+ break;
+ }
+
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog("%s\n", changed ? "CHANGED" : "");
+#endif
+
+ m_changed |= changed;
+ }
+
+ void propagateForward()
+ {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog("Propagating arithmetic node flags forward [%u]\n", ++m_count);
+#endif
+ for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
+ propagate(m_graph[m_compileIndex]);
+ }
+
+ void propagateBackward()
+ {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog("Propagating arithmetic node flags backward [%u]\n", ++m_count);
+#endif
+ for (m_compileIndex = m_graph.size(); m_compileIndex-- > 0;)
+ propagate(m_graph[m_compileIndex]);
+ }
+
+ NodeIndex m_compileIndex;
+ bool m_changed;
+};
+
+void performArithNodeFlagsInference(Graph& graph)
+{
+ runPhase<ArithNodeFlagsInferencePhase>(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+