diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp | 230 |
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) + |