8f91d49f815c03d4cb831ec1b1312a7ebfeaf500
[platform/upstream/nodejs.git] / deps / v8 / src / compiler / machine-operator-reducer.cc
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/machine-operator-reducer.h"
6
7 #include "src/base/bits.h"
8 #include "src/base/division-by-constant.h"
9 #include "src/codegen.h"
10 #include "src/compiler/diamond.h"
11 #include "src/compiler/graph.h"
12 #include "src/compiler/js-graph.h"
13 #include "src/compiler/node-matchers.h"
14
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18
19 MachineOperatorReducer::MachineOperatorReducer(JSGraph* jsgraph)
20     : jsgraph_(jsgraph) {}
21
22
23 MachineOperatorReducer::~MachineOperatorReducer() {}
24
25
26 Node* MachineOperatorReducer::Float32Constant(volatile float value) {
27   return graph()->NewNode(common()->Float32Constant(value));
28 }
29
30
31 Node* MachineOperatorReducer::Float64Constant(volatile double value) {
32   return jsgraph()->Float64Constant(value);
33 }
34
35
36 Node* MachineOperatorReducer::Int32Constant(int32_t value) {
37   return jsgraph()->Int32Constant(value);
38 }
39
40
41 Node* MachineOperatorReducer::Int64Constant(int64_t value) {
42   return graph()->NewNode(common()->Int64Constant(value));
43 }
44
45
46 Node* MachineOperatorReducer::Word32And(Node* lhs, Node* rhs) {
47   Node* const node = graph()->NewNode(machine()->Word32And(), lhs, rhs);
48   Reduction const reduction = ReduceWord32And(node);
49   return reduction.Changed() ? reduction.replacement() : node;
50 }
51
52
53 Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) {
54   if (rhs == 0) return lhs;
55   return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs));
56 }
57
58
59 Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
60   if (rhs == 0) return lhs;
61   return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs));
62 }
63
64
65 Node* MachineOperatorReducer::Word32Equal(Node* lhs, Node* rhs) {
66   return graph()->NewNode(machine()->Word32Equal(), lhs, rhs);
67 }
68
69
70 Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
71   Node* const node = graph()->NewNode(machine()->Int32Add(), lhs, rhs);
72   Reduction const reduction = ReduceInt32Add(node);
73   return reduction.Changed() ? reduction.replacement() : node;
74 }
75
76
77 Node* MachineOperatorReducer::Int32Sub(Node* lhs, Node* rhs) {
78   Node* const node = graph()->NewNode(machine()->Int32Sub(), lhs, rhs);
79   Reduction const reduction = ReduceInt32Sub(node);
80   return reduction.Changed() ? reduction.replacement() : node;
81 }
82
83
84 Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) {
85   return graph()->NewNode(machine()->Int32Mul(), lhs, rhs);
86 }
87
88
89 Node* MachineOperatorReducer::Int32Div(Node* dividend, int32_t divisor) {
90   DCHECK_NE(0, divisor);
91   DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
92   base::MagicNumbersForDivision<uint32_t> const mag =
93       base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
94   Node* quotient = graph()->NewNode(machine()->Int32MulHigh(), dividend,
95                                     Uint32Constant(mag.multiplier));
96   if (divisor > 0 && bit_cast<int32_t>(mag.multiplier) < 0) {
97     quotient = Int32Add(quotient, dividend);
98   } else if (divisor < 0 && bit_cast<int32_t>(mag.multiplier) > 0) {
99     quotient = Int32Sub(quotient, dividend);
100   }
101   return Int32Add(Word32Sar(quotient, mag.shift), Word32Shr(dividend, 31));
102 }
103
104
105 Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
106   DCHECK_LT(0u, divisor);
107   // If the divisor is even, we can avoid using the expensive fixup by shifting
108   // the dividend upfront.
109   unsigned const shift = base::bits::CountTrailingZeros32(divisor);
110   dividend = Word32Shr(dividend, shift);
111   divisor >>= shift;
112   // Compute the magic number for the (shifted) divisor.
113   base::MagicNumbersForDivision<uint32_t> const mag =
114       base::UnsignedDivisionByConstant(divisor, shift);
115   Node* quotient = graph()->NewNode(machine()->Uint32MulHigh(), dividend,
116                                     Uint32Constant(mag.multiplier));
117   if (mag.add) {
118     DCHECK_LE(1u, mag.shift);
119     quotient = Word32Shr(
120         Int32Add(Word32Shr(Int32Sub(dividend, quotient), 1), quotient),
121         mag.shift - 1);
122   } else {
123     quotient = Word32Shr(quotient, mag.shift);
124   }
125   return quotient;
126 }
127
128
129 // Perform constant folding and strength reduction on machine operators.
130 Reduction MachineOperatorReducer::Reduce(Node* node) {
131   switch (node->opcode()) {
132     case IrOpcode::kProjection:
133       return ReduceProjection(ProjectionIndexOf(node->op()), node->InputAt(0));
134     case IrOpcode::kWord32And:
135       return ReduceWord32And(node);
136     case IrOpcode::kWord32Or:
137       return ReduceWord32Or(node);
138     case IrOpcode::kWord32Xor: {
139       Int32BinopMatcher m(node);
140       if (m.right().Is(0)) return Replace(m.left().node());  // x ^ 0 => x
141       if (m.IsFoldable()) {                                  // K ^ K => K
142         return ReplaceInt32(m.left().Value() ^ m.right().Value());
143       }
144       if (m.LeftEqualsRight()) return ReplaceInt32(0);  // x ^ x => 0
145       if (m.left().IsWord32Xor() && m.right().Is(-1)) {
146         Int32BinopMatcher mleft(m.left().node());
147         if (mleft.right().Is(-1)) {  // (x ^ -1) ^ -1 => x
148           return Replace(mleft.left().node());
149         }
150       }
151       break;
152     }
153     case IrOpcode::kWord32Shl:
154       return ReduceWord32Shl(node);
155     case IrOpcode::kWord32Shr: {
156       Uint32BinopMatcher m(node);
157       if (m.right().Is(0)) return Replace(m.left().node());  // x >>> 0 => x
158       if (m.IsFoldable()) {                                  // K >>> K => K
159         return ReplaceInt32(m.left().Value() >> m.right().Value());
160       }
161       return ReduceWord32Shifts(node);
162     }
163     case IrOpcode::kWord32Sar: {
164       Int32BinopMatcher m(node);
165       if (m.right().Is(0)) return Replace(m.left().node());  // x >> 0 => x
166       if (m.IsFoldable()) {                                  // K >> K => K
167         return ReplaceInt32(m.left().Value() >> m.right().Value());
168       }
169       if (m.left().IsWord32Shl()) {
170         Int32BinopMatcher mleft(m.left().node());
171         if (mleft.left().IsLoad()) {
172           LoadRepresentation const rep =
173               OpParameter<LoadRepresentation>(mleft.left().node());
174           if (m.right().Is(24) && mleft.right().Is(24) && rep == kMachInt8) {
175             // Load[kMachInt8] << 24 >> 24 => Load[kMachInt8]
176             return Replace(mleft.left().node());
177           }
178           if (m.right().Is(16) && mleft.right().Is(16) && rep == kMachInt16) {
179             // Load[kMachInt16] << 16 >> 16 => Load[kMachInt8]
180             return Replace(mleft.left().node());
181           }
182         }
183       }
184       return ReduceWord32Shifts(node);
185     }
186     case IrOpcode::kWord32Ror: {
187       Int32BinopMatcher m(node);
188       if (m.right().Is(0)) return Replace(m.left().node());  // x ror 0 => x
189       if (m.IsFoldable()) {                                  // K ror K => K
190         return ReplaceInt32(
191             base::bits::RotateRight32(m.left().Value(), m.right().Value()));
192       }
193       break;
194     }
195     case IrOpcode::kWord32Equal: {
196       Int32BinopMatcher m(node);
197       if (m.IsFoldable()) {  // K == K => K
198         return ReplaceBool(m.left().Value() == m.right().Value());
199       }
200       if (m.left().IsInt32Sub() && m.right().Is(0)) {  // x - y == 0 => x == y
201         Int32BinopMatcher msub(m.left().node());
202         node->ReplaceInput(0, msub.left().node());
203         node->ReplaceInput(1, msub.right().node());
204         return Changed(node);
205       }
206       // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
207       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x == x => true
208       break;
209     }
210     case IrOpcode::kWord64Equal: {
211       Int64BinopMatcher m(node);
212       if (m.IsFoldable()) {  // K == K => K
213         return ReplaceBool(m.left().Value() == m.right().Value());
214       }
215       if (m.left().IsInt64Sub() && m.right().Is(0)) {  // x - y == 0 => x == y
216         Int64BinopMatcher msub(m.left().node());
217         node->ReplaceInput(0, msub.left().node());
218         node->ReplaceInput(1, msub.right().node());
219         return Changed(node);
220       }
221       // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
222       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x == x => true
223       break;
224     }
225     case IrOpcode::kInt32Add:
226       return ReduceInt32Add(node);
227     case IrOpcode::kInt32Sub:
228       return ReduceInt32Sub(node);
229     case IrOpcode::kInt32Mul: {
230       Int32BinopMatcher m(node);
231       if (m.right().Is(0)) return Replace(m.right().node());  // x * 0 => 0
232       if (m.right().Is(1)) return Replace(m.left().node());   // x * 1 => x
233       if (m.IsFoldable()) {                                   // K * K => K
234         return ReplaceInt32(m.left().Value() * m.right().Value());
235       }
236       if (m.right().Is(-1)) {  // x * -1 => 0 - x
237         node->set_op(machine()->Int32Sub());
238         node->ReplaceInput(0, Int32Constant(0));
239         node->ReplaceInput(1, m.left().node());
240         return Changed(node);
241       }
242       if (m.right().IsPowerOf2()) {  // x * 2^n => x << n
243         node->set_op(machine()->Word32Shl());
244         node->ReplaceInput(1, Int32Constant(WhichPowerOf2(m.right().Value())));
245         Reduction reduction = ReduceWord32Shl(node);
246         return reduction.Changed() ? reduction : Changed(node);
247       }
248       break;
249     }
250     case IrOpcode::kInt32Div:
251       return ReduceInt32Div(node);
252     case IrOpcode::kUint32Div:
253       return ReduceUint32Div(node);
254     case IrOpcode::kInt32Mod:
255       return ReduceInt32Mod(node);
256     case IrOpcode::kUint32Mod:
257       return ReduceUint32Mod(node);
258     case IrOpcode::kInt32LessThan: {
259       Int32BinopMatcher m(node);
260       if (m.IsFoldable()) {  // K < K => K
261         return ReplaceBool(m.left().Value() < m.right().Value());
262       }
263       if (m.left().IsInt32Sub() && m.right().Is(0)) {  // x - y < 0 => x < y
264         Int32BinopMatcher msub(m.left().node());
265         node->ReplaceInput(0, msub.left().node());
266         node->ReplaceInput(1, msub.right().node());
267         return Changed(node);
268       }
269       if (m.left().Is(0) && m.right().IsInt32Sub()) {  // 0 < x - y => y < x
270         Int32BinopMatcher msub(m.right().node());
271         node->ReplaceInput(0, msub.right().node());
272         node->ReplaceInput(1, msub.left().node());
273         return Changed(node);
274       }
275       if (m.LeftEqualsRight()) return ReplaceBool(false);  // x < x => false
276       break;
277     }
278     case IrOpcode::kInt32LessThanOrEqual: {
279       Int32BinopMatcher m(node);
280       if (m.IsFoldable()) {  // K <= K => K
281         return ReplaceBool(m.left().Value() <= m.right().Value());
282       }
283       if (m.left().IsInt32Sub() && m.right().Is(0)) {  // x - y <= 0 => x <= y
284         Int32BinopMatcher msub(m.left().node());
285         node->ReplaceInput(0, msub.left().node());
286         node->ReplaceInput(1, msub.right().node());
287         return Changed(node);
288       }
289       if (m.left().Is(0) && m.right().IsInt32Sub()) {  // 0 <= x - y => y <= x
290         Int32BinopMatcher msub(m.right().node());
291         node->ReplaceInput(0, msub.right().node());
292         node->ReplaceInput(1, msub.left().node());
293         return Changed(node);
294       }
295       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x <= x => true
296       break;
297     }
298     case IrOpcode::kUint32LessThan: {
299       Uint32BinopMatcher m(node);
300       if (m.left().Is(kMaxUInt32)) return ReplaceBool(false);  // M < x => false
301       if (m.right().Is(0)) return ReplaceBool(false);          // x < 0 => false
302       if (m.IsFoldable()) {                                    // K < K => K
303         return ReplaceBool(m.left().Value() < m.right().Value());
304       }
305       if (m.LeftEqualsRight()) return ReplaceBool(false);  // x < x => false
306       if (m.left().IsWord32Sar() && m.right().HasValue()) {
307         Int32BinopMatcher mleft(m.left().node());
308         if (mleft.right().HasValue()) {
309           // (x >> K) < C => x < (C << K)
310           // when C < (M >> K)
311           const uint32_t c = m.right().Value();
312           const uint32_t k = mleft.right().Value() & 0x1f;
313           if (c < static_cast<uint32_t>(kMaxInt >> k)) {
314             node->ReplaceInput(0, mleft.left().node());
315             node->ReplaceInput(1, Uint32Constant(c << k));
316             return Changed(node);
317           }
318           // TODO(turbofan): else the comparison is always true.
319         }
320       }
321       break;
322     }
323     case IrOpcode::kUint32LessThanOrEqual: {
324       Uint32BinopMatcher m(node);
325       if (m.left().Is(0)) return ReplaceBool(true);            // 0 <= x => true
326       if (m.right().Is(kMaxUInt32)) return ReplaceBool(true);  // x <= M => true
327       if (m.IsFoldable()) {                                    // K <= K => K
328         return ReplaceBool(m.left().Value() <= m.right().Value());
329       }
330       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x <= x => true
331       break;
332     }
333     case IrOpcode::kFloat64Add: {
334       Float64BinopMatcher m(node);
335       if (m.right().IsNaN()) {  // x + NaN => NaN
336         return Replace(m.right().node());
337       }
338       if (m.IsFoldable()) {  // K + K => K
339         return ReplaceFloat64(m.left().Value() + m.right().Value());
340       }
341       break;
342     }
343     case IrOpcode::kFloat64Sub: {
344       Float64BinopMatcher m(node);
345       if (m.right().Is(0) && (Double(m.right().Value()).Sign() > 0)) {
346         return Replace(m.left().node());  // x - 0 => x
347       }
348       if (m.right().IsNaN()) {  // x - NaN => NaN
349         return Replace(m.right().node());
350       }
351       if (m.left().IsNaN()) {  // NaN - x => NaN
352         return Replace(m.left().node());
353       }
354       if (m.IsFoldable()) {  // K - K => K
355         return ReplaceFloat64(m.left().Value() - m.right().Value());
356       }
357       break;
358     }
359     case IrOpcode::kFloat64Mul: {
360       Float64BinopMatcher m(node);
361       if (m.right().Is(-1)) {  // x * -1.0 => -0.0 - x
362         node->set_op(machine()->Float64Sub());
363         node->ReplaceInput(0, Float64Constant(-0.0));
364         node->ReplaceInput(1, m.left().node());
365         return Changed(node);
366       }
367       if (m.right().Is(1)) return Replace(m.left().node());  // x * 1.0 => x
368       if (m.right().IsNaN()) {                               // x * NaN => NaN
369         return Replace(m.right().node());
370       }
371       if (m.IsFoldable()) {  // K * K => K
372         return ReplaceFloat64(m.left().Value() * m.right().Value());
373       }
374       break;
375     }
376     case IrOpcode::kFloat64Div: {
377       Float64BinopMatcher m(node);
378       if (m.right().Is(1)) return Replace(m.left().node());  // x / 1.0 => x
379       if (m.right().IsNaN()) {                               // x / NaN => NaN
380         return Replace(m.right().node());
381       }
382       if (m.left().IsNaN()) {  // NaN / x => NaN
383         return Replace(m.left().node());
384       }
385       if (m.IsFoldable()) {  // K / K => K
386         return ReplaceFloat64(m.left().Value() / m.right().Value());
387       }
388       break;
389     }
390     case IrOpcode::kFloat64Mod: {
391       Float64BinopMatcher m(node);
392       if (m.right().Is(0)) {  // x % 0 => NaN
393         return ReplaceFloat64(std::numeric_limits<double>::quiet_NaN());
394       }
395       if (m.right().IsNaN()) {  // x % NaN => NaN
396         return Replace(m.right().node());
397       }
398       if (m.left().IsNaN()) {  // NaN % x => NaN
399         return Replace(m.left().node());
400       }
401       if (m.IsFoldable()) {  // K % K => K
402         return ReplaceFloat64(modulo(m.left().Value(), m.right().Value()));
403       }
404       break;
405     }
406     case IrOpcode::kChangeFloat32ToFloat64: {
407       Float32Matcher m(node->InputAt(0));
408       if (m.HasValue()) return ReplaceFloat64(m.Value());
409       break;
410     }
411     case IrOpcode::kChangeFloat64ToInt32: {
412       Float64Matcher m(node->InputAt(0));
413       if (m.HasValue()) return ReplaceInt32(FastD2I(m.Value()));
414       if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
415       break;
416     }
417     case IrOpcode::kChangeFloat64ToUint32: {
418       Float64Matcher m(node->InputAt(0));
419       if (m.HasValue()) return ReplaceInt32(FastD2UI(m.Value()));
420       if (m.IsChangeUint32ToFloat64()) return Replace(m.node()->InputAt(0));
421       break;
422     }
423     case IrOpcode::kChangeInt32ToFloat64: {
424       Int32Matcher m(node->InputAt(0));
425       if (m.HasValue()) return ReplaceFloat64(FastI2D(m.Value()));
426       break;
427     }
428     case IrOpcode::kChangeInt32ToInt64: {
429       Int32Matcher m(node->InputAt(0));
430       if (m.HasValue()) return ReplaceInt64(m.Value());
431       break;
432     }
433     case IrOpcode::kChangeUint32ToFloat64: {
434       Uint32Matcher m(node->InputAt(0));
435       if (m.HasValue()) return ReplaceFloat64(FastUI2D(m.Value()));
436       break;
437     }
438     case IrOpcode::kChangeUint32ToUint64: {
439       Uint32Matcher m(node->InputAt(0));
440       if (m.HasValue()) return ReplaceInt64(static_cast<uint64_t>(m.Value()));
441       break;
442     }
443     case IrOpcode::kTruncateFloat64ToInt32:
444       return ReduceTruncateFloat64ToInt32(node);
445     case IrOpcode::kTruncateInt64ToInt32: {
446       Int64Matcher m(node->InputAt(0));
447       if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value()));
448       if (m.IsChangeInt32ToInt64()) return Replace(m.node()->InputAt(0));
449       break;
450     }
451     case IrOpcode::kTruncateFloat64ToFloat32: {
452       Float64Matcher m(node->InputAt(0));
453       if (m.HasValue()) return ReplaceFloat32(DoubleToFloat32(m.Value()));
454       if (m.IsChangeFloat32ToFloat64()) return Replace(m.node()->InputAt(0));
455       break;
456     }
457     case IrOpcode::kStore:
458       return ReduceStore(node);
459     default:
460       break;
461   }
462   return NoChange();
463 }
464
465
466 Reduction MachineOperatorReducer::ReduceInt32Add(Node* node) {
467   DCHECK_EQ(IrOpcode::kInt32Add, node->opcode());
468   Int32BinopMatcher m(node);
469   if (m.right().Is(0)) return Replace(m.left().node());  // x + 0 => x
470   if (m.IsFoldable()) {                                  // K + K => K
471     return ReplaceUint32(bit_cast<uint32_t>(m.left().Value()) +
472                          bit_cast<uint32_t>(m.right().Value()));
473   }
474   return NoChange();
475 }
476
477
478 Reduction MachineOperatorReducer::ReduceInt32Sub(Node* node) {
479   DCHECK_EQ(IrOpcode::kInt32Sub, node->opcode());
480   Int32BinopMatcher m(node);
481   if (m.right().Is(0)) return Replace(m.left().node());  // x - 0 => x
482   if (m.IsFoldable()) {                                  // K - K => K
483     return ReplaceInt32(static_cast<uint32_t>(m.left().Value()) -
484                         static_cast<uint32_t>(m.right().Value()));
485   }
486   if (m.LeftEqualsRight()) return ReplaceInt32(0);  // x - x => 0
487   if (m.right().HasValue()) {                       // x - K => x + -K
488     node->set_op(machine()->Int32Add());
489     node->ReplaceInput(1, Int32Constant(-m.right().Value()));
490     Reduction const reduction = ReduceInt32Add(node);
491     return reduction.Changed() ? reduction : Changed(node);
492   }
493   return NoChange();
494 }
495
496
497 Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
498   Int32BinopMatcher m(node);
499   if (m.left().Is(0)) return Replace(m.left().node());    // 0 / x => 0
500   if (m.right().Is(0)) return Replace(m.right().node());  // x / 0 => 0
501   if (m.right().Is(1)) return Replace(m.left().node());   // x / 1 => x
502   if (m.IsFoldable()) {                                   // K / K => K
503     return ReplaceInt32(
504         base::bits::SignedDiv32(m.left().Value(), m.right().Value()));
505   }
506   if (m.LeftEqualsRight()) {  // x / x => x != 0
507     Node* const zero = Int32Constant(0);
508     return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
509   }
510   if (m.right().Is(-1)) {  // x / -1 => 0 - x
511     node->set_op(machine()->Int32Sub());
512     node->ReplaceInput(0, Int32Constant(0));
513     node->ReplaceInput(1, m.left().node());
514     node->TrimInputCount(2);
515     return Changed(node);
516   }
517   if (m.right().HasValue()) {
518     int32_t const divisor = m.right().Value();
519     Node* const dividend = m.left().node();
520     Node* quotient = dividend;
521     if (base::bits::IsPowerOfTwo32(Abs(divisor))) {
522       uint32_t const shift = WhichPowerOf2Abs(divisor);
523       DCHECK_NE(0u, shift);
524       if (shift > 1) {
525         quotient = Word32Sar(quotient, 31);
526       }
527       quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend);
528       quotient = Word32Sar(quotient, shift);
529     } else {
530       quotient = Int32Div(quotient, Abs(divisor));
531     }
532     if (divisor < 0) {
533       node->set_op(machine()->Int32Sub());
534       node->ReplaceInput(0, Int32Constant(0));
535       node->ReplaceInput(1, quotient);
536       node->TrimInputCount(2);
537       return Changed(node);
538     }
539     return Replace(quotient);
540   }
541   return NoChange();
542 }
543
544
545 Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
546   Uint32BinopMatcher m(node);
547   if (m.left().Is(0)) return Replace(m.left().node());    // 0 / x => 0
548   if (m.right().Is(0)) return Replace(m.right().node());  // x / 0 => 0
549   if (m.right().Is(1)) return Replace(m.left().node());   // x / 1 => x
550   if (m.IsFoldable()) {                                   // K / K => K
551     return ReplaceUint32(
552         base::bits::UnsignedDiv32(m.left().Value(), m.right().Value()));
553   }
554   if (m.LeftEqualsRight()) {  // x / x => x != 0
555     Node* const zero = Int32Constant(0);
556     return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
557   }
558   if (m.right().HasValue()) {
559     Node* const dividend = m.left().node();
560     uint32_t const divisor = m.right().Value();
561     if (base::bits::IsPowerOfTwo32(divisor)) {  // x / 2^n => x >> n
562       node->set_op(machine()->Word32Shr());
563       node->ReplaceInput(1, Uint32Constant(WhichPowerOf2(m.right().Value())));
564       node->TrimInputCount(2);
565       return Changed(node);
566     } else {
567       return Replace(Uint32Div(dividend, divisor));
568     }
569   }
570   return NoChange();
571 }
572
573
574 Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
575   Int32BinopMatcher m(node);
576   if (m.left().Is(0)) return Replace(m.left().node());    // 0 % x  => 0
577   if (m.right().Is(0)) return Replace(m.right().node());  // x % 0  => 0
578   if (m.right().Is(1)) return ReplaceInt32(0);            // x % 1  => 0
579   if (m.right().Is(-1)) return ReplaceInt32(0);           // x % -1 => 0
580   if (m.LeftEqualsRight()) return ReplaceInt32(0);        // x % x  => 0
581   if (m.IsFoldable()) {                                   // K % K => K
582     return ReplaceInt32(
583         base::bits::SignedMod32(m.left().Value(), m.right().Value()));
584   }
585   if (m.right().HasValue()) {
586     Node* const dividend = m.left().node();
587     int32_t const divisor = Abs(m.right().Value());
588     if (base::bits::IsPowerOfTwo32(divisor)) {
589       uint32_t const mask = divisor - 1;
590       Node* const zero = Int32Constant(0);
591       node->set_op(common()->Select(kMachInt32, BranchHint::kFalse));
592       node->ReplaceInput(
593           0, graph()->NewNode(machine()->Int32LessThan(), dividend, zero));
594       node->ReplaceInput(
595           1, Int32Sub(zero, Word32And(Int32Sub(zero, dividend), mask)));
596       node->ReplaceInput(2, Word32And(dividend, mask));
597     } else {
598       Node* quotient = Int32Div(dividend, divisor);
599       node->set_op(machine()->Int32Sub());
600       DCHECK_EQ(dividend, node->InputAt(0));
601       node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
602       node->TrimInputCount(2);
603     }
604     return Changed(node);
605   }
606   return NoChange();
607 }
608
609
610 Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) {
611   Uint32BinopMatcher m(node);
612   if (m.left().Is(0)) return Replace(m.left().node());    // 0 % x => 0
613   if (m.right().Is(0)) return Replace(m.right().node());  // x % 0 => 0
614   if (m.right().Is(1)) return ReplaceUint32(0);           // x % 1 => 0
615   if (m.LeftEqualsRight()) return ReplaceInt32(0);        // x % x  => 0
616   if (m.IsFoldable()) {                                   // K % K => K
617     return ReplaceUint32(
618         base::bits::UnsignedMod32(m.left().Value(), m.right().Value()));
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 & 2^n-1
624       node->set_op(machine()->Word32And());
625       node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1));
626     } else {
627       Node* quotient = Uint32Div(dividend, divisor);
628       node->set_op(machine()->Int32Sub());
629       DCHECK_EQ(dividend, node->InputAt(0));
630       node->ReplaceInput(1, Int32Mul(quotient, Uint32Constant(divisor)));
631     }
632     node->TrimInputCount(2);
633     return Changed(node);
634   }
635   return NoChange();
636 }
637
638
639 Reduction MachineOperatorReducer::ReduceTruncateFloat64ToInt32(Node* node) {
640   Float64Matcher m(node->InputAt(0));
641   if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value()));
642   if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
643   if (m.IsPhi()) {
644     Node* const phi = m.node();
645     DCHECK_EQ(kRepFloat64, RepresentationOf(OpParameter<MachineType>(phi)));
646     if (phi->OwnedBy(node)) {
647       // TruncateFloat64ToInt32(Phi[Float64](x1,...,xn))
648       //   => Phi[Int32](TruncateFloat64ToInt32(x1),
649       //                 ...,
650       //                 TruncateFloat64ToInt32(xn))
651       const int value_input_count = phi->InputCount() - 1;
652       for (int i = 0; i < value_input_count; ++i) {
653         Node* input = graph()->NewNode(machine()->TruncateFloat64ToInt32(),
654                                        phi->InputAt(i));
655         // TODO(bmeurer): Reschedule input for reduction once we have Revisit()
656         // instead of recursing into ReduceTruncateFloat64ToInt32() here.
657         Reduction reduction = ReduceTruncateFloat64ToInt32(input);
658         if (reduction.Changed()) input = reduction.replacement();
659         phi->ReplaceInput(i, input);
660       }
661       phi->set_op(common()->Phi(kMachInt32, value_input_count));
662       return Replace(phi);
663     }
664   }
665   return NoChange();
666 }
667
668
669 Reduction MachineOperatorReducer::ReduceStore(Node* node) {
670   MachineType const rep =
671       RepresentationOf(StoreRepresentationOf(node->op()).machine_type());
672   Node* const value = node->InputAt(2);
673   switch (value->opcode()) {
674     case IrOpcode::kWord32And: {
675       Uint32BinopMatcher m(value);
676       if (m.right().HasValue() &&
677           ((rep == kRepWord8 && (m.right().Value() & 0xff) == 0xff) ||
678            (rep == kRepWord16 && (m.right().Value() & 0xffff) == 0xffff))) {
679         node->ReplaceInput(2, m.left().node());
680         return Changed(node);
681       }
682       break;
683     }
684     case IrOpcode::kWord32Sar: {
685       Int32BinopMatcher m(value);
686       if (m.left().IsWord32Shl() &&
687           ((rep == kRepWord8 && m.right().IsInRange(1, 24)) ||
688            (rep == kRepWord16 && m.right().IsInRange(1, 16)))) {
689         Int32BinopMatcher mleft(m.left().node());
690         if (mleft.right().Is(m.right().Value())) {
691           node->ReplaceInput(2, mleft.left().node());
692           return Changed(node);
693         }
694       }
695       break;
696     }
697     default:
698       break;
699   }
700   return NoChange();
701 }
702
703
704 Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) {
705   switch (node->opcode()) {
706     case IrOpcode::kInt32AddWithOverflow: {
707       DCHECK(index == 0 || index == 1);
708       Int32BinopMatcher m(node);
709       if (m.IsFoldable()) {
710         int32_t val;
711         bool ovf = base::bits::SignedAddOverflow32(m.left().Value(),
712                                                    m.right().Value(), &val);
713         return ReplaceInt32((index == 0) ? val : ovf);
714       }
715       if (m.right().Is(0)) {
716         return (index == 0) ? Replace(m.left().node()) : ReplaceInt32(0);
717       }
718       break;
719     }
720     case IrOpcode::kInt32SubWithOverflow: {
721       DCHECK(index == 0 || index == 1);
722       Int32BinopMatcher m(node);
723       if (m.IsFoldable()) {
724         int32_t val;
725         bool ovf = base::bits::SignedSubOverflow32(m.left().Value(),
726                                                    m.right().Value(), &val);
727         return ReplaceInt32((index == 0) ? val : ovf);
728       }
729       if (m.right().Is(0)) {
730         return (index == 0) ? Replace(m.left().node()) : ReplaceInt32(0);
731       }
732       break;
733     }
734     default:
735       break;
736   }
737   return NoChange();
738 }
739
740
741 Reduction MachineOperatorReducer::ReduceWord32Shifts(Node* node) {
742   DCHECK((node->opcode() == IrOpcode::kWord32Shl) ||
743          (node->opcode() == IrOpcode::kWord32Shr) ||
744          (node->opcode() == IrOpcode::kWord32Sar));
745   if (machine()->Word32ShiftIsSafe()) {
746     // Remove the explicit 'and' with 0x1f if the shift provided by the machine
747     // instruction matches that required by JavaScript.
748     Int32BinopMatcher m(node);
749     if (m.right().IsWord32And()) {
750       Int32BinopMatcher mright(m.right().node());
751       if (mright.right().Is(0x1f)) {
752         node->ReplaceInput(1, mright.left().node());
753         return Changed(node);
754       }
755     }
756   }
757   return NoChange();
758 }
759
760
761 Reduction MachineOperatorReducer::ReduceWord32Shl(Node* node) {
762   DCHECK_EQ(IrOpcode::kWord32Shl, node->opcode());
763   Int32BinopMatcher m(node);
764   if (m.right().Is(0)) return Replace(m.left().node());  // x << 0 => x
765   if (m.IsFoldable()) {                                  // K << K => K
766     return ReplaceInt32(m.left().Value() << m.right().Value());
767   }
768   if (m.right().IsInRange(1, 31)) {
769     // (x >>> K) << K => x & ~(2^K - 1)
770     // (x >> K) << K => x & ~(2^K - 1)
771     if (m.left().IsWord32Sar() || m.left().IsWord32Shr()) {
772       Int32BinopMatcher mleft(m.left().node());
773       if (mleft.right().Is(m.right().Value())) {
774         node->set_op(machine()->Word32And());
775         node->ReplaceInput(0, mleft.left().node());
776         node->ReplaceInput(1,
777                            Uint32Constant(~((1U << m.right().Value()) - 1U)));
778         Reduction reduction = ReduceWord32And(node);
779         return reduction.Changed() ? reduction : Changed(node);
780       }
781     }
782   }
783   return ReduceWord32Shifts(node);
784 }
785
786
787 Reduction MachineOperatorReducer::ReduceWord32And(Node* node) {
788   DCHECK_EQ(IrOpcode::kWord32And, node->opcode());
789   Int32BinopMatcher m(node);
790   if (m.right().Is(0)) return Replace(m.right().node());  // x & 0  => 0
791   if (m.right().Is(-1)) return Replace(m.left().node());  // x & -1 => x
792   if (m.IsFoldable()) {                                   // K & K  => K
793     return ReplaceInt32(m.left().Value() & m.right().Value());
794   }
795   if (m.LeftEqualsRight()) return Replace(m.left().node());  // x & x => x
796   if (m.left().IsWord32And() && m.right().HasValue()) {
797     Int32BinopMatcher mleft(m.left().node());
798     if (mleft.right().HasValue()) {  // (x & K) & K => x & K
799       node->ReplaceInput(0, mleft.left().node());
800       node->ReplaceInput(
801           1, Int32Constant(m.right().Value() & mleft.right().Value()));
802       Reduction const reduction = ReduceWord32And(node);
803       return reduction.Changed() ? reduction : Changed(node);
804     }
805   }
806   if (m.right().IsNegativePowerOf2()) {
807     int32_t const mask = m.right().Value();
808     if (m.left().IsWord32Shl()) {
809       Uint32BinopMatcher mleft(m.left().node());
810       if (mleft.right().HasValue() &&
811           mleft.right().Value() >= base::bits::CountTrailingZeros32(mask)) {
812         // (x << L) & (-1 << K) => x << L iff K >= L
813         return Replace(mleft.node());
814       }
815     } else if (m.left().IsInt32Add()) {
816       Int32BinopMatcher mleft(m.left().node());
817       if (mleft.right().HasValue() &&
818           (mleft.right().Value() & mask) == mleft.right().Value()) {
819         // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
820         node->set_op(machine()->Int32Add());
821         node->ReplaceInput(0, Word32And(mleft.left().node(), m.right().node()));
822         node->ReplaceInput(1, mleft.right().node());
823         Reduction const reduction = ReduceInt32Add(node);
824         return reduction.Changed() ? reduction : Changed(node);
825       }
826       if (mleft.left().IsInt32Mul()) {
827         Int32BinopMatcher mleftleft(mleft.left().node());
828         if (mleftleft.right().IsMultipleOf(-mask)) {
829           // (y * (K << L) + x) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
830           node->set_op(machine()->Int32Add());
831           node->ReplaceInput(0,
832                              Word32And(mleft.right().node(), m.right().node()));
833           node->ReplaceInput(1, mleftleft.node());
834           Reduction const reduction = ReduceInt32Add(node);
835           return reduction.Changed() ? reduction : Changed(node);
836         }
837       }
838       if (mleft.right().IsInt32Mul()) {
839         Int32BinopMatcher mleftright(mleft.right().node());
840         if (mleftright.right().IsMultipleOf(-mask)) {
841           // (x + y * (K << L)) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
842           node->set_op(machine()->Int32Add());
843           node->ReplaceInput(0,
844                              Word32And(mleft.left().node(), m.right().node()));
845           node->ReplaceInput(1, mleftright.node());
846           Reduction const reduction = ReduceInt32Add(node);
847           return reduction.Changed() ? reduction : Changed(node);
848         }
849       }
850       if (mleft.left().IsWord32Shl()) {
851         Int32BinopMatcher mleftleft(mleft.left().node());
852         if (mleftleft.right().Is(base::bits::CountTrailingZeros32(mask))) {
853           // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
854           node->set_op(machine()->Int32Add());
855           node->ReplaceInput(0,
856                              Word32And(mleft.right().node(), m.right().node()));
857           node->ReplaceInput(1, mleftleft.node());
858           Reduction const reduction = ReduceInt32Add(node);
859           return reduction.Changed() ? reduction : Changed(node);
860         }
861       }
862       if (mleft.right().IsWord32Shl()) {
863         Int32BinopMatcher mleftright(mleft.right().node());
864         if (mleftright.right().Is(base::bits::CountTrailingZeros32(mask))) {
865           // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
866           node->set_op(machine()->Int32Add());
867           node->ReplaceInput(0,
868                              Word32And(mleft.left().node(), m.right().node()));
869           node->ReplaceInput(1, mleftright.node());
870           Reduction const reduction = ReduceInt32Add(node);
871           return reduction.Changed() ? reduction : Changed(node);
872         }
873       }
874     }
875   }
876   return NoChange();
877 }
878
879
880 Reduction MachineOperatorReducer::ReduceWord32Or(Node* node) {
881   DCHECK_EQ(IrOpcode::kWord32Or, node->opcode());
882   Int32BinopMatcher m(node);
883   if (m.right().Is(0)) return Replace(m.left().node());    // x | 0  => x
884   if (m.right().Is(-1)) return Replace(m.right().node());  // x | -1 => -1
885   if (m.IsFoldable()) {                                    // K | K  => K
886     return ReplaceInt32(m.left().Value() | m.right().Value());
887   }
888   if (m.LeftEqualsRight()) return Replace(m.left().node());  // x | x => x
889
890   Node* shl = NULL;
891   Node* shr = NULL;
892   // Recognize rotation, we are matching either:
893   //  * x << y | x >>> (32 - y) => x ror (32 - y), i.e  x rol y
894   //  * x << (32 - y) | x >>> y => x ror y
895   // as well as their commuted form.
896   if (m.left().IsWord32Shl() && m.right().IsWord32Shr()) {
897     shl = m.left().node();
898     shr = m.right().node();
899   } else if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) {
900     shl = m.right().node();
901     shr = m.left().node();
902   } else {
903     return NoChange();
904   }
905
906   Int32BinopMatcher mshl(shl);
907   Int32BinopMatcher mshr(shr);
908   if (mshl.left().node() != mshr.left().node()) return NoChange();
909
910   if (mshl.right().HasValue() && mshr.right().HasValue()) {
911     // Case where y is a constant.
912     if (mshl.right().Value() + mshr.right().Value() != 32) return NoChange();
913   } else {
914     Node* sub = NULL;
915     Node* y = NULL;
916     if (mshl.right().IsInt32Sub()) {
917       sub = mshl.right().node();
918       y = mshr.right().node();
919     } else if (mshr.right().IsInt32Sub()) {
920       sub = mshr.right().node();
921       y = mshl.right().node();
922     } else {
923       return NoChange();
924     }
925
926     Int32BinopMatcher msub(sub);
927     if (!msub.left().Is(32) || msub.right().node() != y) return NoChange();
928   }
929
930   node->set_op(machine()->Word32Ror());
931   node->ReplaceInput(0, mshl.left().node());
932   node->ReplaceInput(1, mshr.right().node());
933   return Changed(node);
934 }
935
936
937 CommonOperatorBuilder* MachineOperatorReducer::common() const {
938   return jsgraph()->common();
939 }
940
941
942 MachineOperatorBuilder* MachineOperatorReducer::machine() const {
943   return jsgraph()->machine();
944 }
945
946
947 Graph* MachineOperatorReducer::graph() const { return jsgraph()->graph(); }
948
949 }  // namespace compiler
950 }  // namespace internal
951 }  // namespace v8