7e3250449b23dd2dad249fac927c0316d4e336e6
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGArithNodeFlagsInferencePhase.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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. 
24  */
25
26 #include "config.h"
27 #include "DFGArithNodeFlagsInferencePhase.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGGraph.h"
32 #include "DFGPhase.h"
33
34 namespace JSC { namespace DFG {
35
36 class ArithNodeFlagsInferencePhase: public Phase {
37 public:
38     ArithNodeFlagsInferencePhase(Graph& graph)
39         : Phase(graph, "arithmetic node flags inference")
40     {
41     }
42     
43     void run()
44     {
45 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
46         m_count = 0;
47 #endif
48         do {
49             m_changed = false;
50             
51             // Up here we start with a backward pass because we suspect that to be
52             // more profitable.
53             propagateBackward();
54             if (!m_changed)
55                 break;
56             
57             m_changed = false;
58             propagateForward();
59         } while (m_changed);
60     }
61     
62 private:
63     bool isNotNegZero(NodeIndex nodeIndex)
64     {
65         if (!m_graph.isNumberConstant(nodeIndex))
66             return false;
67         double value = m_graph.valueOfNumberConstant(nodeIndex);
68         return !value && 1.0 / value < 0.0;
69     }
70     
71     bool isNotZero(NodeIndex nodeIndex)
72     {
73         if (!m_graph.isNumberConstant(nodeIndex))
74             return false;
75         return !!m_graph.valueOfNumberConstant(nodeIndex);
76     }
77     
78     void propagate(Node& node)
79     {
80         if (!node.shouldGenerate())
81             return;
82         
83         NodeType op = node.op;
84         ArithNodeFlags flags = 0;
85         
86         if (node.hasArithNodeFlags())
87             flags = node.rawArithNodeFlags();
88         
89 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
90         dataLog("   %s @%u: %s ", Graph::opName(op), m_compileIndex, arithNodeFlagsAsString(flags));
91 #endif
92         
93         flags &= NodeUsedAsMask;
94         
95         bool changed = false;
96         
97         switch (op) {
98         case ValueToInt32:
99         case BitAnd:
100         case BitOr:
101         case BitXor:
102         case BitLShift:
103         case BitRShift:
104         case BitURShift: {
105             // These operations are perfectly happy with truncated integers,
106             // so we don't want to propagate anything.
107             break;
108         }
109             
110         case UInt32ToNumber: {
111             changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
112             break;
113         }
114             
115         case ArithAdd:
116         case ValueAdd: {
117             if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
118                 flags &= ~NodeNeedsNegZero;
119             
120             changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
121             changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
122             break;
123         }
124             
125         case ArithSub: {
126             if (isNotZero(node.child1().index()) || isNotZero(node.child2().index()))
127                 flags &= ~NodeNeedsNegZero;
128             
129             changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
130             changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
131             break;
132         }
133             
134         case ArithMul:
135         case ArithDiv: {
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.
140             
141             flags |= NodeUsedAsNumber | NodeNeedsNegZero;
142             changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
143             changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
144             break;
145         }
146             
147         case ArithMin:
148         case ArithMax: {
149             flags |= NodeUsedAsNumber;
150             changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
151             changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
152             break;
153         }
154             
155         case ArithAbs: {
156             flags &= ~NodeNeedsNegZero;
157             changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
158             break;
159         }
160             
161         case PutByVal: {
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);
165             break;
166         }
167             
168         case GetByVal: {
169             changed |= m_graph[node.child1()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
170             changed |= m_graph[node.child2()].mergeArithNodeFlags(flags | NodeUsedAsNumber);
171             break;
172         }
173             
174         default:
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);
179             } else {
180                 if (!node.child1())
181                     break;
182                 changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
183                 if (!node.child2())
184                     break;
185                 changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
186                 if (!node.child3())
187                     break;
188                 changed |= m_graph[node.child3()].mergeArithNodeFlags(flags);
189             }
190             break;
191         }
192
193 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
194         dataLog("%s\n", changed ? "CHANGED" : "");
195 #endif
196         
197         m_changed |= changed;
198     }
199     
200     void propagateForward()
201     {
202 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
203         dataLog("Propagating arithmetic node flags forward [%u]\n", ++m_count);
204 #endif
205         for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
206             propagate(m_graph[m_compileIndex]);
207     }
208     
209     void propagateBackward()
210     {
211 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
212         dataLog("Propagating arithmetic node flags backward [%u]\n", ++m_count);
213 #endif
214         for (m_compileIndex = m_graph.size(); m_compileIndex-- > 0;)
215             propagate(m_graph[m_compileIndex]);
216     }
217     
218     NodeIndex m_compileIndex;
219     bool m_changed;
220 };
221
222 void performArithNodeFlagsInference(Graph& graph)
223 {
224     runPhase<ArithNodeFlagsInferencePhase>(graph);
225 }
226
227 } } // namespace JSC::DFG
228
229 #endif // ENABLE(DFG_JIT)
230