2 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "DFGArithNodeFlagsInferencePhase.h"
34 namespace JSC { namespace DFG {
36 class ArithNodeFlagsInferencePhase : public Phase {
38 ArithNodeFlagsInferencePhase(Graph& graph)
39 : Phase(graph, "arithmetic node flags inference")
45 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
51 // Up here we start with a backward pass because we suspect that to be
63 bool isNotNegZero(NodeIndex nodeIndex)
65 if (!m_graph.isNumberConstant(nodeIndex))
67 double value = m_graph.valueOfNumberConstant(nodeIndex);
68 return !value && 1.0 / value < 0.0;
71 bool isNotZero(NodeIndex nodeIndex)
73 if (!m_graph.isNumberConstant(nodeIndex))
75 return !!m_graph.valueOfNumberConstant(nodeIndex);
78 void propagate(Node& node)
80 if (!node.shouldGenerate())
83 NodeType op = node.op;
84 ArithNodeFlags flags = 0;
86 if (node.hasArithNodeFlags())
87 flags = node.rawArithNodeFlags();
89 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
90 dataLog(" %s @%u: %s ", Graph::opName(op), m_compileIndex, arithNodeFlagsAsString(flags));
93 flags &= NodeUsedAsMask;
105 // These operations are perfectly happy with truncated integers,
106 // so we don't want to propagate anything.
110 case UInt32ToNumber: {
111 changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
117 if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
118 flags &= ~NodeNeedsNegZero;
120 changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
121 changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
126 if (isNotZero(node.child1().index()) || isNotZero(node.child2().index()))
127 flags &= ~NodeNeedsNegZero;
129 changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
130 changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
136 // As soon as a multiply happens, we can easily end up in the part
137 // of the double domain where the point at which you do truncation
138 // can change the outcome. So, ArithMul always checks for overflow
139 // no matter what, and always forces its inputs to check as well.
141 flags |= NodeUsedAsNumber | NodeNeedsNegZero;
142 changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
143 changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
149 flags |= NodeUsedAsNumber;
150 changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
151 changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
156 flags &= ~NodeNeedsNegZero;
157 changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
162 changed |= m_graph[node.child1()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
163 changed |= m_graph[node.child2()].mergeArithNodeFlags(flags | NodeUsedAsNumber);
164 changed |= m_graph[node.child3()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
169 changed |= m_graph[node.child1()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
170 changed |= m_graph[node.child2()].mergeArithNodeFlags(flags | NodeUsedAsNumber);
175 flags |= NodeUsedAsNumber | NodeNeedsNegZero;
176 if (op & NodeHasVarArgs) {
177 for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
178 changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeArithNodeFlags(flags);
182 changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
185 changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
188 changed |= m_graph[node.child3()].mergeArithNodeFlags(flags);
193 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
194 dataLog("%s\n", changed ? "CHANGED" : "");
197 m_changed |= changed;
200 void propagateForward()
202 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
203 dataLog("Propagating arithmetic node flags forward [%u]\n", ++m_count);
205 for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
206 propagate(m_graph[m_compileIndex]);
209 void propagateBackward()
211 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
212 dataLog("Propagating arithmetic node flags backward [%u]\n", ++m_count);
214 for (m_compileIndex = m_graph.size(); m_compileIndex-- > 0;)
215 propagate(m_graph[m_compileIndex]);
218 NodeIndex m_compileIndex;
222 void performArithNodeFlagsInference(Graph& graph)
224 runPhase<ArithNodeFlagsInferencePhase>(graph);
227 } } // namespace JSC::DFG
229 #endif // ENABLE(DFG_JIT)