blob: b566f489cb1114739f21823c0401ecc2fc84a1cc [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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/machine-operator-reducer.h"
6
7#include "src/base/bits.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008#include "src/base/division-by-constant.h"
Ben Murdoch61f157c2016-09-16 13:49:30 +01009#include "src/base/ieee754.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010#include "src/codegen.h"
11#include "src/compiler/diamond.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012#include "src/compiler/graph.h"
13#include "src/compiler/js-graph.h"
14#include "src/compiler/node-matchers.h"
15
16namespace v8 {
17namespace internal {
18namespace compiler {
19
20MachineOperatorReducer::MachineOperatorReducer(JSGraph* jsgraph)
21 : jsgraph_(jsgraph) {}
22
23
24MachineOperatorReducer::~MachineOperatorReducer() {}
25
26
27Node* MachineOperatorReducer::Float32Constant(volatile float value) {
28 return graph()->NewNode(common()->Float32Constant(value));
29}
30
31
32Node* MachineOperatorReducer::Float64Constant(volatile double value) {
33 return jsgraph()->Float64Constant(value);
34}
35
36
37Node* MachineOperatorReducer::Int32Constant(int32_t value) {
38 return jsgraph()->Int32Constant(value);
39}
40
41
42Node* MachineOperatorReducer::Int64Constant(int64_t value) {
43 return graph()->NewNode(common()->Int64Constant(value));
44}
45
46
Emily Bernierd0a1eb72015-03-24 16:35:39 -040047Node* MachineOperatorReducer::Word32And(Node* lhs, Node* rhs) {
48 Node* const node = graph()->NewNode(machine()->Word32And(), lhs, rhs);
49 Reduction const reduction = ReduceWord32And(node);
50 return reduction.Changed() ? reduction.replacement() : node;
51}
52
53
54Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) {
55 if (rhs == 0) return lhs;
56 return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs));
57}
58
59
60Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
61 if (rhs == 0) return lhs;
62 return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs));
63}
64
65
66Node* MachineOperatorReducer::Word32Equal(Node* lhs, Node* rhs) {
67 return graph()->NewNode(machine()->Word32Equal(), lhs, rhs);
68}
69
70
71Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
72 Node* const node = graph()->NewNode(machine()->Int32Add(), lhs, rhs);
73 Reduction const reduction = ReduceInt32Add(node);
74 return reduction.Changed() ? reduction.replacement() : node;
75}
76
77
78Node* MachineOperatorReducer::Int32Sub(Node* lhs, Node* rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079 Node* const node = graph()->NewNode(machine()->Int32Sub(), lhs, rhs);
80 Reduction const reduction = ReduceInt32Sub(node);
81 return reduction.Changed() ? reduction.replacement() : node;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082}
83
84
85Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) {
86 return graph()->NewNode(machine()->Int32Mul(), lhs, rhs);
87}
88
89
90Node* MachineOperatorReducer::Int32Div(Node* dividend, int32_t divisor) {
91 DCHECK_NE(0, divisor);
92 DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
93 base::MagicNumbersForDivision<uint32_t> const mag =
94 base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
95 Node* quotient = graph()->NewNode(machine()->Int32MulHigh(), dividend,
96 Uint32Constant(mag.multiplier));
97 if (divisor > 0 && bit_cast<int32_t>(mag.multiplier) < 0) {
98 quotient = Int32Add(quotient, dividend);
99 } else if (divisor < 0 && bit_cast<int32_t>(mag.multiplier) > 0) {
100 quotient = Int32Sub(quotient, dividend);
101 }
102 return Int32Add(Word32Sar(quotient, mag.shift), Word32Shr(dividend, 31));
103}
104
105
106Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107 DCHECK_LT(0u, divisor);
108 // If the divisor is even, we can avoid using the expensive fixup by shifting
109 // the dividend upfront.
110 unsigned const shift = base::bits::CountTrailingZeros32(divisor);
111 dividend = Word32Shr(dividend, shift);
112 divisor >>= shift;
113 // Compute the magic number for the (shifted) divisor.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400114 base::MagicNumbersForDivision<uint32_t> const mag =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115 base::UnsignedDivisionByConstant(divisor, shift);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400116 Node* quotient = graph()->NewNode(machine()->Uint32MulHigh(), dividend,
117 Uint32Constant(mag.multiplier));
118 if (mag.add) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 DCHECK_LE(1u, mag.shift);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400120 quotient = Word32Shr(
121 Int32Add(Word32Shr(Int32Sub(dividend, quotient), 1), quotient),
122 mag.shift - 1);
123 } else {
124 quotient = Word32Shr(quotient, mag.shift);
125 }
126 return quotient;
127}
128
129
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130// Perform constant folding and strength reduction on machine operators.
131Reduction MachineOperatorReducer::Reduce(Node* node) {
132 switch (node->opcode()) {
133 case IrOpcode::kProjection:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000134 return ReduceProjection(ProjectionIndexOf(node->op()), node->InputAt(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400135 case IrOpcode::kWord32And:
136 return ReduceWord32And(node);
137 case IrOpcode::kWord32Or:
138 return ReduceWord32Or(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000139 case IrOpcode::kWord32Xor: {
140 Int32BinopMatcher m(node);
141 if (m.right().Is(0)) return Replace(m.left().node()); // x ^ 0 => x
142 if (m.IsFoldable()) { // K ^ K => K
143 return ReplaceInt32(m.left().Value() ^ m.right().Value());
144 }
145 if (m.LeftEqualsRight()) return ReplaceInt32(0); // x ^ x => 0
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400146 if (m.left().IsWord32Xor() && m.right().Is(-1)) {
147 Int32BinopMatcher mleft(m.left().node());
148 if (mleft.right().Is(-1)) { // (x ^ -1) ^ -1 => x
149 return Replace(mleft.left().node());
150 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000151 }
152 break;
153 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400154 case IrOpcode::kWord32Shl:
155 return ReduceWord32Shl(node);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100156 case IrOpcode::kWord32Shr:
157 return ReduceWord32Shr(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158 case IrOpcode::kWord32Sar:
159 return ReduceWord32Sar(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000160 case IrOpcode::kWord32Ror: {
161 Int32BinopMatcher m(node);
162 if (m.right().Is(0)) return Replace(m.left().node()); // x ror 0 => x
163 if (m.IsFoldable()) { // K ror K => K
164 return ReplaceInt32(
165 base::bits::RotateRight32(m.left().Value(), m.right().Value()));
166 }
167 break;
168 }
169 case IrOpcode::kWord32Equal: {
170 Int32BinopMatcher m(node);
171 if (m.IsFoldable()) { // K == K => K
172 return ReplaceBool(m.left().Value() == m.right().Value());
173 }
174 if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y == 0 => x == y
175 Int32BinopMatcher msub(m.left().node());
176 node->ReplaceInput(0, msub.left().node());
177 node->ReplaceInput(1, msub.right().node());
178 return Changed(node);
179 }
180 // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
181 if (m.LeftEqualsRight()) return ReplaceBool(true); // x == x => true
182 break;
183 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400184 case IrOpcode::kWord64Equal: {
185 Int64BinopMatcher m(node);
186 if (m.IsFoldable()) { // K == K => K
187 return ReplaceBool(m.left().Value() == m.right().Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400189 if (m.left().IsInt64Sub() && m.right().Is(0)) { // x - y == 0 => x == y
190 Int64BinopMatcher msub(m.left().node());
191 node->ReplaceInput(0, msub.left().node());
192 node->ReplaceInput(1, msub.right().node());
193 return Changed(node);
194 }
195 // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
196 if (m.LeftEqualsRight()) return ReplaceBool(true); // x == x => true
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000197 break;
198 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400199 case IrOpcode::kInt32Add:
200 return ReduceInt32Add(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 case IrOpcode::kInt32Sub:
202 return ReduceInt32Sub(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000203 case IrOpcode::kInt32Mul: {
204 Int32BinopMatcher m(node);
205 if (m.right().Is(0)) return Replace(m.right().node()); // x * 0 => 0
206 if (m.right().Is(1)) return Replace(m.left().node()); // x * 1 => x
207 if (m.IsFoldable()) { // K * K => K
208 return ReplaceInt32(m.left().Value() * m.right().Value());
209 }
210 if (m.right().Is(-1)) { // x * -1 => 0 - x
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000211 node->ReplaceInput(0, Int32Constant(0));
212 node->ReplaceInput(1, m.left().node());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213 NodeProperties::ChangeOp(node, machine()->Int32Sub());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 return Changed(node);
215 }
216 if (m.right().IsPowerOf2()) { // x * 2^n => x << n
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217 node->ReplaceInput(1, Int32Constant(WhichPowerOf2(m.right().Value())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218 NodeProperties::ChangeOp(node, machine()->Word32Shl());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400219 Reduction reduction = ReduceWord32Shl(node);
220 return reduction.Changed() ? reduction : Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000221 }
222 break;
223 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400224 case IrOpcode::kInt32Div:
225 return ReduceInt32Div(node);
226 case IrOpcode::kUint32Div:
227 return ReduceUint32Div(node);
228 case IrOpcode::kInt32Mod:
229 return ReduceInt32Mod(node);
230 case IrOpcode::kUint32Mod:
231 return ReduceUint32Mod(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 case IrOpcode::kInt32LessThan: {
233 Int32BinopMatcher m(node);
234 if (m.IsFoldable()) { // K < K => K
235 return ReplaceBool(m.left().Value() < m.right().Value());
236 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000237 if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false
238 break;
239 }
240 case IrOpcode::kInt32LessThanOrEqual: {
241 Int32BinopMatcher m(node);
242 if (m.IsFoldable()) { // K <= K => K
243 return ReplaceBool(m.left().Value() <= m.right().Value());
244 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000245 if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true
246 break;
247 }
248 case IrOpcode::kUint32LessThan: {
249 Uint32BinopMatcher m(node);
250 if (m.left().Is(kMaxUInt32)) return ReplaceBool(false); // M < x => false
251 if (m.right().Is(0)) return ReplaceBool(false); // x < 0 => false
252 if (m.IsFoldable()) { // K < K => K
253 return ReplaceBool(m.left().Value() < m.right().Value());
254 }
255 if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400256 if (m.left().IsWord32Sar() && m.right().HasValue()) {
257 Int32BinopMatcher mleft(m.left().node());
258 if (mleft.right().HasValue()) {
259 // (x >> K) < C => x < (C << K)
260 // when C < (M >> K)
261 const uint32_t c = m.right().Value();
262 const uint32_t k = mleft.right().Value() & 0x1f;
263 if (c < static_cast<uint32_t>(kMaxInt >> k)) {
264 node->ReplaceInput(0, mleft.left().node());
265 node->ReplaceInput(1, Uint32Constant(c << k));
266 return Changed(node);
267 }
268 // TODO(turbofan): else the comparison is always true.
269 }
270 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000271 break;
272 }
273 case IrOpcode::kUint32LessThanOrEqual: {
274 Uint32BinopMatcher m(node);
275 if (m.left().Is(0)) return ReplaceBool(true); // 0 <= x => true
276 if (m.right().Is(kMaxUInt32)) return ReplaceBool(true); // x <= M => true
277 if (m.IsFoldable()) { // K <= K => K
278 return ReplaceBool(m.left().Value() <= m.right().Value());
279 }
280 if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true
281 break;
282 }
283 case IrOpcode::kFloat64Add: {
284 Float64BinopMatcher m(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400285 if (m.right().IsNaN()) { // x + NaN => NaN
286 return Replace(m.right().node());
287 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288 if (m.IsFoldable()) { // K + K => K
289 return ReplaceFloat64(m.left().Value() + m.right().Value());
290 }
291 break;
292 }
293 case IrOpcode::kFloat64Sub: {
294 Float64BinopMatcher m(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400295 if (m.right().Is(0) && (Double(m.right().Value()).Sign() > 0)) {
296 return Replace(m.left().node()); // x - 0 => x
297 }
298 if (m.right().IsNaN()) { // x - NaN => NaN
299 return Replace(m.right().node());
300 }
301 if (m.left().IsNaN()) { // NaN - x => NaN
302 return Replace(m.left().node());
303 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 if (m.IsFoldable()) { // K - K => K
305 return ReplaceFloat64(m.left().Value() - m.right().Value());
306 }
307 break;
308 }
309 case IrOpcode::kFloat64Mul: {
310 Float64BinopMatcher m(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400311 if (m.right().Is(-1)) { // x * -1.0 => -0.0 - x
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400312 node->ReplaceInput(0, Float64Constant(-0.0));
313 node->ReplaceInput(1, m.left().node());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000314 NodeProperties::ChangeOp(node, machine()->Float64Sub());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400315 return Changed(node);
316 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000317 if (m.right().Is(1)) return Replace(m.left().node()); // x * 1.0 => x
318 if (m.right().IsNaN()) { // x * NaN => NaN
319 return Replace(m.right().node());
320 }
321 if (m.IsFoldable()) { // K * K => K
322 return ReplaceFloat64(m.left().Value() * m.right().Value());
323 }
324 break;
325 }
326 case IrOpcode::kFloat64Div: {
327 Float64BinopMatcher m(node);
328 if (m.right().Is(1)) return Replace(m.left().node()); // x / 1.0 => x
329 if (m.right().IsNaN()) { // x / NaN => NaN
330 return Replace(m.right().node());
331 }
332 if (m.left().IsNaN()) { // NaN / x => NaN
333 return Replace(m.left().node());
334 }
335 if (m.IsFoldable()) { // K / K => K
336 return ReplaceFloat64(m.left().Value() / m.right().Value());
337 }
338 break;
339 }
340 case IrOpcode::kFloat64Mod: {
341 Float64BinopMatcher m(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400342 if (m.right().Is(0)) { // x % 0 => NaN
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 return ReplaceFloat64(std::numeric_limits<double>::quiet_NaN());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400344 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345 if (m.right().IsNaN()) { // x % NaN => NaN
346 return Replace(m.right().node());
347 }
348 if (m.left().IsNaN()) { // NaN % x => NaN
349 return Replace(m.left().node());
350 }
351 if (m.IsFoldable()) { // K % K => K
352 return ReplaceFloat64(modulo(m.left().Value(), m.right().Value()));
353 }
354 break;
355 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100356 case IrOpcode::kFloat64Atan: {
357 Float64Matcher m(node->InputAt(0));
358 if (m.HasValue()) return ReplaceFloat64(base::ieee754::atan(m.Value()));
359 break;
360 }
361 case IrOpcode::kFloat64Atan2: {
362 Float64BinopMatcher m(node);
363 if (m.right().IsNaN()) {
364 return Replace(m.right().node());
365 }
366 if (m.left().IsNaN()) {
367 return Replace(m.left().node());
368 }
369 if (m.IsFoldable()) {
370 return ReplaceFloat64(
371 base::ieee754::atan2(m.left().Value(), m.right().Value()));
372 }
373 break;
374 }
375 case IrOpcode::kFloat64Atanh: {
376 Float64Matcher m(node->InputAt(0));
377 if (m.HasValue()) return ReplaceFloat64(base::ieee754::atanh(m.Value()));
378 break;
379 }
380 case IrOpcode::kFloat64Cos: {
381 Float64Matcher m(node->InputAt(0));
382 if (m.HasValue()) return ReplaceFloat64(base::ieee754::cos(m.Value()));
383 break;
384 }
385 case IrOpcode::kFloat64Exp: {
386 Float64Matcher m(node->InputAt(0));
387 if (m.HasValue()) return ReplaceFloat64(base::ieee754::exp(m.Value()));
388 break;
389 }
390 case IrOpcode::kFloat64Expm1: {
391 Float64Matcher m(node->InputAt(0));
392 if (m.HasValue()) return ReplaceFloat64(base::ieee754::expm1(m.Value()));
393 break;
394 }
395 case IrOpcode::kFloat64Log: {
396 Float64Matcher m(node->InputAt(0));
397 if (m.HasValue()) return ReplaceFloat64(base::ieee754::log(m.Value()));
398 break;
399 }
400 case IrOpcode::kFloat64Log1p: {
401 Float64Matcher m(node->InputAt(0));
402 if (m.HasValue()) return ReplaceFloat64(base::ieee754::log1p(m.Value()));
403 break;
404 }
405 case IrOpcode::kFloat64Log2: {
406 Float64Matcher m(node->InputAt(0));
407 if (m.HasValue()) return ReplaceFloat64(base::ieee754::log2(m.Value()));
408 break;
409 }
410 case IrOpcode::kFloat64Log10: {
411 Float64Matcher m(node->InputAt(0));
412 if (m.HasValue()) return ReplaceFloat64(base::ieee754::log10(m.Value()));
413 break;
414 }
415 case IrOpcode::kFloat64Cbrt: {
416 Float64Matcher m(node->InputAt(0));
417 if (m.HasValue()) return ReplaceFloat64(base::ieee754::cbrt(m.Value()));
418 break;
419 }
420 case IrOpcode::kFloat64Sin: {
421 Float64Matcher m(node->InputAt(0));
422 if (m.HasValue()) return ReplaceFloat64(base::ieee754::sin(m.Value()));
423 break;
424 }
425 case IrOpcode::kFloat64Tan: {
426 Float64Matcher m(node->InputAt(0));
427 if (m.HasValue()) return ReplaceFloat64(base::ieee754::tan(m.Value()));
428 break;
429 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430 case IrOpcode::kChangeFloat32ToFloat64: {
431 Float32Matcher m(node->InputAt(0));
432 if (m.HasValue()) return ReplaceFloat64(m.Value());
433 break;
434 }
435 case IrOpcode::kChangeFloat64ToInt32: {
436 Float64Matcher m(node->InputAt(0));
437 if (m.HasValue()) return ReplaceInt32(FastD2I(m.Value()));
438 if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
439 break;
440 }
441 case IrOpcode::kChangeFloat64ToUint32: {
442 Float64Matcher m(node->InputAt(0));
443 if (m.HasValue()) return ReplaceInt32(FastD2UI(m.Value()));
444 if (m.IsChangeUint32ToFloat64()) return Replace(m.node()->InputAt(0));
445 break;
446 }
447 case IrOpcode::kChangeInt32ToFloat64: {
448 Int32Matcher m(node->InputAt(0));
449 if (m.HasValue()) return ReplaceFloat64(FastI2D(m.Value()));
450 break;
451 }
452 case IrOpcode::kChangeInt32ToInt64: {
453 Int32Matcher m(node->InputAt(0));
454 if (m.HasValue()) return ReplaceInt64(m.Value());
455 break;
456 }
457 case IrOpcode::kChangeUint32ToFloat64: {
458 Uint32Matcher m(node->InputAt(0));
459 if (m.HasValue()) return ReplaceFloat64(FastUI2D(m.Value()));
460 break;
461 }
462 case IrOpcode::kChangeUint32ToUint64: {
463 Uint32Matcher m(node->InputAt(0));
464 if (m.HasValue()) return ReplaceInt64(static_cast<uint64_t>(m.Value()));
465 break;
466 }
Ben Murdochc5610432016-08-08 18:44:38 +0100467 case IrOpcode::kTruncateFloat64ToWord32: {
468 Float64Matcher m(node->InputAt(0));
469 if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value()));
470 if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
471 return NoChange();
472 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000473 case IrOpcode::kTruncateInt64ToInt32: {
474 Int64Matcher m(node->InputAt(0));
475 if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value()));
476 if (m.IsChangeInt32ToInt64()) return Replace(m.node()->InputAt(0));
477 break;
478 }
479 case IrOpcode::kTruncateFloat64ToFloat32: {
480 Float64Matcher m(node->InputAt(0));
481 if (m.HasValue()) return ReplaceFloat32(DoubleToFloat32(m.Value()));
482 if (m.IsChangeFloat32ToFloat64()) return Replace(m.node()->InputAt(0));
483 break;
484 }
Ben Murdochc5610432016-08-08 18:44:38 +0100485 case IrOpcode::kRoundFloat64ToInt32: {
486 Float64Matcher m(node->InputAt(0));
487 if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value()));
488 if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
489 break;
490 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000491 case IrOpcode::kFloat64InsertLowWord32:
492 return ReduceFloat64InsertLowWord32(node);
493 case IrOpcode::kFloat64InsertHighWord32:
494 return ReduceFloat64InsertHighWord32(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400495 case IrOpcode::kStore:
Ben Murdochc5610432016-08-08 18:44:38 +0100496 case IrOpcode::kCheckedStore:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400497 return ReduceStore(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000498 case IrOpcode::kFloat64Equal:
499 case IrOpcode::kFloat64LessThan:
500 case IrOpcode::kFloat64LessThanOrEqual:
501 return ReduceFloat64Compare(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400502 default:
503 break;
504 }
505 return NoChange();
506}
507
508
509Reduction MachineOperatorReducer::ReduceInt32Add(Node* node) {
510 DCHECK_EQ(IrOpcode::kInt32Add, node->opcode());
511 Int32BinopMatcher m(node);
512 if (m.right().Is(0)) return Replace(m.left().node()); // x + 0 => x
513 if (m.IsFoldable()) { // K + K => K
514 return ReplaceUint32(bit_cast<uint32_t>(m.left().Value()) +
515 bit_cast<uint32_t>(m.right().Value()));
516 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517 if (m.left().IsInt32Sub()) {
518 Int32BinopMatcher mleft(m.left().node());
519 if (mleft.left().Is(0)) { // (0 - x) + y => y - x
520 node->ReplaceInput(0, m.right().node());
521 node->ReplaceInput(1, mleft.right().node());
522 NodeProperties::ChangeOp(node, machine()->Int32Sub());
523 Reduction const reduction = ReduceInt32Sub(node);
524 return reduction.Changed() ? reduction : Changed(node);
525 }
526 }
527 if (m.right().IsInt32Sub()) {
528 Int32BinopMatcher mright(m.right().node());
529 if (mright.left().Is(0)) { // y + (0 - x) => y - x
530 node->ReplaceInput(1, mright.right().node());
531 NodeProperties::ChangeOp(node, machine()->Int32Sub());
532 Reduction const reduction = ReduceInt32Sub(node);
533 return reduction.Changed() ? reduction : Changed(node);
534 }
535 }
536 return NoChange();
537}
538
539
540Reduction MachineOperatorReducer::ReduceInt32Sub(Node* node) {
541 DCHECK_EQ(IrOpcode::kInt32Sub, node->opcode());
542 Int32BinopMatcher m(node);
543 if (m.right().Is(0)) return Replace(m.left().node()); // x - 0 => x
544 if (m.IsFoldable()) { // K - K => K
545 return ReplaceInt32(static_cast<uint32_t>(m.left().Value()) -
546 static_cast<uint32_t>(m.right().Value()));
547 }
548 if (m.LeftEqualsRight()) return ReplaceInt32(0); // x - x => 0
549 if (m.right().HasValue()) { // x - K => x + -K
550 node->ReplaceInput(1, Int32Constant(-m.right().Value()));
551 NodeProperties::ChangeOp(node, machine()->Int32Add());
552 Reduction const reduction = ReduceInt32Add(node);
553 return reduction.Changed() ? reduction : Changed(node);
554 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400555 return NoChange();
556}
557
558
559Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
560 Int32BinopMatcher m(node);
561 if (m.left().Is(0)) return Replace(m.left().node()); // 0 / x => 0
562 if (m.right().Is(0)) return Replace(m.right().node()); // x / 0 => 0
563 if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x
564 if (m.IsFoldable()) { // K / K => K
565 return ReplaceInt32(
566 base::bits::SignedDiv32(m.left().Value(), m.right().Value()));
567 }
568 if (m.LeftEqualsRight()) { // x / x => x != 0
569 Node* const zero = Int32Constant(0);
570 return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
571 }
572 if (m.right().Is(-1)) { // x / -1 => 0 - x
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400573 node->ReplaceInput(0, Int32Constant(0));
574 node->ReplaceInput(1, m.left().node());
575 node->TrimInputCount(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000576 NodeProperties::ChangeOp(node, machine()->Int32Sub());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400577 return Changed(node);
578 }
579 if (m.right().HasValue()) {
580 int32_t const divisor = m.right().Value();
581 Node* const dividend = m.left().node();
582 Node* quotient = dividend;
583 if (base::bits::IsPowerOfTwo32(Abs(divisor))) {
584 uint32_t const shift = WhichPowerOf2Abs(divisor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000585 DCHECK_NE(0u, shift);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400586 if (shift > 1) {
587 quotient = Word32Sar(quotient, 31);
588 }
589 quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend);
590 quotient = Word32Sar(quotient, shift);
591 } else {
592 quotient = Int32Div(quotient, Abs(divisor));
593 }
594 if (divisor < 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400595 node->ReplaceInput(0, Int32Constant(0));
596 node->ReplaceInput(1, quotient);
597 node->TrimInputCount(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000598 NodeProperties::ChangeOp(node, machine()->Int32Sub());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400599 return Changed(node);
600 }
601 return Replace(quotient);
602 }
603 return NoChange();
604}
605
606
607Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
608 Uint32BinopMatcher m(node);
609 if (m.left().Is(0)) return Replace(m.left().node()); // 0 / x => 0
610 if (m.right().Is(0)) return Replace(m.right().node()); // x / 0 => 0
611 if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x
612 if (m.IsFoldable()) { // K / K => K
613 return ReplaceUint32(
614 base::bits::UnsignedDiv32(m.left().Value(), m.right().Value()));
615 }
616 if (m.LeftEqualsRight()) { // x / x => x != 0
617 Node* const zero = Int32Constant(0);
618 return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
619 }
620 if (m.right().HasValue()) {
621 Node* const dividend = m.left().node();
622 uint32_t const divisor = m.right().Value();
623 if (base::bits::IsPowerOfTwo32(divisor)) { // x / 2^n => x >> n
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400624 node->ReplaceInput(1, Uint32Constant(WhichPowerOf2(m.right().Value())));
625 node->TrimInputCount(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000626 NodeProperties::ChangeOp(node, machine()->Word32Shr());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400627 return Changed(node);
628 } else {
629 return Replace(Uint32Div(dividend, divisor));
630 }
631 }
632 return NoChange();
633}
634
635
636Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
637 Int32BinopMatcher m(node);
638 if (m.left().Is(0)) return Replace(m.left().node()); // 0 % x => 0
639 if (m.right().Is(0)) return Replace(m.right().node()); // x % 0 => 0
640 if (m.right().Is(1)) return ReplaceInt32(0); // x % 1 => 0
641 if (m.right().Is(-1)) return ReplaceInt32(0); // x % -1 => 0
642 if (m.LeftEqualsRight()) return ReplaceInt32(0); // x % x => 0
643 if (m.IsFoldable()) { // K % K => K
644 return ReplaceInt32(
645 base::bits::SignedMod32(m.left().Value(), m.right().Value()));
646 }
647 if (m.right().HasValue()) {
648 Node* const dividend = m.left().node();
649 int32_t const divisor = Abs(m.right().Value());
650 if (base::bits::IsPowerOfTwo32(divisor)) {
651 uint32_t const mask = divisor - 1;
652 Node* const zero = Int32Constant(0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400653 node->ReplaceInput(
654 0, graph()->NewNode(machine()->Int32LessThan(), dividend, zero));
655 node->ReplaceInput(
656 1, Int32Sub(zero, Word32And(Int32Sub(zero, dividend), mask)));
657 node->ReplaceInput(2, Word32And(dividend, mask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000658 NodeProperties::ChangeOp(
659 node,
660 common()->Select(MachineRepresentation::kWord32, BranchHint::kFalse));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400661 } else {
662 Node* quotient = Int32Div(dividend, divisor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400663 DCHECK_EQ(dividend, node->InputAt(0));
664 node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
665 node->TrimInputCount(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000666 NodeProperties::ChangeOp(node, machine()->Int32Sub());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400667 }
668 return Changed(node);
669 }
670 return NoChange();
671}
672
673
674Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) {
675 Uint32BinopMatcher m(node);
676 if (m.left().Is(0)) return Replace(m.left().node()); // 0 % x => 0
677 if (m.right().Is(0)) return Replace(m.right().node()); // x % 0 => 0
678 if (m.right().Is(1)) return ReplaceUint32(0); // x % 1 => 0
679 if (m.LeftEqualsRight()) return ReplaceInt32(0); // x % x => 0
680 if (m.IsFoldable()) { // K % K => K
681 return ReplaceUint32(
682 base::bits::UnsignedMod32(m.left().Value(), m.right().Value()));
683 }
684 if (m.right().HasValue()) {
685 Node* const dividend = m.left().node();
686 uint32_t const divisor = m.right().Value();
687 if (base::bits::IsPowerOfTwo32(divisor)) { // x % 2^n => x & 2^n-1
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400688 node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000689 node->TrimInputCount(2);
690 NodeProperties::ChangeOp(node, machine()->Word32And());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400691 } else {
692 Node* quotient = Uint32Div(dividend, divisor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400693 DCHECK_EQ(dividend, node->InputAt(0));
694 node->ReplaceInput(1, Int32Mul(quotient, Uint32Constant(divisor)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000695 node->TrimInputCount(2);
696 NodeProperties::ChangeOp(node, machine()->Int32Sub());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400697 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400698 return Changed(node);
699 }
700 return NoChange();
701}
702
703
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400704Reduction MachineOperatorReducer::ReduceStore(Node* node) {
Ben Murdochc5610432016-08-08 18:44:38 +0100705 NodeMatcher nm(node);
706 MachineRepresentation rep;
707 int value_input;
708 if (nm.IsCheckedStore()) {
709 rep = CheckedStoreRepresentationOf(node->op());
710 value_input = 3;
711 } else {
712 rep = StoreRepresentationOf(node->op()).representation();
713 value_input = 2;
714 }
715
716 Node* const value = node->InputAt(value_input);
717
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400718 switch (value->opcode()) {
719 case IrOpcode::kWord32And: {
720 Uint32BinopMatcher m(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000721 if (m.right().HasValue() && ((rep == MachineRepresentation::kWord8 &&
722 (m.right().Value() & 0xff) == 0xff) ||
723 (rep == MachineRepresentation::kWord16 &&
724 (m.right().Value() & 0xffff) == 0xffff))) {
Ben Murdochc5610432016-08-08 18:44:38 +0100725 node->ReplaceInput(value_input, m.left().node());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400726 return Changed(node);
727 }
728 break;
729 }
730 case IrOpcode::kWord32Sar: {
731 Int32BinopMatcher m(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000732 if (m.left().IsWord32Shl() && ((rep == MachineRepresentation::kWord8 &&
733 m.right().IsInRange(1, 24)) ||
734 (rep == MachineRepresentation::kWord16 &&
735 m.right().IsInRange(1, 16)))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400736 Int32BinopMatcher mleft(m.left().node());
737 if (mleft.right().Is(m.right().Value())) {
Ben Murdochc5610432016-08-08 18:44:38 +0100738 node->ReplaceInput(value_input, mleft.left().node());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400739 return Changed(node);
740 }
741 }
742 break;
743 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000744 default:
745 break;
746 }
747 return NoChange();
748}
749
750
751Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) {
752 switch (node->opcode()) {
753 case IrOpcode::kInt32AddWithOverflow: {
754 DCHECK(index == 0 || index == 1);
755 Int32BinopMatcher m(node);
756 if (m.IsFoldable()) {
757 int32_t val;
758 bool ovf = base::bits::SignedAddOverflow32(m.left().Value(),
759 m.right().Value(), &val);
760 return ReplaceInt32((index == 0) ? val : ovf);
761 }
762 if (m.right().Is(0)) {
763 return (index == 0) ? Replace(m.left().node()) : ReplaceInt32(0);
764 }
765 break;
766 }
767 case IrOpcode::kInt32SubWithOverflow: {
768 DCHECK(index == 0 || index == 1);
769 Int32BinopMatcher m(node);
770 if (m.IsFoldable()) {
771 int32_t val;
772 bool ovf = base::bits::SignedSubOverflow32(m.left().Value(),
773 m.right().Value(), &val);
774 return ReplaceInt32((index == 0) ? val : ovf);
775 }
776 if (m.right().Is(0)) {
777 return (index == 0) ? Replace(m.left().node()) : ReplaceInt32(0);
778 }
779 break;
780 }
781 default:
782 break;
783 }
784 return NoChange();
785}
786
787
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400788Reduction MachineOperatorReducer::ReduceWord32Shifts(Node* node) {
789 DCHECK((node->opcode() == IrOpcode::kWord32Shl) ||
790 (node->opcode() == IrOpcode::kWord32Shr) ||
791 (node->opcode() == IrOpcode::kWord32Sar));
792 if (machine()->Word32ShiftIsSafe()) {
793 // Remove the explicit 'and' with 0x1f if the shift provided by the machine
794 // instruction matches that required by JavaScript.
795 Int32BinopMatcher m(node);
796 if (m.right().IsWord32And()) {
797 Int32BinopMatcher mright(m.right().node());
798 if (mright.right().Is(0x1f)) {
799 node->ReplaceInput(1, mright.left().node());
800 return Changed(node);
801 }
802 }
803 }
804 return NoChange();
805}
806
807
808Reduction MachineOperatorReducer::ReduceWord32Shl(Node* node) {
809 DCHECK_EQ(IrOpcode::kWord32Shl, node->opcode());
810 Int32BinopMatcher m(node);
811 if (m.right().Is(0)) return Replace(m.left().node()); // x << 0 => x
812 if (m.IsFoldable()) { // K << K => K
813 return ReplaceInt32(m.left().Value() << m.right().Value());
814 }
815 if (m.right().IsInRange(1, 31)) {
816 // (x >>> K) << K => x & ~(2^K - 1)
817 // (x >> K) << K => x & ~(2^K - 1)
818 if (m.left().IsWord32Sar() || m.left().IsWord32Shr()) {
819 Int32BinopMatcher mleft(m.left().node());
820 if (mleft.right().Is(m.right().Value())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400821 node->ReplaceInput(0, mleft.left().node());
822 node->ReplaceInput(1,
823 Uint32Constant(~((1U << m.right().Value()) - 1U)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000824 NodeProperties::ChangeOp(node, machine()->Word32And());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400825 Reduction reduction = ReduceWord32And(node);
826 return reduction.Changed() ? reduction : Changed(node);
827 }
828 }
829 }
830 return ReduceWord32Shifts(node);
831}
832
Ben Murdoch61f157c2016-09-16 13:49:30 +0100833Reduction MachineOperatorReducer::ReduceWord32Shr(Node* node) {
834 Uint32BinopMatcher m(node);
835 if (m.right().Is(0)) return Replace(m.left().node()); // x >>> 0 => x
836 if (m.IsFoldable()) { // K >>> K => K
837 return ReplaceInt32(m.left().Value() >> m.right().Value());
838 }
839 if (m.left().IsWord32And() && m.right().HasValue()) {
840 Uint32BinopMatcher mleft(m.left().node());
841 if (mleft.right().HasValue()) {
842 uint32_t shift = m.right().Value() & 0x1f;
843 uint32_t mask = mleft.right().Value();
844 if ((mask >> shift) == 0) {
845 // (m >>> s) == 0 implies ((x & m) >>> s) == 0
846 return ReplaceInt32(0);
847 }
848 }
849 }
850 return ReduceWord32Shifts(node);
851}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400852
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000853Reduction MachineOperatorReducer::ReduceWord32Sar(Node* node) {
854 Int32BinopMatcher m(node);
855 if (m.right().Is(0)) return Replace(m.left().node()); // x >> 0 => x
856 if (m.IsFoldable()) { // K >> K => K
857 return ReplaceInt32(m.left().Value() >> m.right().Value());
858 }
859 if (m.left().IsWord32Shl()) {
860 Int32BinopMatcher mleft(m.left().node());
861 if (mleft.left().IsComparison()) {
862 if (m.right().Is(31) && mleft.right().Is(31)) {
863 // Comparison << 31 >> 31 => 0 - Comparison
864 node->ReplaceInput(0, Int32Constant(0));
865 node->ReplaceInput(1, mleft.left().node());
866 NodeProperties::ChangeOp(node, machine()->Int32Sub());
867 Reduction const reduction = ReduceInt32Sub(node);
868 return reduction.Changed() ? reduction : Changed(node);
869 }
870 } else if (mleft.left().IsLoad()) {
871 LoadRepresentation const rep =
872 LoadRepresentationOf(mleft.left().node()->op());
873 if (m.right().Is(24) && mleft.right().Is(24) &&
874 rep == MachineType::Int8()) {
875 // Load[kMachInt8] << 24 >> 24 => Load[kMachInt8]
876 return Replace(mleft.left().node());
877 }
878 if (m.right().Is(16) && mleft.right().Is(16) &&
879 rep == MachineType::Int16()) {
880 // Load[kMachInt16] << 16 >> 16 => Load[kMachInt8]
881 return Replace(mleft.left().node());
882 }
883 }
884 }
885 return ReduceWord32Shifts(node);
886}
887
888
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400889Reduction MachineOperatorReducer::ReduceWord32And(Node* node) {
890 DCHECK_EQ(IrOpcode::kWord32And, node->opcode());
891 Int32BinopMatcher m(node);
892 if (m.right().Is(0)) return Replace(m.right().node()); // x & 0 => 0
893 if (m.right().Is(-1)) return Replace(m.left().node()); // x & -1 => x
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000894 if (m.left().IsComparison() && m.right().Is(1)) { // CMP & 1 => CMP
895 return Replace(m.left().node());
896 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400897 if (m.IsFoldable()) { // K & K => K
898 return ReplaceInt32(m.left().Value() & m.right().Value());
899 }
900 if (m.LeftEqualsRight()) return Replace(m.left().node()); // x & x => x
901 if (m.left().IsWord32And() && m.right().HasValue()) {
902 Int32BinopMatcher mleft(m.left().node());
903 if (mleft.right().HasValue()) { // (x & K) & K => x & K
904 node->ReplaceInput(0, mleft.left().node());
905 node->ReplaceInput(
906 1, Int32Constant(m.right().Value() & mleft.right().Value()));
907 Reduction const reduction = ReduceWord32And(node);
908 return reduction.Changed() ? reduction : Changed(node);
909 }
910 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000911 if (m.right().IsNegativePowerOf2()) {
912 int32_t const mask = m.right().Value();
913 if (m.left().IsWord32Shl()) {
914 Uint32BinopMatcher mleft(m.left().node());
915 if (mleft.right().HasValue() &&
916 mleft.right().Value() >= base::bits::CountTrailingZeros32(mask)) {
917 // (x << L) & (-1 << K) => x << L iff K >= L
918 return Replace(mleft.node());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400919 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000920 } else if (m.left().IsInt32Add()) {
921 Int32BinopMatcher mleft(m.left().node());
922 if (mleft.right().HasValue() &&
923 (mleft.right().Value() & mask) == mleft.right().Value()) {
924 // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400925 node->ReplaceInput(0, Word32And(mleft.left().node(), m.right().node()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000926 node->ReplaceInput(1, mleft.right().node());
927 NodeProperties::ChangeOp(node, machine()->Int32Add());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400928 Reduction const reduction = ReduceInt32Add(node);
929 return reduction.Changed() ? reduction : Changed(node);
930 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000931 if (mleft.left().IsInt32Mul()) {
932 Int32BinopMatcher mleftleft(mleft.left().node());
933 if (mleftleft.right().IsMultipleOf(-mask)) {
934 // (y * (K << L) + x) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
935 node->ReplaceInput(0,
936 Word32And(mleft.right().node(), m.right().node()));
937 node->ReplaceInput(1, mleftleft.node());
938 NodeProperties::ChangeOp(node, machine()->Int32Add());
939 Reduction const reduction = ReduceInt32Add(node);
940 return reduction.Changed() ? reduction : Changed(node);
941 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400942 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000943 if (mleft.right().IsInt32Mul()) {
944 Int32BinopMatcher mleftright(mleft.right().node());
945 if (mleftright.right().IsMultipleOf(-mask)) {
946 // (x + y * (K << L)) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
947 node->ReplaceInput(0,
948 Word32And(mleft.left().node(), m.right().node()));
949 node->ReplaceInput(1, mleftright.node());
950 NodeProperties::ChangeOp(node, machine()->Int32Add());
951 Reduction const reduction = ReduceInt32Add(node);
952 return reduction.Changed() ? reduction : Changed(node);
953 }
954 }
955 if (mleft.left().IsWord32Shl()) {
956 Int32BinopMatcher mleftleft(mleft.left().node());
957 if (mleftleft.right().Is(base::bits::CountTrailingZeros32(mask))) {
958 // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
959 node->ReplaceInput(0,
960 Word32And(mleft.right().node(), m.right().node()));
961 node->ReplaceInput(1, mleftleft.node());
962 NodeProperties::ChangeOp(node, machine()->Int32Add());
963 Reduction const reduction = ReduceInt32Add(node);
964 return reduction.Changed() ? reduction : Changed(node);
965 }
966 }
967 if (mleft.right().IsWord32Shl()) {
968 Int32BinopMatcher mleftright(mleft.right().node());
969 if (mleftright.right().Is(base::bits::CountTrailingZeros32(mask))) {
970 // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
971 node->ReplaceInput(0,
972 Word32And(mleft.left().node(), m.right().node()));
973 node->ReplaceInput(1, mleftright.node());
974 NodeProperties::ChangeOp(node, machine()->Int32Add());
975 Reduction const reduction = ReduceInt32Add(node);
976 return reduction.Changed() ? reduction : Changed(node);
977 }
978 }
979 } else if (m.left().IsInt32Mul()) {
980 Int32BinopMatcher mleft(m.left().node());
981 if (mleft.right().IsMultipleOf(-mask)) {
982 // (x * (K << L)) & (-1 << L) => x * (K << L)
983 return Replace(mleft.node());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400984 }
985 }
986 }
987 return NoChange();
988}
989
990
991Reduction MachineOperatorReducer::ReduceWord32Or(Node* node) {
992 DCHECK_EQ(IrOpcode::kWord32Or, node->opcode());
993 Int32BinopMatcher m(node);
994 if (m.right().Is(0)) return Replace(m.left().node()); // x | 0 => x
995 if (m.right().Is(-1)) return Replace(m.right().node()); // x | -1 => -1
996 if (m.IsFoldable()) { // K | K => K
997 return ReplaceInt32(m.left().Value() | m.right().Value());
998 }
999 if (m.LeftEqualsRight()) return Replace(m.left().node()); // x | x => x
1000
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001001 Node* shl = nullptr;
1002 Node* shr = nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001003 // Recognize rotation, we are matching either:
1004 // * x << y | x >>> (32 - y) => x ror (32 - y), i.e x rol y
1005 // * x << (32 - y) | x >>> y => x ror y
1006 // as well as their commuted form.
1007 if (m.left().IsWord32Shl() && m.right().IsWord32Shr()) {
1008 shl = m.left().node();
1009 shr = m.right().node();
1010 } else if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) {
1011 shl = m.right().node();
1012 shr = m.left().node();
1013 } else {
1014 return NoChange();
1015 }
1016
1017 Int32BinopMatcher mshl(shl);
1018 Int32BinopMatcher mshr(shr);
1019 if (mshl.left().node() != mshr.left().node()) return NoChange();
1020
1021 if (mshl.right().HasValue() && mshr.right().HasValue()) {
1022 // Case where y is a constant.
1023 if (mshl.right().Value() + mshr.right().Value() != 32) return NoChange();
1024 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001025 Node* sub = nullptr;
1026 Node* y = nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001027 if (mshl.right().IsInt32Sub()) {
1028 sub = mshl.right().node();
1029 y = mshr.right().node();
1030 } else if (mshr.right().IsInt32Sub()) {
1031 sub = mshr.right().node();
1032 y = mshl.right().node();
1033 } else {
1034 return NoChange();
1035 }
1036
1037 Int32BinopMatcher msub(sub);
1038 if (!msub.left().Is(32) || msub.right().node() != y) return NoChange();
1039 }
1040
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001041 node->ReplaceInput(0, mshl.left().node());
1042 node->ReplaceInput(1, mshr.right().node());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001043 NodeProperties::ChangeOp(node, machine()->Word32Ror());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001044 return Changed(node);
1045}
1046
1047
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001048Reduction MachineOperatorReducer::ReduceFloat64InsertLowWord32(Node* node) {
1049 DCHECK_EQ(IrOpcode::kFloat64InsertLowWord32, node->opcode());
1050 Float64Matcher mlhs(node->InputAt(0));
1051 Uint32Matcher mrhs(node->InputAt(1));
1052 if (mlhs.HasValue() && mrhs.HasValue()) {
1053 return ReplaceFloat64(bit_cast<double>(
1054 (bit_cast<uint64_t>(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF00000000)) |
1055 mrhs.Value()));
1056 }
1057 return NoChange();
1058}
1059
1060
1061Reduction MachineOperatorReducer::ReduceFloat64InsertHighWord32(Node* node) {
1062 DCHECK_EQ(IrOpcode::kFloat64InsertHighWord32, node->opcode());
1063 Float64Matcher mlhs(node->InputAt(0));
1064 Uint32Matcher mrhs(node->InputAt(1));
1065 if (mlhs.HasValue() && mrhs.HasValue()) {
1066 return ReplaceFloat64(bit_cast<double>(
1067 (bit_cast<uint64_t>(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF)) |
1068 (static_cast<uint64_t>(mrhs.Value()) << 32)));
1069 }
1070 return NoChange();
1071}
1072
1073
1074namespace {
1075
1076bool IsFloat64RepresentableAsFloat32(const Float64Matcher& m) {
1077 if (m.HasValue()) {
1078 double v = m.Value();
1079 float fv = static_cast<float>(v);
1080 return static_cast<double>(fv) == v;
1081 }
1082 return false;
1083}
1084
1085} // namespace
1086
1087
1088Reduction MachineOperatorReducer::ReduceFloat64Compare(Node* node) {
1089 DCHECK((IrOpcode::kFloat64Equal == node->opcode()) ||
1090 (IrOpcode::kFloat64LessThan == node->opcode()) ||
1091 (IrOpcode::kFloat64LessThanOrEqual == node->opcode()));
1092 // As all Float32 values have an exact representation in Float64, comparing
1093 // two Float64 values both converted from Float32 is equivalent to comparing
1094 // the original Float32s, so we can ignore the conversions. We can also reduce
1095 // comparisons of converted Float64 values against constants that can be
1096 // represented exactly as Float32.
1097 Float64BinopMatcher m(node);
1098 if ((m.left().IsChangeFloat32ToFloat64() &&
1099 m.right().IsChangeFloat32ToFloat64()) ||
1100 (m.left().IsChangeFloat32ToFloat64() &&
1101 IsFloat64RepresentableAsFloat32(m.right())) ||
1102 (IsFloat64RepresentableAsFloat32(m.left()) &&
1103 m.right().IsChangeFloat32ToFloat64())) {
1104 switch (node->opcode()) {
1105 case IrOpcode::kFloat64Equal:
1106 NodeProperties::ChangeOp(node, machine()->Float32Equal());
1107 break;
1108 case IrOpcode::kFloat64LessThan:
1109 NodeProperties::ChangeOp(node, machine()->Float32LessThan());
1110 break;
1111 case IrOpcode::kFloat64LessThanOrEqual:
1112 NodeProperties::ChangeOp(node, machine()->Float32LessThanOrEqual());
1113 break;
1114 default:
1115 return NoChange();
1116 }
1117 node->ReplaceInput(
1118 0, m.left().HasValue()
1119 ? Float32Constant(static_cast<float>(m.left().Value()))
1120 : m.left().InputAt(0));
1121 node->ReplaceInput(
1122 1, m.right().HasValue()
1123 ? Float32Constant(static_cast<float>(m.right().Value()))
1124 : m.right().InputAt(0));
1125 return Changed(node);
1126 }
1127 return NoChange();
1128}
1129
1130
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001131CommonOperatorBuilder* MachineOperatorReducer::common() const {
1132 return jsgraph()->common();
1133}
1134
1135
1136MachineOperatorBuilder* MachineOperatorReducer::machine() const {
1137 return jsgraph()->machine();
1138}
1139
1140
1141Graph* MachineOperatorReducer::graph() const { return jsgraph()->graph(); }
1142
1143} // namespace compiler
1144} // namespace internal
1145} // namespace v8