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