• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/compiler/simplified-operator-reducer.h"
6 
7 #include "src/compiler/common-operator.h"
8 #include "src/compiler/js-graph.h"
9 #include "src/compiler/js-heap-broker.h"
10 #include "src/compiler/machine-operator.h"
11 #include "src/compiler/node-matchers.h"
12 #include "src/compiler/opcodes.h"
13 #include "src/compiler/operator-properties.h"
14 #include "src/compiler/simplified-operator.h"
15 #include "src/compiler/type-cache.h"
16 #include "src/numbers/conversions-inl.h"
17 
18 namespace v8 {
19 namespace internal {
20 namespace compiler {
21 
22 namespace {
23 
DecideObjectIsSmi(Node * const input)24 Decision DecideObjectIsSmi(Node* const input) {
25   NumberMatcher m(input);
26   if (m.HasResolvedValue()) {
27     return IsSmiDouble(m.ResolvedValue()) ? Decision::kTrue : Decision::kFalse;
28   }
29   if (m.IsAllocate()) return Decision::kFalse;
30   if (m.IsChangeBitToTagged()) return Decision::kFalse;
31   if (m.IsChangeInt31ToTaggedSigned()) return Decision::kTrue;
32   if (m.IsHeapConstant()) return Decision::kFalse;
33   return Decision::kUnknown;
34 }
35 
36 }  // namespace
37 
SimplifiedOperatorReducer(Editor * editor,JSGraph * jsgraph,JSHeapBroker * broker,BranchSemantics branch_semantics)38 SimplifiedOperatorReducer::SimplifiedOperatorReducer(
39     Editor* editor, JSGraph* jsgraph, JSHeapBroker* broker,
40     BranchSemantics branch_semantics)
41     : AdvancedReducer(editor),
42       jsgraph_(jsgraph),
43       broker_(broker),
44       branch_semantics_(branch_semantics) {}
45 
46 SimplifiedOperatorReducer::~SimplifiedOperatorReducer() = default;
47 
48 
Reduce(Node * node)49 Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
50   switch (node->opcode()) {
51     case IrOpcode::kBooleanNot: {
52       HeapObjectMatcher m(node->InputAt(0));
53       if (m.Is(factory()->true_value())) return ReplaceBoolean(false);
54       if (m.Is(factory()->false_value())) return ReplaceBoolean(true);
55       if (m.IsBooleanNot()) return Replace(m.InputAt(0));
56       break;
57     }
58     case IrOpcode::kChangeBitToTagged: {
59       Int32Matcher m(node->InputAt(0));
60       if (m.Is(0)) return Replace(jsgraph()->FalseConstant());
61       if (m.Is(1)) return Replace(jsgraph()->TrueConstant());
62       if (m.IsChangeTaggedToBit()) return Replace(m.InputAt(0));
63       break;
64     }
65     case IrOpcode::kChangeTaggedToBit: {
66       HeapObjectMatcher m(node->InputAt(0));
67       if (m.HasResolvedValue()) {
68         base::Optional<bool> maybe_result =
69             m.Ref(broker()).TryGetBooleanValue();
70         if (maybe_result.has_value()) return ReplaceInt32(*maybe_result);
71       }
72       if (m.IsChangeBitToTagged()) return Replace(m.InputAt(0));
73       break;
74     }
75     case IrOpcode::kChangeFloat64ToTagged: {
76       Float64Matcher m(node->InputAt(0));
77       if (m.HasResolvedValue()) return ReplaceNumber(m.ResolvedValue());
78       if (m.IsChangeTaggedToFloat64()) return Replace(m.node()->InputAt(0));
79       break;
80     }
81     case IrOpcode::kChangeInt31ToTaggedSigned:
82     case IrOpcode::kChangeInt32ToTagged: {
83       Int32Matcher m(node->InputAt(0));
84       if (m.HasResolvedValue()) return ReplaceNumber(m.ResolvedValue());
85       if (m.IsChangeTaggedSignedToInt32()) {
86         return Replace(m.InputAt(0));
87       }
88       break;
89     }
90     case IrOpcode::kChangeTaggedToFloat64:
91     case IrOpcode::kTruncateTaggedToFloat64: {
92       NumberMatcher m(node->InputAt(0));
93       if (m.HasResolvedValue()) return ReplaceFloat64(m.ResolvedValue());
94       if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) {
95         return Replace(m.node()->InputAt(0));
96       }
97       if (m.IsChangeInt31ToTaggedSigned() || m.IsChangeInt32ToTagged()) {
98         return Change(node, machine()->ChangeInt32ToFloat64(), m.InputAt(0));
99       }
100       if (m.IsChangeUint32ToTagged()) {
101         return Change(node, machine()->ChangeUint32ToFloat64(), m.InputAt(0));
102       }
103       break;
104     }
105     case IrOpcode::kChangeTaggedSignedToInt32:
106     case IrOpcode::kChangeTaggedToInt32: {
107       NumberMatcher m(node->InputAt(0));
108       if (m.HasResolvedValue())
109         return ReplaceInt32(DoubleToInt32(m.ResolvedValue()));
110       if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) {
111         return Change(node, machine()->ChangeFloat64ToInt32(), m.InputAt(0));
112       }
113       if (m.IsChangeInt31ToTaggedSigned() || m.IsChangeInt32ToTagged()) {
114         return Replace(m.InputAt(0));
115       }
116       break;
117     }
118     case IrOpcode::kChangeTaggedToUint32: {
119       NumberMatcher m(node->InputAt(0));
120       if (m.HasResolvedValue())
121         return ReplaceUint32(DoubleToUint32(m.ResolvedValue()));
122       if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) {
123         return Change(node, machine()->ChangeFloat64ToUint32(), m.InputAt(0));
124       }
125       if (m.IsChangeUint32ToTagged()) return Replace(m.InputAt(0));
126       break;
127     }
128     case IrOpcode::kChangeUint32ToTagged: {
129       Uint32Matcher m(node->InputAt(0));
130       if (m.HasResolvedValue())
131         return ReplaceNumber(FastUI2D(m.ResolvedValue()));
132       break;
133     }
134     case IrOpcode::kTruncateTaggedToWord32: {
135       NumberMatcher m(node->InputAt(0));
136       if (m.HasResolvedValue())
137         return ReplaceInt32(DoubleToInt32(m.ResolvedValue()));
138       if (m.IsChangeInt31ToTaggedSigned() || m.IsChangeInt32ToTagged() ||
139           m.IsChangeUint32ToTagged()) {
140         return Replace(m.InputAt(0));
141       }
142       if (m.IsChangeFloat64ToTagged() || m.IsChangeFloat64ToTaggedPointer()) {
143         return Change(node, machine()->TruncateFloat64ToWord32(), m.InputAt(0));
144       }
145       break;
146     }
147     case IrOpcode::kCheckedFloat64ToInt32: {
148       Float64Matcher m(node->InputAt(0));
149       if (m.HasResolvedValue() && IsInt32Double(m.ResolvedValue())) {
150         Node* value =
151             jsgraph()->Int32Constant(static_cast<int32_t>(m.ResolvedValue()));
152         ReplaceWithValue(node, value);
153         return Replace(value);
154       }
155       break;
156     }
157     case IrOpcode::kCheckedTaggedToArrayIndex:
158     case IrOpcode::kCheckedTaggedToInt32:
159     case IrOpcode::kCheckedTaggedSignedToInt32: {
160       NodeMatcher m(node->InputAt(0));
161       if (m.IsConvertTaggedHoleToUndefined()) {
162         node->ReplaceInput(0, m.InputAt(0));
163         return Changed(node);
164       }
165       break;
166     }
167     case IrOpcode::kCheckIf: {
168       HeapObjectMatcher m(node->InputAt(0));
169       if (m.Is(factory()->true_value())) {
170         Node* const effect = NodeProperties::GetEffectInput(node);
171         return Replace(effect);
172       }
173       break;
174     }
175     case IrOpcode::kCheckNumber: {
176       NodeMatcher m(node->InputAt(0));
177       if (m.IsConvertTaggedHoleToUndefined()) {
178         node->ReplaceInput(0, m.InputAt(0));
179         return Changed(node);
180       }
181       break;
182     }
183     case IrOpcode::kCheckHeapObject: {
184       Node* const input = node->InputAt(0);
185       if (DecideObjectIsSmi(input) == Decision::kFalse) {
186         ReplaceWithValue(node, input);
187         return Replace(input);
188       }
189       NodeMatcher m(input);
190       if (m.IsCheckHeapObject()) {
191         ReplaceWithValue(node, input);
192         return Replace(input);
193       }
194       break;
195     }
196     case IrOpcode::kCheckSmi: {
197       Node* const input = node->InputAt(0);
198       if (DecideObjectIsSmi(input) == Decision::kTrue) {
199         ReplaceWithValue(node, input);
200         return Replace(input);
201       }
202       NodeMatcher m(input);
203       if (m.IsCheckSmi()) {
204         ReplaceWithValue(node, input);
205         return Replace(input);
206       } else if (m.IsConvertTaggedHoleToUndefined()) {
207         node->ReplaceInput(0, m.InputAt(0));
208         return Changed(node);
209       }
210       break;
211     }
212     case IrOpcode::kObjectIsSmi: {
213       Node* const input = node->InputAt(0);
214       switch (DecideObjectIsSmi(input)) {
215         case Decision::kTrue:
216           return ReplaceBoolean(true);
217         case Decision::kFalse:
218           return ReplaceBoolean(false);
219         case Decision::kUnknown:
220           break;
221       }
222       break;
223     }
224     case IrOpcode::kNumberAbs: {
225       NumberMatcher m(node->InputAt(0));
226       if (m.HasResolvedValue())
227         return ReplaceNumber(std::fabs(m.ResolvedValue()));
228       break;
229     }
230     case IrOpcode::kReferenceEqual: {
231       HeapObjectBinopMatcher m(node);
232       if (m.left().node() == m.right().node()) return ReplaceBoolean(true);
233       break;
234     }
235     case IrOpcode::kCheckedInt32Add: {
236       // (x + a) + b => x + (a + b) where a and b are constants and have the
237       // same sign.
238       Int32BinopMatcher m(node);
239       if (m.right().HasResolvedValue()) {
240         Node* checked_int32_add = m.left().node();
241         if (checked_int32_add->opcode() == IrOpcode::kCheckedInt32Add) {
242           Int32BinopMatcher n(checked_int32_add);
243           if (n.right().HasResolvedValue() &&
244               (n.right().ResolvedValue() >= 0) ==
245                   (m.right().ResolvedValue() >= 0)) {
246             int32_t val;
247             bool overflow = base::bits::SignedAddOverflow32(
248                 n.right().ResolvedValue(), m.right().ResolvedValue(), &val);
249             if (!overflow) {
250               bool has_no_other_uses = true;
251               for (Edge edge : checked_int32_add->use_edges()) {
252                 if (!edge.from()->IsDead() && edge.from() != node) {
253                   has_no_other_uses = false;
254                   break;
255                 }
256               }
257               if (has_no_other_uses) {
258                 node->ReplaceInput(0, n.left().node());
259                 node->ReplaceInput(1, jsgraph()->Int32Constant(val));
260                 RelaxEffectsAndControls(checked_int32_add);
261                 return Changed(node);
262               }
263             }
264           }
265         }
266       }
267       break;
268     }
269     default:
270       break;
271   }
272   return NoChange();
273 }
274 
Change(Node * node,const Operator * op,Node * a)275 Reduction SimplifiedOperatorReducer::Change(Node* node, const Operator* op,
276                                             Node* a) {
277   DCHECK_EQ(node->InputCount(), OperatorProperties::GetTotalInputCount(op));
278   DCHECK_LE(1, node->InputCount());
279   node->ReplaceInput(0, a);
280   NodeProperties::ChangeOp(node, op);
281   return Changed(node);
282 }
283 
ReplaceBoolean(bool value)284 Reduction SimplifiedOperatorReducer::ReplaceBoolean(bool value) {
285   if (branch_semantics_ == BranchSemantics::kJS) {
286     return Replace(jsgraph()->BooleanConstant(value));
287   } else {
288     return ReplaceInt32(value);
289   }
290 }
291 
ReplaceFloat64(double value)292 Reduction SimplifiedOperatorReducer::ReplaceFloat64(double value) {
293   return Replace(jsgraph()->Float64Constant(value));
294 }
295 
296 
ReplaceInt32(int32_t value)297 Reduction SimplifiedOperatorReducer::ReplaceInt32(int32_t value) {
298   return Replace(jsgraph()->Int32Constant(value));
299 }
300 
301 
ReplaceNumber(double value)302 Reduction SimplifiedOperatorReducer::ReplaceNumber(double value) {
303   return Replace(jsgraph()->Constant(value));
304 }
305 
306 
ReplaceNumber(int32_t value)307 Reduction SimplifiedOperatorReducer::ReplaceNumber(int32_t value) {
308   return Replace(jsgraph()->Constant(value));
309 }
310 
factory() const311 Factory* SimplifiedOperatorReducer::factory() const {
312   return jsgraph()->isolate()->factory();
313 }
314 
graph() const315 Graph* SimplifiedOperatorReducer::graph() const { return jsgraph()->graph(); }
316 
machine() const317 MachineOperatorBuilder* SimplifiedOperatorReducer::machine() const {
318   return jsgraph()->machine();
319 }
320 
simplified() const321 SimplifiedOperatorBuilder* SimplifiedOperatorReducer::simplified() const {
322   return jsgraph()->simplified();
323 }
324 
325 }  // namespace compiler
326 }  // namespace internal
327 }  // namespace v8
328