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