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 #include <cmath>
7 
8 #include "src/base/bits.h"
9 #include "src/base/division-by-constant.h"
10 #include "src/base/ieee754.h"
11 #include "src/base/overflowing-math.h"
12 #include "src/compiler/diamond.h"
13 #include "src/compiler/graph.h"
14 #include "src/compiler/machine-graph.h"
15 #include "src/compiler/node-matchers.h"
16 #include "src/compiler/node-properties.h"
17 #include "src/numbers/conversions-inl.h"
18 
19 namespace v8 {
20 namespace internal {
21 namespace compiler {
22 
23 // Some optimizations performed by the MachineOperatorReducer can be applied
24 // to both Word32 and Word64 operations. Those are implemented in a generic
25 // way to be reused for different word sizes.
26 // This class adapts a generic algorithm to Word32 operations.
27 class Word32Adapter {
28  public:
29   using IntNBinopMatcher = Int32BinopMatcher;
30   using UintNBinopMatcher = Uint32BinopMatcher;
31   using intN_t = int32_t;
32   // WORD_SIZE refers to the N for which this adapter specializes.
33   static constexpr std::size_t WORD_SIZE = 32;
34 
Word32Adapter(MachineOperatorReducer * reducer)35   explicit Word32Adapter(MachineOperatorReducer* reducer) : r_(reducer) {}
36 
37   template <typename T>
IsWordNAnd(const T & x)38   static bool IsWordNAnd(const T& x) {
39     return x.IsWord32And();
40   }
41   template <typename T>
IsWordNShl(const T & x)42   static bool IsWordNShl(const T& x) {
43     return x.IsWord32Shl();
44   }
45   template <typename T>
IsWordNXor(const T & x)46   static bool IsWordNXor(const T& x) {
47     return x.IsWord32Xor();
48   }
49   template <typename T>
IsIntNAdd(const T & x)50   static bool IsIntNAdd(const T& x) {
51     return x.IsInt32Add();
52   }
53   template <typename T>
IsIntNMul(const T & x)54   static bool IsIntNMul(const T& x) {
55     return x.IsInt32Mul();
56   }
57 
IntNAdd(MachineOperatorBuilder * machine)58   const Operator* IntNAdd(MachineOperatorBuilder* machine) {
59     return machine->Int32Add();
60   }
61 
ReplaceIntN(int32_t value)62   Reduction ReplaceIntN(int32_t value) { return r_->ReplaceInt32(value); }
ReduceWordNAnd(Node * node)63   Reduction ReduceWordNAnd(Node* node) { return r_->ReduceWord32And(node); }
ReduceIntNAdd(Node * node)64   Reduction ReduceIntNAdd(Node* node) { return r_->ReduceInt32Add(node); }
TryMatchWordNRor(Node * node)65   Reduction TryMatchWordNRor(Node* node) { return r_->TryMatchWord32Ror(node); }
66 
IntNConstant(int32_t value)67   Node* IntNConstant(int32_t value) { return r_->Int32Constant(value); }
WordNAnd(Node * lhs,Node * rhs)68   Node* WordNAnd(Node* lhs, Node* rhs) { return r_->Word32And(lhs, rhs); }
69 
70  private:
71   MachineOperatorReducer* r_;
72 };
73 
74 // Some optimizations performed by the MachineOperatorReducer can be applied
75 // to both Word32 and Word64 operations. Those are implemented in a generic
76 // way to be reused for different word sizes.
77 // This class adapts a generic algorithm to Word64 operations.
78 class Word64Adapter {
79  public:
80   using IntNBinopMatcher = Int64BinopMatcher;
81   using UintNBinopMatcher = Uint64BinopMatcher;
82   using intN_t = int64_t;
83   // WORD_SIZE refers to the N for which this adapter specializes.
84   static constexpr std::size_t WORD_SIZE = 64;
85 
Word64Adapter(MachineOperatorReducer * reducer)86   explicit Word64Adapter(MachineOperatorReducer* reducer) : r_(reducer) {}
87 
88   template <typename T>
IsWordNAnd(const T & x)89   static bool IsWordNAnd(const T& x) {
90     return x.IsWord64And();
91   }
92   template <typename T>
IsWordNShl(const T & x)93   static bool IsWordNShl(const T& x) {
94     return x.IsWord64Shl();
95   }
96   template <typename T>
IsWordNXor(const T & x)97   static bool IsWordNXor(const T& x) {
98     return x.IsWord64Xor();
99   }
100   template <typename T>
IsIntNAdd(const T & x)101   static bool IsIntNAdd(const T& x) {
102     return x.IsInt64Add();
103   }
104   template <typename T>
IsIntNMul(const T & x)105   static bool IsIntNMul(const T& x) {
106     return x.IsInt64Mul();
107   }
108 
IntNAdd(MachineOperatorBuilder * machine)109   static const Operator* IntNAdd(MachineOperatorBuilder* machine) {
110     return machine->Int64Add();
111   }
112 
ReplaceIntN(int64_t value)113   Reduction ReplaceIntN(int64_t value) { return r_->ReplaceInt64(value); }
ReduceWordNAnd(Node * node)114   Reduction ReduceWordNAnd(Node* node) { return r_->ReduceWord64And(node); }
ReduceIntNAdd(Node * node)115   Reduction ReduceIntNAdd(Node* node) { return r_->ReduceInt64Add(node); }
TryMatchWordNRor(Node * node)116   Reduction TryMatchWordNRor(Node* node) {
117     // TODO(nicohartmann@): Add a MachineOperatorReducer::TryMatchWord64Ror.
118     return r_->NoChange();
119   }
120 
IntNConstant(int64_t value)121   Node* IntNConstant(int64_t value) { return r_->Int64Constant(value); }
WordNAnd(Node * lhs,Node * rhs)122   Node* WordNAnd(Node* lhs, Node* rhs) { return r_->Word64And(lhs, rhs); }
123 
124  private:
125   MachineOperatorReducer* r_;
126 };
127 
MachineOperatorReducer(Editor * editor,MachineGraph * mcgraph,bool allow_signalling_nan)128 MachineOperatorReducer::MachineOperatorReducer(Editor* editor,
129                                                MachineGraph* mcgraph,
130                                                bool allow_signalling_nan)
131     : AdvancedReducer(editor),
132       mcgraph_(mcgraph),
133       allow_signalling_nan_(allow_signalling_nan) {}
134 
135 MachineOperatorReducer::~MachineOperatorReducer() = default;
136 
137 
Float32Constant(volatile float value)138 Node* MachineOperatorReducer::Float32Constant(volatile float value) {
139   return graph()->NewNode(common()->Float32Constant(value));
140 }
141 
Float64Constant(volatile double value)142 Node* MachineOperatorReducer::Float64Constant(volatile double value) {
143   return mcgraph()->Float64Constant(value);
144 }
145 
Int32Constant(int32_t value)146 Node* MachineOperatorReducer::Int32Constant(int32_t value) {
147   return mcgraph()->Int32Constant(value);
148 }
149 
Int64Constant(int64_t value)150 Node* MachineOperatorReducer::Int64Constant(int64_t value) {
151   return graph()->NewNode(common()->Int64Constant(value));
152 }
153 
Float64Mul(Node * lhs,Node * rhs)154 Node* MachineOperatorReducer::Float64Mul(Node* lhs, Node* rhs) {
155   return graph()->NewNode(machine()->Float64Mul(), lhs, rhs);
156 }
157 
Float64PowHalf(Node * value)158 Node* MachineOperatorReducer::Float64PowHalf(Node* value) {
159   value =
160       graph()->NewNode(machine()->Float64Add(), Float64Constant(0.0), value);
161   Diamond d(graph(), common(),
162             graph()->NewNode(machine()->Float64LessThanOrEqual(), value,
163                              Float64Constant(-V8_INFINITY)),
164             BranchHint::kFalse);
165   return d.Phi(MachineRepresentation::kFloat64, Float64Constant(V8_INFINITY),
166                graph()->NewNode(machine()->Float64Sqrt(), value));
167 }
168 
Word32And(Node * lhs,Node * rhs)169 Node* MachineOperatorReducer::Word32And(Node* lhs, Node* rhs) {
170   Node* const node = graph()->NewNode(machine()->Word32And(), lhs, rhs);
171   Reduction const reduction = ReduceWord32And(node);
172   return reduction.Changed() ? reduction.replacement() : node;
173 }
174 
Word32Sar(Node * lhs,uint32_t rhs)175 Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) {
176   if (rhs == 0) return lhs;
177   return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs));
178 }
179 
Word32Shr(Node * lhs,uint32_t rhs)180 Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
181   if (rhs == 0) return lhs;
182   return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs));
183 }
184 
Word32Equal(Node * lhs,Node * rhs)185 Node* MachineOperatorReducer::Word32Equal(Node* lhs, Node* rhs) {
186   return graph()->NewNode(machine()->Word32Equal(), lhs, rhs);
187 }
188 
Word64And(Node * lhs,Node * rhs)189 Node* MachineOperatorReducer::Word64And(Node* lhs, Node* rhs) {
190   Node* const node = graph()->NewNode(machine()->Word64And(), lhs, rhs);
191   Reduction const reduction = ReduceWord64And(node);
192   return reduction.Changed() ? reduction.replacement() : node;
193 }
194 
Int32Add(Node * lhs,Node * rhs)195 Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
196   Node* const node = graph()->NewNode(machine()->Int32Add(), lhs, rhs);
197   Reduction const reduction = ReduceInt32Add(node);
198   return reduction.Changed() ? reduction.replacement() : node;
199 }
200 
Int32Sub(Node * lhs,Node * rhs)201 Node* MachineOperatorReducer::Int32Sub(Node* lhs, Node* rhs) {
202   Node* const node = graph()->NewNode(machine()->Int32Sub(), lhs, rhs);
203   Reduction const reduction = ReduceInt32Sub(node);
204   return reduction.Changed() ? reduction.replacement() : node;
205 }
206 
Int32Mul(Node * lhs,Node * rhs)207 Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) {
208   return graph()->NewNode(machine()->Int32Mul(), lhs, rhs);
209 }
210 
Int32Div(Node * dividend,int32_t divisor)211 Node* MachineOperatorReducer::Int32Div(Node* dividend, int32_t divisor) {
212   DCHECK_NE(0, divisor);
213   DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
214   base::MagicNumbersForDivision<uint32_t> const mag =
215       base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
216   Node* quotient = graph()->NewNode(machine()->Int32MulHigh(), dividend,
217                                     Uint32Constant(mag.multiplier));
218   if (divisor > 0 && bit_cast<int32_t>(mag.multiplier) < 0) {
219     quotient = Int32Add(quotient, dividend);
220   } else if (divisor < 0 && bit_cast<int32_t>(mag.multiplier) > 0) {
221     quotient = Int32Sub(quotient, dividend);
222   }
223   return Int32Add(Word32Sar(quotient, mag.shift), Word32Shr(dividend, 31));
224 }
225 
Uint32Div(Node * dividend,uint32_t divisor)226 Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
227   DCHECK_LT(0u, divisor);
228   // If the divisor is even, we can avoid using the expensive fixup by shifting
229   // the dividend upfront.
230   unsigned const shift = base::bits::CountTrailingZeros(divisor);
231   dividend = Word32Shr(dividend, shift);
232   divisor >>= shift;
233   // Compute the magic number for the (shifted) divisor.
234   base::MagicNumbersForDivision<uint32_t> const mag =
235       base::UnsignedDivisionByConstant(divisor, shift);
236   Node* quotient = graph()->NewNode(machine()->Uint32MulHigh(), dividend,
237                                     Uint32Constant(mag.multiplier));
238   if (mag.add) {
239     DCHECK_LE(1u, mag.shift);
240     quotient = Word32Shr(
241         Int32Add(Word32Shr(Int32Sub(dividend, quotient), 1), quotient),
242         mag.shift - 1);
243   } else {
244     quotient = Word32Shr(quotient, mag.shift);
245   }
246   return quotient;
247 }
248 
249 // Perform constant folding and strength reduction on machine operators.
Reduce(Node * node)250 Reduction MachineOperatorReducer::Reduce(Node* node) {
251   switch (node->opcode()) {
252     case IrOpcode::kProjection:
253       return ReduceProjection(ProjectionIndexOf(node->op()), node->InputAt(0));
254     case IrOpcode::kWord32And:
255       return ReduceWord32And(node);
256     case IrOpcode::kWord64And:
257       return ReduceWord64And(node);
258     case IrOpcode::kWord32Or:
259       return ReduceWord32Or(node);
260     case IrOpcode::kWord64Or:
261       return ReduceWord64Or(node);
262     case IrOpcode::kWord32Xor:
263       return ReduceWord32Xor(node);
264     case IrOpcode::kWord64Xor:
265       return ReduceWord64Xor(node);
266     case IrOpcode::kWord32Shl:
267       return ReduceWord32Shl(node);
268     case IrOpcode::kWord64Shl:
269       return ReduceWord64Shl(node);
270     case IrOpcode::kWord32Shr:
271       return ReduceWord32Shr(node);
272     case IrOpcode::kWord64Shr:
273       return ReduceWord64Shr(node);
274     case IrOpcode::kWord32Sar:
275       return ReduceWord32Sar(node);
276     case IrOpcode::kWord64Sar:
277       return ReduceWord64Sar(node);
278     case IrOpcode::kWord32Ror: {
279       Int32BinopMatcher m(node);
280       if (m.right().Is(0)) return Replace(m.left().node());  // x ror 0 => x
281       if (m.IsFoldable()) {                                  // K ror K => K
282         return ReplaceInt32(base::bits::RotateRight32(m.left().Value(),
283                                                       m.right().Value() & 31));
284       }
285       break;
286     }
287     case IrOpcode::kWord32Equal: {
288       Int32BinopMatcher m(node);
289       if (m.IsFoldable()) {  // K == K => K
290         return ReplaceBool(m.left().Value() == m.right().Value());
291       }
292       if (m.left().IsInt32Sub() && m.right().Is(0)) {  // x - y == 0 => x == y
293         Int32BinopMatcher msub(m.left().node());
294         node->ReplaceInput(0, msub.left().node());
295         node->ReplaceInput(1, msub.right().node());
296         return Changed(node);
297       }
298       // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
299       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x == x => true
300       if (m.left().IsWord32And() && m.right().HasValue()) {
301         Uint32BinopMatcher mand(m.left().node());
302         if ((mand.left().IsWord32Shr() || mand.left().IsWord32Sar()) &&
303             mand.right().HasValue()) {
304           Uint32BinopMatcher mshift(mand.left().node());
305           // ((x >> K1) & K2) == K3 => (x & (K2 << K1)) == (K3 << K1)
306           if (mshift.right().HasValue()) {
307             auto shift_bits = mshift.right().Value();
308             auto mask = mand.right().Value();
309             auto rhs = static_cast<uint32_t>(m.right().Value());
310             // Make sure that we won't shift data off the end.
311             if (shift_bits <= base::bits::CountLeadingZeros(mask) &&
312                 shift_bits <= base::bits::CountLeadingZeros(rhs)) {
313               node->ReplaceInput(
314                   0, Word32And(mshift.left().node(), mask << shift_bits));
315               node->ReplaceInput(1, Int32Constant(rhs << shift_bits));
316               return Changed(node);
317             }
318           }
319         }
320       }
321       break;
322     }
323     case IrOpcode::kWord64Equal: {
324       Int64BinopMatcher m(node);
325       if (m.IsFoldable()) {  // K == K => K
326         return ReplaceBool(m.left().Value() == m.right().Value());
327       }
328       if (m.left().IsInt64Sub() && m.right().Is(0)) {  // x - y == 0 => x == y
329         Int64BinopMatcher msub(m.left().node());
330         node->ReplaceInput(0, msub.left().node());
331         node->ReplaceInput(1, msub.right().node());
332         return Changed(node);
333       }
334       // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
335       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x == x => true
336       break;
337     }
338     case IrOpcode::kInt32Add:
339       return ReduceInt32Add(node);
340     case IrOpcode::kInt64Add:
341       return ReduceInt64Add(node);
342     case IrOpcode::kInt32Sub:
343       return ReduceInt32Sub(node);
344     case IrOpcode::kInt64Sub:
345       return ReduceInt64Sub(node);
346     case IrOpcode::kInt32Mul: {
347       Int32BinopMatcher m(node);
348       if (m.right().Is(0)) return Replace(m.right().node());  // x * 0 => 0
349       if (m.right().Is(1)) return Replace(m.left().node());   // x * 1 => x
350       if (m.IsFoldable()) {                                   // K * K => K
351         return ReplaceInt32(
352             base::MulWithWraparound(m.left().Value(), m.right().Value()));
353       }
354       if (m.right().Is(-1)) {  // x * -1 => 0 - x
355         node->ReplaceInput(0, Int32Constant(0));
356         node->ReplaceInput(1, m.left().node());
357         NodeProperties::ChangeOp(node, machine()->Int32Sub());
358         return Changed(node);
359       }
360       if (m.right().IsPowerOf2()) {  // x * 2^n => x << n
361         node->ReplaceInput(
362             1, Int32Constant(base::bits::WhichPowerOfTwo(m.right().Value())));
363         NodeProperties::ChangeOp(node, machine()->Word32Shl());
364         Reduction reduction = ReduceWord32Shl(node);
365         return reduction.Changed() ? reduction : Changed(node);
366       }
367       break;
368     }
369     case IrOpcode::kInt32MulWithOverflow: {
370       Int32BinopMatcher m(node);
371       if (m.right().Is(2)) {
372         node->ReplaceInput(1, m.left().node());
373         NodeProperties::ChangeOp(node, machine()->Int32AddWithOverflow());
374         return Changed(node);
375       }
376       if (m.right().Is(-1)) {
377         node->ReplaceInput(0, Int32Constant(0));
378         node->ReplaceInput(1, m.left().node());
379         NodeProperties::ChangeOp(node, machine()->Int32SubWithOverflow());
380         return Changed(node);
381       }
382       break;
383     }
384     case IrOpcode::kInt64Mul:
385       return ReduceInt64Mul(node);
386     case IrOpcode::kInt32Div:
387       return ReduceInt32Div(node);
388     case IrOpcode::kUint32Div:
389       return ReduceUint32Div(node);
390     case IrOpcode::kInt32Mod:
391       return ReduceInt32Mod(node);
392     case IrOpcode::kUint32Mod:
393       return ReduceUint32Mod(node);
394     case IrOpcode::kInt32LessThan: {
395       Int32BinopMatcher m(node);
396       if (m.IsFoldable()) {  // K < K => K
397         return ReplaceBool(m.left().Value() < m.right().Value());
398       }
399       if (m.LeftEqualsRight()) return ReplaceBool(false);  // x < x => false
400       if (m.left().IsWord32Or() && m.right().Is(0)) {
401         // (x | K) < 0 => true or (K | x) < 0 => true iff K < 0
402         Int32BinopMatcher mleftmatcher(m.left().node());
403         if (mleftmatcher.left().IsNegative() ||
404             mleftmatcher.right().IsNegative()) {
405           return ReplaceBool(true);
406         }
407       }
408       break;
409     }
410     case IrOpcode::kInt32LessThanOrEqual: {
411       Int32BinopMatcher m(node);
412       if (m.IsFoldable()) {  // K <= K => K
413         return ReplaceBool(m.left().Value() <= m.right().Value());
414       }
415       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x <= x => true
416       break;
417     }
418     case IrOpcode::kUint32LessThan: {
419       Uint32BinopMatcher m(node);
420       if (m.left().Is(kMaxUInt32)) return ReplaceBool(false);  // M < x => false
421       if (m.right().Is(0)) return ReplaceBool(false);          // x < 0 => false
422       if (m.IsFoldable()) {                                    // K < K => K
423         return ReplaceBool(m.left().Value() < m.right().Value());
424       }
425       if (m.LeftEqualsRight()) return ReplaceBool(false);  // x < x => false
426       if (m.left().IsWord32Sar() && m.right().HasValue()) {
427         Int32BinopMatcher mleft(m.left().node());
428         if (mleft.right().HasValue()) {
429           // (x >> K) < C => x < (C << K)
430           // when C < (M >> K)
431           const uint32_t c = m.right().Value();
432           const uint32_t k = mleft.right().Value() & 0x1F;
433           if (c < static_cast<uint32_t>(kMaxInt >> k)) {
434             node->ReplaceInput(0, mleft.left().node());
435             node->ReplaceInput(1, Uint32Constant(c << k));
436             return Changed(node);
437           }
438           // TODO(turbofan): else the comparison is always true.
439         }
440       }
441       break;
442     }
443     case IrOpcode::kUint32LessThanOrEqual: {
444       Uint32BinopMatcher m(node);
445       if (m.left().Is(0)) return ReplaceBool(true);            // 0 <= x => true
446       if (m.right().Is(kMaxUInt32)) return ReplaceBool(true);  // x <= M => true
447       if (m.IsFoldable()) {                                    // K <= K => K
448         return ReplaceBool(m.left().Value() <= m.right().Value());
449       }
450       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x <= x => true
451       break;
452     }
453     case IrOpcode::kFloat32Sub: {
454       Float32BinopMatcher m(node);
455       if (allow_signalling_nan_ && m.right().Is(0) &&
456           (std::copysign(1.0, m.right().Value()) > 0)) {
457         return Replace(m.left().node());  // x - 0 => x
458       }
459       if (m.right().IsNaN()) {  // x - NaN => NaN
460         // Do some calculation to make a signalling NaN quiet.
461         return ReplaceFloat32(m.right().Value() - m.right().Value());
462       }
463       if (m.left().IsNaN()) {  // NaN - x => NaN
464         // Do some calculation to make a signalling NaN quiet.
465         return ReplaceFloat32(m.left().Value() - m.left().Value());
466       }
467       if (m.IsFoldable()) {  // L - R => (L - R)
468         return ReplaceFloat32(m.left().Value() - m.right().Value());
469       }
470       if (allow_signalling_nan_ && m.left().IsMinusZero()) {
471         // -0.0 - round_down(-0.0 - R) => round_up(R)
472         if (machine()->Float32RoundUp().IsSupported() &&
473             m.right().IsFloat32RoundDown()) {
474           if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat32Sub) {
475             Float32BinopMatcher mright0(m.right().InputAt(0));
476             if (mright0.left().IsMinusZero()) {
477               return Replace(graph()->NewNode(machine()->Float32RoundUp().op(),
478                                               mright0.right().node()));
479             }
480           }
481         }
482         // -0.0 - R => -R
483         node->RemoveInput(0);
484         NodeProperties::ChangeOp(node, machine()->Float32Neg());
485         return Changed(node);
486       }
487       break;
488     }
489     case IrOpcode::kFloat64Add: {
490       Float64BinopMatcher m(node);
491       if (m.IsFoldable()) {  // K + K => K
492         return ReplaceFloat64(m.left().Value() + m.right().Value());
493       }
494       break;
495     }
496     case IrOpcode::kFloat64Sub: {
497       Float64BinopMatcher m(node);
498       if (allow_signalling_nan_ && m.right().Is(0) &&
499           (Double(m.right().Value()).Sign() > 0)) {
500         return Replace(m.left().node());  // x - 0 => x
501       }
502       if (m.right().IsNaN()) {  // x - NaN => NaN
503         // Do some calculation to make a signalling NaN quiet.
504         return ReplaceFloat64(m.right().Value() - m.right().Value());
505       }
506       if (m.left().IsNaN()) {  // NaN - x => NaN
507         // Do some calculation to make a signalling NaN quiet.
508         return ReplaceFloat64(m.left().Value() - m.left().Value());
509       }
510       if (m.IsFoldable()) {  // L - R => (L - R)
511         return ReplaceFloat64(m.left().Value() - m.right().Value());
512       }
513       if (allow_signalling_nan_ && m.left().IsMinusZero()) {
514         // -0.0 - round_down(-0.0 - R) => round_up(R)
515         if (machine()->Float64RoundUp().IsSupported() &&
516             m.right().IsFloat64RoundDown()) {
517           if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub) {
518             Float64BinopMatcher mright0(m.right().InputAt(0));
519             if (mright0.left().IsMinusZero()) {
520               return Replace(graph()->NewNode(machine()->Float64RoundUp().op(),
521                                               mright0.right().node()));
522             }
523           }
524         }
525         // -0.0 - R => -R
526         node->RemoveInput(0);
527         NodeProperties::ChangeOp(node, machine()->Float64Neg());
528         return Changed(node);
529       }
530       break;
531     }
532     case IrOpcode::kFloat64Mul: {
533       Float64BinopMatcher m(node);
534       if (allow_signalling_nan_ && m.right().Is(1))
535         return Replace(m.left().node());  // x * 1.0 => x
536       if (m.right().Is(-1)) {  // x * -1.0 => -0.0 - x
537         node->ReplaceInput(0, Float64Constant(-0.0));
538         node->ReplaceInput(1, m.left().node());
539         NodeProperties::ChangeOp(node, machine()->Float64Sub());
540         return Changed(node);
541       }
542       if (m.right().IsNaN()) {                               // x * NaN => NaN
543         // Do some calculation to make a signalling NaN quiet.
544         return ReplaceFloat64(m.right().Value() - m.right().Value());
545       }
546       if (m.IsFoldable()) {  // K * K => K
547         return ReplaceFloat64(m.left().Value() * m.right().Value());
548       }
549       if (m.right().Is(2)) {  // x * 2.0 => x + x
550         node->ReplaceInput(1, m.left().node());
551         NodeProperties::ChangeOp(node, machine()->Float64Add());
552         return Changed(node);
553       }
554       break;
555     }
556     case IrOpcode::kFloat64Div: {
557       Float64BinopMatcher m(node);
558       if (allow_signalling_nan_ && m.right().Is(1))
559         return Replace(m.left().node());  // x / 1.0 => x
560       // TODO(ahaas): We could do x / 1.0 = x if we knew that x is not an sNaN.
561       if (m.right().IsNaN()) {                               // x / NaN => NaN
562         // Do some calculation to make a signalling NaN quiet.
563         return ReplaceFloat64(m.right().Value() - m.right().Value());
564       }
565       if (m.left().IsNaN()) {  // NaN / x => NaN
566         // Do some calculation to make a signalling NaN quiet.
567         return ReplaceFloat64(m.left().Value() - m.left().Value());
568       }
569       if (m.IsFoldable()) {  // K / K => K
570         return ReplaceFloat64(
571             base::Divide(m.left().Value(), m.right().Value()));
572       }
573       if (allow_signalling_nan_ && m.right().Is(-1)) {  // x / -1.0 => -x
574         node->RemoveInput(1);
575         NodeProperties::ChangeOp(node, machine()->Float64Neg());
576         return Changed(node);
577       }
578       if (m.right().IsNormal() && m.right().IsPositiveOrNegativePowerOf2()) {
579         // All reciprocals of non-denormal powers of two can be represented
580         // exactly, so division by power of two can be reduced to
581         // multiplication by reciprocal, with the same result.
582         node->ReplaceInput(1, Float64Constant(1.0 / m.right().Value()));
583         NodeProperties::ChangeOp(node, machine()->Float64Mul());
584         return Changed(node);
585       }
586       break;
587     }
588     case IrOpcode::kFloat64Mod: {
589       Float64BinopMatcher m(node);
590       if (m.right().Is(0)) {  // x % 0 => NaN
591         return ReplaceFloat64(std::numeric_limits<double>::quiet_NaN());
592       }
593       if (m.right().IsNaN()) {  // x % NaN => NaN
594         return Replace(m.right().node());
595       }
596       if (m.left().IsNaN()) {  // NaN % x => NaN
597         return Replace(m.left().node());
598       }
599       if (m.IsFoldable()) {  // K % K => K
600         return ReplaceFloat64(Modulo(m.left().Value(), m.right().Value()));
601       }
602       break;
603     }
604     case IrOpcode::kFloat64Acos: {
605       Float64Matcher m(node->InputAt(0));
606       if (m.HasValue()) return ReplaceFloat64(base::ieee754::acos(m.Value()));
607       break;
608     }
609     case IrOpcode::kFloat64Acosh: {
610       Float64Matcher m(node->InputAt(0));
611       if (m.HasValue()) return ReplaceFloat64(base::ieee754::acosh(m.Value()));
612       break;
613     }
614     case IrOpcode::kFloat64Asin: {
615       Float64Matcher m(node->InputAt(0));
616       if (m.HasValue()) return ReplaceFloat64(base::ieee754::asin(m.Value()));
617       break;
618     }
619     case IrOpcode::kFloat64Asinh: {
620       Float64Matcher m(node->InputAt(0));
621       if (m.HasValue()) return ReplaceFloat64(base::ieee754::asinh(m.Value()));
622       break;
623     }
624     case IrOpcode::kFloat64Atan: {
625       Float64Matcher m(node->InputAt(0));
626       if (m.HasValue()) return ReplaceFloat64(base::ieee754::atan(m.Value()));
627       break;
628     }
629     case IrOpcode::kFloat64Atanh: {
630       Float64Matcher m(node->InputAt(0));
631       if (m.HasValue()) return ReplaceFloat64(base::ieee754::atanh(m.Value()));
632       break;
633     }
634     case IrOpcode::kFloat64Atan2: {
635       Float64BinopMatcher m(node);
636       if (m.right().IsNaN()) {
637         return Replace(m.right().node());
638       }
639       if (m.left().IsNaN()) {
640         return Replace(m.left().node());
641       }
642       if (m.IsFoldable()) {
643         return ReplaceFloat64(
644             base::ieee754::atan2(m.left().Value(), m.right().Value()));
645       }
646       break;
647     }
648     case IrOpcode::kFloat64Cbrt: {
649       Float64Matcher m(node->InputAt(0));
650       if (m.HasValue()) return ReplaceFloat64(base::ieee754::cbrt(m.Value()));
651       break;
652     }
653     case IrOpcode::kFloat64Cos: {
654       Float64Matcher m(node->InputAt(0));
655       if (m.HasValue()) return ReplaceFloat64(base::ieee754::cos(m.Value()));
656       break;
657     }
658     case IrOpcode::kFloat64Cosh: {
659       Float64Matcher m(node->InputAt(0));
660       if (m.HasValue()) return ReplaceFloat64(base::ieee754::cosh(m.Value()));
661       break;
662     }
663     case IrOpcode::kFloat64Exp: {
664       Float64Matcher m(node->InputAt(0));
665       if (m.HasValue()) return ReplaceFloat64(base::ieee754::exp(m.Value()));
666       break;
667     }
668     case IrOpcode::kFloat64Expm1: {
669       Float64Matcher m(node->InputAt(0));
670       if (m.HasValue()) return ReplaceFloat64(base::ieee754::expm1(m.Value()));
671       break;
672     }
673     case IrOpcode::kFloat64Log: {
674       Float64Matcher m(node->InputAt(0));
675       if (m.HasValue()) return ReplaceFloat64(base::ieee754::log(m.Value()));
676       break;
677     }
678     case IrOpcode::kFloat64Log1p: {
679       Float64Matcher m(node->InputAt(0));
680       if (m.HasValue()) return ReplaceFloat64(base::ieee754::log1p(m.Value()));
681       break;
682     }
683     case IrOpcode::kFloat64Log10: {
684       Float64Matcher m(node->InputAt(0));
685       if (m.HasValue()) return ReplaceFloat64(base::ieee754::log10(m.Value()));
686       break;
687     }
688     case IrOpcode::kFloat64Log2: {
689       Float64Matcher m(node->InputAt(0));
690       if (m.HasValue()) return ReplaceFloat64(base::ieee754::log2(m.Value()));
691       break;
692     }
693     case IrOpcode::kFloat64Pow: {
694       Float64BinopMatcher m(node);
695       if (m.IsFoldable()) {
696         return ReplaceFloat64(
697             base::ieee754::pow(m.left().Value(), m.right().Value()));
698       } else if (m.right().Is(0.0)) {  // x ** +-0.0 => 1.0
699         return ReplaceFloat64(1.0);
700       } else if (m.right().Is(-2.0)) {  // x ** -2.0 => 1 / (x * x)
701         node->ReplaceInput(0, Float64Constant(1.0));
702         node->ReplaceInput(1, Float64Mul(m.left().node(), m.left().node()));
703         NodeProperties::ChangeOp(node, machine()->Float64Div());
704         return Changed(node);
705       } else if (m.right().Is(2.0)) {  // x ** 2.0 => x * x
706         node->ReplaceInput(1, m.left().node());
707         NodeProperties::ChangeOp(node, machine()->Float64Mul());
708         return Changed(node);
709       } else if (m.right().Is(-0.5)) {
710         // x ** 0.5 => 1 / (if x <= -Infinity then Infinity else sqrt(0.0 + x))
711         node->ReplaceInput(0, Float64Constant(1.0));
712         node->ReplaceInput(1, Float64PowHalf(m.left().node()));
713         NodeProperties::ChangeOp(node, machine()->Float64Div());
714         return Changed(node);
715       } else if (m.right().Is(0.5)) {
716         // x ** 0.5 => if x <= -Infinity then Infinity else sqrt(0.0 + x)
717         return Replace(Float64PowHalf(m.left().node()));
718       }
719       break;
720     }
721     case IrOpcode::kFloat64Sin: {
722       Float64Matcher m(node->InputAt(0));
723       if (m.HasValue()) return ReplaceFloat64(base::ieee754::sin(m.Value()));
724       break;
725     }
726     case IrOpcode::kFloat64Sinh: {
727       Float64Matcher m(node->InputAt(0));
728       if (m.HasValue()) return ReplaceFloat64(base::ieee754::sinh(m.Value()));
729       break;
730     }
731     case IrOpcode::kFloat64Tan: {
732       Float64Matcher m(node->InputAt(0));
733       if (m.HasValue()) return ReplaceFloat64(base::ieee754::tan(m.Value()));
734       break;
735     }
736     case IrOpcode::kFloat64Tanh: {
737       Float64Matcher m(node->InputAt(0));
738       if (m.HasValue()) return ReplaceFloat64(base::ieee754::tanh(m.Value()));
739       break;
740     }
741     case IrOpcode::kChangeFloat32ToFloat64: {
742       Float32Matcher m(node->InputAt(0));
743       if (m.HasValue()) {
744         if (!allow_signalling_nan_ && std::isnan(m.Value())) {
745           // Do some calculation to make guarantee the value is a quiet NaN.
746           return ReplaceFloat64(m.Value() + m.Value());
747         }
748         return ReplaceFloat64(m.Value());
749       }
750       break;
751     }
752     case IrOpcode::kChangeFloat64ToInt32: {
753       Float64Matcher m(node->InputAt(0));
754       if (m.HasValue()) return ReplaceInt32(FastD2IChecked(m.Value()));
755       if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
756       break;
757     }
758     case IrOpcode::kChangeFloat64ToInt64: {
759       Float64Matcher m(node->InputAt(0));
760       if (m.HasValue()) return ReplaceInt64(static_cast<int64_t>(m.Value()));
761       if (m.IsChangeInt64ToFloat64()) return Replace(m.node()->InputAt(0));
762       break;
763     }
764     case IrOpcode::kChangeFloat64ToUint32: {
765       Float64Matcher m(node->InputAt(0));
766       if (m.HasValue()) return ReplaceInt32(FastD2UI(m.Value()));
767       if (m.IsChangeUint32ToFloat64()) return Replace(m.node()->InputAt(0));
768       break;
769     }
770     case IrOpcode::kChangeInt32ToFloat64: {
771       Int32Matcher m(node->InputAt(0));
772       if (m.HasValue()) return ReplaceFloat64(FastI2D(m.Value()));
773       break;
774     }
775     case IrOpcode::kBitcastWord32ToWord64: {
776       Int32Matcher m(node->InputAt(0));
777       if (m.HasValue()) return ReplaceInt64(m.Value());
778       break;
779     }
780     case IrOpcode::kChangeInt32ToInt64: {
781       Int32Matcher m(node->InputAt(0));
782       if (m.HasValue()) return ReplaceInt64(m.Value());
783       break;
784     }
785     case IrOpcode::kChangeInt64ToFloat64: {
786       Int64Matcher m(node->InputAt(0));
787       if (m.HasValue()) return ReplaceFloat64(static_cast<double>(m.Value()));
788       if (m.IsChangeFloat64ToInt64()) return Replace(m.node()->InputAt(0));
789       break;
790     }
791     case IrOpcode::kChangeUint32ToFloat64: {
792       Uint32Matcher m(node->InputAt(0));
793       if (m.HasValue()) return ReplaceFloat64(FastUI2D(m.Value()));
794       break;
795     }
796     case IrOpcode::kChangeUint32ToUint64: {
797       Uint32Matcher m(node->InputAt(0));
798       if (m.HasValue()) return ReplaceInt64(static_cast<uint64_t>(m.Value()));
799       break;
800     }
801     case IrOpcode::kTruncateFloat64ToWord32: {
802       Float64Matcher m(node->InputAt(0));
803       if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value()));
804       if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
805       return NoChange();
806     }
807     case IrOpcode::kTruncateInt64ToInt32: {
808       Int64Matcher m(node->InputAt(0));
809       if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value()));
810       if (m.IsChangeInt32ToInt64()) return Replace(m.node()->InputAt(0));
811       break;
812     }
813     case IrOpcode::kTruncateFloat64ToFloat32: {
814       Float64Matcher m(node->InputAt(0));
815       if (m.HasValue()) {
816         if (!allow_signalling_nan_ && std::isnan(m.Value())) {
817           // Do some calculation to make guarantee the value is a quiet NaN.
818           return ReplaceFloat32(DoubleToFloat32(m.Value() + m.Value()));
819         }
820         return ReplaceFloat32(DoubleToFloat32(m.Value()));
821       }
822       if (allow_signalling_nan_ && m.IsChangeFloat32ToFloat64())
823         return Replace(m.node()->InputAt(0));
824       break;
825     }
826     case IrOpcode::kRoundFloat64ToInt32: {
827       Float64Matcher m(node->InputAt(0));
828       if (m.HasValue()) {
829         return ReplaceInt32(DoubleToInt32(m.Value()));
830       }
831       if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
832       break;
833     }
834     case IrOpcode::kFloat64InsertLowWord32:
835       return ReduceFloat64InsertLowWord32(node);
836     case IrOpcode::kFloat64InsertHighWord32:
837       return ReduceFloat64InsertHighWord32(node);
838     case IrOpcode::kStore:
839     case IrOpcode::kUnalignedStore:
840       return ReduceStore(node);
841     case IrOpcode::kFloat64Equal:
842     case IrOpcode::kFloat64LessThan:
843     case IrOpcode::kFloat64LessThanOrEqual:
844       return ReduceFloat64Compare(node);
845     case IrOpcode::kFloat64RoundDown:
846       return ReduceFloat64RoundDown(node);
847     case IrOpcode::kBitcastTaggedToWord:
848     case IrOpcode::kBitcastTaggedToWordForTagAndSmiBits: {
849       NodeMatcher m(node->InputAt(0));
850       if (m.IsBitcastWordToTaggedSigned()) {
851         RelaxEffectsAndControls(node);
852         return Replace(m.InputAt(0));
853       }
854       break;
855     }
856     case IrOpcode::kBranch:
857     case IrOpcode::kDeoptimizeIf:
858     case IrOpcode::kDeoptimizeUnless:
859     case IrOpcode::kTrapIf:
860     case IrOpcode::kTrapUnless:
861       return ReduceConditional(node);
862     default:
863       break;
864   }
865   return NoChange();
866 }
867 
ReduceInt32Add(Node * node)868 Reduction MachineOperatorReducer::ReduceInt32Add(Node* node) {
869   DCHECK_EQ(IrOpcode::kInt32Add, node->opcode());
870   Int32BinopMatcher m(node);
871   if (m.right().Is(0)) return Replace(m.left().node());  // x + 0 => x
872   if (m.IsFoldable()) {                                  // K + K => K
873     return ReplaceInt32(
874         base::AddWithWraparound(m.left().Value(), m.right().Value()));
875   }
876   if (m.left().IsInt32Sub()) {
877     Int32BinopMatcher mleft(m.left().node());
878     if (mleft.left().Is(0)) {  // (0 - x) + y => y - x
879       node->ReplaceInput(0, m.right().node());
880       node->ReplaceInput(1, mleft.right().node());
881       NodeProperties::ChangeOp(node, machine()->Int32Sub());
882       Reduction const reduction = ReduceInt32Sub(node);
883       return reduction.Changed() ? reduction : Changed(node);
884     }
885   }
886   if (m.right().IsInt32Sub()) {
887     Int32BinopMatcher mright(m.right().node());
888     if (mright.left().Is(0)) {  // y + (0 - x) => y - x
889       node->ReplaceInput(1, mright.right().node());
890       NodeProperties::ChangeOp(node, machine()->Int32Sub());
891       Reduction const reduction = ReduceInt32Sub(node);
892       return reduction.Changed() ? reduction : Changed(node);
893     }
894   }
895   // (x + Int32Constant(a)) + Int32Constant(b)) => x + Int32Constant(a + b)
896   if (m.right().HasValue() && m.left().IsInt32Add()) {
897     Int32BinopMatcher n(m.left().node());
898     if (n.right().HasValue() && m.OwnsInput(m.left().node())) {
899       node->ReplaceInput(1, Int32Constant(base::AddWithWraparound(
900                                 m.right().Value(), n.right().Value())));
901       node->ReplaceInput(0, n.left().node());
902       return Changed(node);
903     }
904   }
905 
906   return NoChange();
907 }
908 
ReduceInt64Add(Node * node)909 Reduction MachineOperatorReducer::ReduceInt64Add(Node* node) {
910   DCHECK_EQ(IrOpcode::kInt64Add, node->opcode());
911   Int64BinopMatcher m(node);
912   if (m.right().Is(0)) return Replace(m.left().node());  // x + 0 => 0
913   if (m.IsFoldable()) {
914     return ReplaceInt64(
915         base::AddWithWraparound(m.left().Value(), m.right().Value()));
916   }
917   // (x + Int64Constant(a)) + Int64Constant(b)) => x + Int64Constant(a + b)
918   if (m.right().HasValue() && m.left().IsInt64Add()) {
919     Int64BinopMatcher n(m.left().node());
920     if (n.right().HasValue() && m.OwnsInput(m.left().node())) {
921       node->ReplaceInput(1, Int64Constant(base::AddWithWraparound(
922                                 m.right().Value(), n.right().Value())));
923       node->ReplaceInput(0, n.left().node());
924       return Changed(node);
925     }
926   }
927   return NoChange();
928 }
929 
ReduceInt32Sub(Node * node)930 Reduction MachineOperatorReducer::ReduceInt32Sub(Node* node) {
931   DCHECK_EQ(IrOpcode::kInt32Sub, node->opcode());
932   Int32BinopMatcher m(node);
933   if (m.right().Is(0)) return Replace(m.left().node());  // x - 0 => x
934   if (m.IsFoldable()) {                                  // K - K => K
935     return ReplaceInt32(
936         base::SubWithWraparound(m.left().Value(), m.right().Value()));
937   }
938   if (m.LeftEqualsRight()) return ReplaceInt32(0);  // x - x => 0
939   if (m.right().HasValue()) {                       // x - K => x + -K
940     node->ReplaceInput(
941         1, Int32Constant(base::NegateWithWraparound(m.right().Value())));
942     NodeProperties::ChangeOp(node, machine()->Int32Add());
943     Reduction const reduction = ReduceInt32Add(node);
944     return reduction.Changed() ? reduction : Changed(node);
945   }
946   return NoChange();
947 }
948 
ReduceInt64Sub(Node * node)949 Reduction MachineOperatorReducer::ReduceInt64Sub(Node* node) {
950   DCHECK_EQ(IrOpcode::kInt64Sub, node->opcode());
951   Int64BinopMatcher m(node);
952   if (m.right().Is(0)) return Replace(m.left().node());  // x - 0 => x
953   if (m.IsFoldable()) {                                  // K - K => K
954     return ReplaceInt64(
955         base::SubWithWraparound(m.left().Value(), m.right().Value()));
956   }
957   if (m.LeftEqualsRight()) return Replace(Int64Constant(0));  // x - x => 0
958   if (m.right().HasValue()) {                                 // x - K => x + -K
959     node->ReplaceInput(
960         1, Int64Constant(base::NegateWithWraparound(m.right().Value())));
961     NodeProperties::ChangeOp(node, machine()->Int64Add());
962     Reduction const reduction = ReduceInt64Add(node);
963     return reduction.Changed() ? reduction : Changed(node);
964   }
965   return NoChange();
966 }
967 
ReduceInt64Mul(Node * node)968 Reduction MachineOperatorReducer::ReduceInt64Mul(Node* node) {
969   DCHECK_EQ(IrOpcode::kInt64Mul, node->opcode());
970   Int64BinopMatcher m(node);
971   if (m.right().Is(0)) return Replace(m.right().node());  // x * 0 => 0
972   if (m.right().Is(1)) return Replace(m.left().node());   // x * 1 => x
973   if (m.IsFoldable()) {                                   // K * K => K
974     return ReplaceInt64(
975         base::MulWithWraparound(m.left().Value(), m.right().Value()));
976   }
977   if (m.right().Is(-1)) {  // x * -1 => 0 - x
978     node->ReplaceInput(0, Int64Constant(0));
979     node->ReplaceInput(1, m.left().node());
980     NodeProperties::ChangeOp(node, machine()->Int64Sub());
981     return Changed(node);
982   }
983   if (m.right().IsPowerOf2()) {  // x * 2^n => x << n
984     node->ReplaceInput(
985         1, Int64Constant(base::bits::WhichPowerOfTwo(m.right().Value())));
986     NodeProperties::ChangeOp(node, machine()->Word64Shl());
987     Reduction reduction = ReduceWord64Shl(node);
988     return reduction.Changed() ? reduction : Changed(node);
989   }
990   return NoChange();
991 }
992 
ReduceInt32Div(Node * node)993 Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
994   Int32BinopMatcher m(node);
995   if (m.left().Is(0)) return Replace(m.left().node());    // 0 / x => 0
996   if (m.right().Is(0)) return Replace(m.right().node());  // x / 0 => 0
997   if (m.right().Is(1)) return Replace(m.left().node());   // x / 1 => x
998   if (m.IsFoldable()) {                                   // K / K => K
999     return ReplaceInt32(
1000         base::bits::SignedDiv32(m.left().Value(), m.right().Value()));
1001   }
1002   if (m.LeftEqualsRight()) {  // x / x => x != 0
1003     Node* const zero = Int32Constant(0);
1004     return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
1005   }
1006   if (m.right().Is(-1)) {  // x / -1 => 0 - x
1007     node->ReplaceInput(0, Int32Constant(0));
1008     node->ReplaceInput(1, m.left().node());
1009     node->TrimInputCount(2);
1010     NodeProperties::ChangeOp(node, machine()->Int32Sub());
1011     return Changed(node);
1012   }
1013   if (m.right().HasValue()) {
1014     int32_t const divisor = m.right().Value();
1015     Node* const dividend = m.left().node();
1016     Node* quotient = dividend;
1017     if (base::bits::IsPowerOfTwo(Abs(divisor))) {
1018       uint32_t const shift = base::bits::WhichPowerOfTwo(Abs(divisor));
1019       DCHECK_NE(0u, shift);
1020       if (shift > 1) {
1021         quotient = Word32Sar(quotient, 31);
1022       }
1023       quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend);
1024       quotient = Word32Sar(quotient, shift);
1025     } else {
1026       quotient = Int32Div(quotient, Abs(divisor));
1027     }
1028     if (divisor < 0) {
1029       node->ReplaceInput(0, Int32Constant(0));
1030       node->ReplaceInput(1, quotient);
1031       node->TrimInputCount(2);
1032       NodeProperties::ChangeOp(node, machine()->Int32Sub());
1033       return Changed(node);
1034     }
1035     return Replace(quotient);
1036   }
1037   return NoChange();
1038 }
1039 
ReduceUint32Div(Node * node)1040 Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
1041   Uint32BinopMatcher m(node);
1042   if (m.left().Is(0)) return Replace(m.left().node());    // 0 / x => 0
1043   if (m.right().Is(0)) return Replace(m.right().node());  // x / 0 => 0
1044   if (m.right().Is(1)) return Replace(m.left().node());   // x / 1 => x
1045   if (m.IsFoldable()) {                                   // K / K => K
1046     return ReplaceUint32(
1047         base::bits::UnsignedDiv32(m.left().Value(), m.right().Value()));
1048   }
1049   if (m.LeftEqualsRight()) {  // x / x => x != 0
1050     Node* const zero = Int32Constant(0);
1051     return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
1052   }
1053   if (m.right().HasValue()) {
1054     Node* const dividend = m.left().node();
1055     uint32_t const divisor = m.right().Value();
1056     if (base::bits::IsPowerOfTwo(divisor)) {  // x / 2^n => x >> n
1057       node->ReplaceInput(
1058           1, Uint32Constant(base::bits::WhichPowerOfTwo(m.right().Value())));
1059       node->TrimInputCount(2);
1060       NodeProperties::ChangeOp(node, machine()->Word32Shr());
1061       return Changed(node);
1062     } else {
1063       return Replace(Uint32Div(dividend, divisor));
1064     }
1065   }
1066   return NoChange();
1067 }
1068 
ReduceInt32Mod(Node * node)1069 Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
1070   Int32BinopMatcher m(node);
1071   if (m.left().Is(0)) return Replace(m.left().node());    // 0 % x  => 0
1072   if (m.right().Is(0)) return Replace(m.right().node());  // x % 0  => 0
1073   if (m.right().Is(1)) return ReplaceInt32(0);            // x % 1  => 0
1074   if (m.right().Is(-1)) return ReplaceInt32(0);           // x % -1 => 0
1075   if (m.LeftEqualsRight()) return ReplaceInt32(0);        // x % x  => 0
1076   if (m.IsFoldable()) {                                   // K % K => K
1077     return ReplaceInt32(
1078         base::bits::SignedMod32(m.left().Value(), m.right().Value()));
1079   }
1080   if (m.right().HasValue()) {
1081     Node* const dividend = m.left().node();
1082     uint32_t const divisor = Abs(m.right().Value());
1083     if (base::bits::IsPowerOfTwo(divisor)) {
1084       uint32_t const mask = divisor - 1;
1085       Node* const zero = Int32Constant(0);
1086       Diamond d(graph(), common(),
1087                 graph()->NewNode(machine()->Int32LessThan(), dividend, zero),
1088                 BranchHint::kFalse);
1089       return Replace(
1090           d.Phi(MachineRepresentation::kWord32,
1091                 Int32Sub(zero, Word32And(Int32Sub(zero, dividend), mask)),
1092                 Word32And(dividend, mask)));
1093     } else {
1094       Node* quotient = Int32Div(dividend, divisor);
1095       DCHECK_EQ(dividend, node->InputAt(0));
1096       node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
1097       node->TrimInputCount(2);
1098       NodeProperties::ChangeOp(node, machine()->Int32Sub());
1099     }
1100     return Changed(node);
1101   }
1102   return NoChange();
1103 }
1104 
ReduceUint32Mod(Node * node)1105 Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) {
1106   Uint32BinopMatcher m(node);
1107   if (m.left().Is(0)) return Replace(m.left().node());    // 0 % x => 0
1108   if (m.right().Is(0)) return Replace(m.right().node());  // x % 0 => 0
1109   if (m.right().Is(1)) return ReplaceUint32(0);           // x % 1 => 0
1110   if (m.LeftEqualsRight()) return ReplaceInt32(0);        // x % x  => 0
1111   if (m.IsFoldable()) {                                   // K % K => K
1112     return ReplaceUint32(
1113         base::bits::UnsignedMod32(m.left().Value(), m.right().Value()));
1114   }
1115   if (m.right().HasValue()) {
1116     Node* const dividend = m.left().node();
1117     uint32_t const divisor = m.right().Value();
1118     if (base::bits::IsPowerOfTwo(divisor)) {  // x % 2^n => x & 2^n-1
1119       node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1));
1120       node->TrimInputCount(2);
1121       NodeProperties::ChangeOp(node, machine()->Word32And());
1122     } else {
1123       Node* quotient = Uint32Div(dividend, divisor);
1124       DCHECK_EQ(dividend, node->InputAt(0));
1125       node->ReplaceInput(1, Int32Mul(quotient, Uint32Constant(divisor)));
1126       node->TrimInputCount(2);
1127       NodeProperties::ChangeOp(node, machine()->Int32Sub());
1128     }
1129     return Changed(node);
1130   }
1131   return NoChange();
1132 }
1133 
ReduceStore(Node * node)1134 Reduction MachineOperatorReducer::ReduceStore(Node* node) {
1135   NodeMatcher nm(node);
1136   MachineRepresentation rep;
1137   int value_input;
1138   if (nm.IsStore()) {
1139     rep = StoreRepresentationOf(node->op()).representation();
1140     value_input = 2;
1141   } else {
1142     DCHECK(nm.IsUnalignedStore());
1143     rep = UnalignedStoreRepresentationOf(node->op());
1144     value_input = 2;
1145   }
1146 
1147   Node* const value = node->InputAt(value_input);
1148 
1149   switch (value->opcode()) {
1150     case IrOpcode::kWord32And: {
1151       Uint32BinopMatcher m(value);
1152       if (m.right().HasValue() && ((rep == MachineRepresentation::kWord8 &&
1153                                     (m.right().Value() & 0xFF) == 0xFF) ||
1154                                    (rep == MachineRepresentation::kWord16 &&
1155                                     (m.right().Value() & 0xFFFF) == 0xFFFF))) {
1156         node->ReplaceInput(value_input, m.left().node());
1157         return Changed(node);
1158       }
1159       break;
1160     }
1161     case IrOpcode::kWord32Sar: {
1162       Int32BinopMatcher m(value);
1163       if (m.left().IsWord32Shl() && ((rep == MachineRepresentation::kWord8 &&
1164                                       m.right().IsInRange(1, 24)) ||
1165                                      (rep == MachineRepresentation::kWord16 &&
1166                                       m.right().IsInRange(1, 16)))) {
1167         Int32BinopMatcher mleft(m.left().node());
1168         if (mleft.right().Is(m.right().Value())) {
1169           node->ReplaceInput(value_input, mleft.left().node());
1170           return Changed(node);
1171         }
1172       }
1173       break;
1174     }
1175     default:
1176       break;
1177   }
1178   return NoChange();
1179 }
1180 
ReduceProjection(size_t index,Node * node)1181 Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) {
1182   switch (node->opcode()) {
1183     case IrOpcode::kInt32AddWithOverflow: {
1184       DCHECK(index == 0 || index == 1);
1185       Int32BinopMatcher m(node);
1186       if (m.IsFoldable()) {
1187         int32_t val;
1188         bool ovf = base::bits::SignedAddOverflow32(m.left().Value(),
1189                                                    m.right().Value(), &val);
1190         return ReplaceInt32(index == 0 ? val : ovf);
1191       }
1192       if (m.right().Is(0)) {
1193         return Replace(index == 0 ? m.left().node() : m.right().node());
1194       }
1195       break;
1196     }
1197     case IrOpcode::kInt32SubWithOverflow: {
1198       DCHECK(index == 0 || index == 1);
1199       Int32BinopMatcher m(node);
1200       if (m.IsFoldable()) {
1201         int32_t val;
1202         bool ovf = base::bits::SignedSubOverflow32(m.left().Value(),
1203                                                    m.right().Value(), &val);
1204         return ReplaceInt32(index == 0 ? val : ovf);
1205       }
1206       if (m.right().Is(0)) {
1207         return Replace(index == 0 ? m.left().node() : m.right().node());
1208       }
1209       break;
1210     }
1211     case IrOpcode::kInt32MulWithOverflow: {
1212       DCHECK(index == 0 || index == 1);
1213       Int32BinopMatcher m(node);
1214       if (m.IsFoldable()) {
1215         int32_t val;
1216         bool ovf = base::bits::SignedMulOverflow32(m.left().Value(),
1217                                                    m.right().Value(), &val);
1218         return ReplaceInt32(index == 0 ? val : ovf);
1219       }
1220       if (m.right().Is(0)) {
1221         return Replace(m.right().node());
1222       }
1223       if (m.right().Is(1)) {
1224         return index == 0 ? Replace(m.left().node()) : ReplaceInt32(0);
1225       }
1226       break;
1227     }
1228     default:
1229       break;
1230   }
1231   return NoChange();
1232 }
1233 
ReduceWord32Shifts(Node * node)1234 Reduction MachineOperatorReducer::ReduceWord32Shifts(Node* node) {
1235   DCHECK((node->opcode() == IrOpcode::kWord32Shl) ||
1236          (node->opcode() == IrOpcode::kWord32Shr) ||
1237          (node->opcode() == IrOpcode::kWord32Sar));
1238   if (machine()->Word32ShiftIsSafe()) {
1239     // Remove the explicit 'and' with 0x1F if the shift provided by the machine
1240     // instruction matches that required by JavaScript.
1241     Int32BinopMatcher m(node);
1242     if (m.right().IsWord32And()) {
1243       Int32BinopMatcher mright(m.right().node());
1244       if (mright.right().Is(0x1F)) {
1245         node->ReplaceInput(1, mright.left().node());
1246         return Changed(node);
1247       }
1248     }
1249   }
1250   return NoChange();
1251 }
1252 
ReduceWord32Shl(Node * node)1253 Reduction MachineOperatorReducer::ReduceWord32Shl(Node* node) {
1254   DCHECK_EQ(IrOpcode::kWord32Shl, node->opcode());
1255   Int32BinopMatcher m(node);
1256   if (m.right().Is(0)) return Replace(m.left().node());  // x << 0 => x
1257   if (m.IsFoldable()) {                                  // K << K => K
1258     return ReplaceInt32(
1259         base::ShlWithWraparound(m.left().Value(), m.right().Value()));
1260   }
1261   if (m.right().IsInRange(1, 31)) {
1262     // (x >>> K) << K => x & ~(2^K - 1)
1263     // (x >> K) << K => x & ~(2^K - 1)
1264     if (m.left().IsWord32Sar() || m.left().IsWord32Shr()) {
1265       Int32BinopMatcher mleft(m.left().node());
1266       if (mleft.right().Is(m.right().Value())) {
1267         node->ReplaceInput(0, mleft.left().node());
1268         node->ReplaceInput(1,
1269                            Uint32Constant(~((1U << m.right().Value()) - 1U)));
1270         NodeProperties::ChangeOp(node, machine()->Word32And());
1271         Reduction reduction = ReduceWord32And(node);
1272         return reduction.Changed() ? reduction : Changed(node);
1273       }
1274     }
1275   }
1276   return ReduceWord32Shifts(node);
1277 }
1278 
ReduceWord64Shl(Node * node)1279 Reduction MachineOperatorReducer::ReduceWord64Shl(Node* node) {
1280   DCHECK_EQ(IrOpcode::kWord64Shl, node->opcode());
1281   Int64BinopMatcher m(node);
1282   if (m.right().Is(0)) return Replace(m.left().node());  // x << 0 => x
1283   if (m.IsFoldable()) {                                  // K << K => K
1284     return ReplaceInt64(
1285         base::ShlWithWraparound(m.left().Value(), m.right().Value()));
1286   }
1287   return NoChange();
1288 }
1289 
ReduceWord32Shr(Node * node)1290 Reduction MachineOperatorReducer::ReduceWord32Shr(Node* node) {
1291   Uint32BinopMatcher m(node);
1292   if (m.right().Is(0)) return Replace(m.left().node());  // x >>> 0 => x
1293   if (m.IsFoldable()) {                                  // K >>> K => K
1294     return ReplaceInt32(m.left().Value() >> (m.right().Value() & 31));
1295   }
1296   if (m.left().IsWord32And() && m.right().HasValue()) {
1297     Uint32BinopMatcher mleft(m.left().node());
1298     if (mleft.right().HasValue()) {
1299       uint32_t shift = m.right().Value() & 31;
1300       uint32_t mask = mleft.right().Value();
1301       if ((mask >> shift) == 0) {
1302         // (m >>> s) == 0 implies ((x & m) >>> s) == 0
1303         return ReplaceInt32(0);
1304       }
1305     }
1306   }
1307   return ReduceWord32Shifts(node);
1308 }
1309 
ReduceWord64Shr(Node * node)1310 Reduction MachineOperatorReducer::ReduceWord64Shr(Node* node) {
1311   DCHECK_EQ(IrOpcode::kWord64Shr, node->opcode());
1312   Uint64BinopMatcher m(node);
1313   if (m.right().Is(0)) return Replace(m.left().node());  // x >>> 0 => x
1314   if (m.IsFoldable()) {                                  // K >> K => K
1315     return ReplaceInt64(m.left().Value() >> (m.right().Value() & 63));
1316   }
1317   return NoChange();
1318 }
1319 
ReduceWord32Sar(Node * node)1320 Reduction MachineOperatorReducer::ReduceWord32Sar(Node* node) {
1321   Int32BinopMatcher m(node);
1322   if (m.right().Is(0)) return Replace(m.left().node());  // x >> 0 => x
1323   if (m.IsFoldable()) {                                  // K >> K => K
1324     return ReplaceInt32(m.left().Value() >> (m.right().Value() & 31));
1325   }
1326   if (m.left().IsWord32Shl()) {
1327     Int32BinopMatcher mleft(m.left().node());
1328     if (mleft.left().IsComparison()) {
1329       if (m.right().Is(31) && mleft.right().Is(31)) {
1330         // Comparison << 31 >> 31 => 0 - Comparison
1331         node->ReplaceInput(0, Int32Constant(0));
1332         node->ReplaceInput(1, mleft.left().node());
1333         NodeProperties::ChangeOp(node, machine()->Int32Sub());
1334         Reduction const reduction = ReduceInt32Sub(node);
1335         return reduction.Changed() ? reduction : Changed(node);
1336       }
1337     } else if (mleft.left().IsLoad()) {
1338       LoadRepresentation const rep =
1339           LoadRepresentationOf(mleft.left().node()->op());
1340       if (m.right().Is(24) && mleft.right().Is(24) &&
1341           rep == MachineType::Int8()) {
1342         // Load[kMachInt8] << 24 >> 24 => Load[kMachInt8]
1343         return Replace(mleft.left().node());
1344       }
1345       if (m.right().Is(16) && mleft.right().Is(16) &&
1346           rep == MachineType::Int16()) {
1347         // Load[kMachInt16] << 16 >> 16 => Load[kMachInt8]
1348         return Replace(mleft.left().node());
1349       }
1350     }
1351   }
1352   return ReduceWord32Shifts(node);
1353 }
1354 
ReduceWord64Sar(Node * node)1355 Reduction MachineOperatorReducer::ReduceWord64Sar(Node* node) {
1356   Int64BinopMatcher m(node);
1357   if (m.right().Is(0)) return Replace(m.left().node());  // x >> 0 => x
1358   if (m.IsFoldable()) {
1359     return ReplaceInt64(m.left().Value() >> (m.right().Value() & 63));
1360   }
1361   return NoChange();
1362 }
1363 
1364 template <typename WordNAdapter>
ReduceWordNAnd(Node * node)1365 Reduction MachineOperatorReducer::ReduceWordNAnd(Node* node) {
1366   using A = WordNAdapter;
1367   A a(this);
1368 
1369   typename A::IntNBinopMatcher m(node);
1370   if (m.right().Is(0)) return Replace(m.right().node());  // x & 0  => 0
1371   if (m.right().Is(-1)) return Replace(m.left().node());  // x & -1 => x
1372   if (m.left().IsComparison() && m.right().Is(1)) {       // CMP & 1 => CMP
1373     return Replace(m.left().node());
1374   }
1375   if (m.IsFoldable()) {                                   // K & K  => K
1376     return a.ReplaceIntN(m.left().Value() & m.right().Value());
1377   }
1378   if (m.LeftEqualsRight()) return Replace(m.left().node());  // x & x => x
1379   if (A::IsWordNAnd(m.left()) && m.right().HasValue()) {
1380     typename A::IntNBinopMatcher mleft(m.left().node());
1381     if (mleft.right().HasValue()) {  // (x & K) & K => x & K
1382       node->ReplaceInput(0, mleft.left().node());
1383       node->ReplaceInput(
1384           1, a.IntNConstant(m.right().Value() & mleft.right().Value()));
1385       Reduction const reduction = a.ReduceWordNAnd(node);
1386       return reduction.Changed() ? reduction : Changed(node);
1387     }
1388   }
1389   if (m.right().IsNegativePowerOf2()) {
1390     typename A::intN_t const mask = m.right().Value();
1391     typename A::intN_t const neg_mask = base::NegateWithWraparound(mask);
1392     if (A::IsWordNShl(m.left())) {
1393       typename A::UintNBinopMatcher mleft(m.left().node());
1394       if (mleft.right().HasValue() &&
1395           (mleft.right().Value() & (A::WORD_SIZE - 1)) >=
1396               base::bits::CountTrailingZeros(mask)) {
1397         // (x << L) & (-1 << K) => x << L iff L >= K
1398         return Replace(mleft.node());
1399       }
1400     } else if (A::IsIntNAdd(m.left())) {
1401       typename A::IntNBinopMatcher mleft(m.left().node());
1402       if (mleft.right().HasValue() &&
1403           (mleft.right().Value() & mask) == mleft.right().Value()) {
1404         // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
1405         node->ReplaceInput(0,
1406                            a.WordNAnd(mleft.left().node(), m.right().node()));
1407         node->ReplaceInput(1, mleft.right().node());
1408         NodeProperties::ChangeOp(node, a.IntNAdd(machine()));
1409         Reduction const reduction = a.ReduceIntNAdd(node);
1410         return reduction.Changed() ? reduction : Changed(node);
1411       }
1412       if (A::IsIntNMul(mleft.left())) {
1413         typename A::IntNBinopMatcher mleftleft(mleft.left().node());
1414         if (mleftleft.right().IsMultipleOf(neg_mask)) {
1415           // (y * (K << L) + x) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
1416           node->ReplaceInput(
1417               0, a.WordNAnd(mleft.right().node(), m.right().node()));
1418           node->ReplaceInput(1, mleftleft.node());
1419           NodeProperties::ChangeOp(node, a.IntNAdd(machine()));
1420           Reduction const reduction = a.ReduceIntNAdd(node);
1421           return reduction.Changed() ? reduction : Changed(node);
1422         }
1423       }
1424       if (A::IsIntNMul(mleft.right())) {
1425         typename A::IntNBinopMatcher mleftright(mleft.right().node());
1426         if (mleftright.right().IsMultipleOf(neg_mask)) {
1427           // (x + y * (K << L)) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
1428           node->ReplaceInput(0,
1429                              a.WordNAnd(mleft.left().node(), m.right().node()));
1430           node->ReplaceInput(1, mleftright.node());
1431           NodeProperties::ChangeOp(node, a.IntNAdd(machine()));
1432           Reduction const reduction = a.ReduceIntNAdd(node);
1433           return reduction.Changed() ? reduction : Changed(node);
1434         }
1435       }
1436       if (A::IsWordNShl(mleft.left())) {
1437         typename A::IntNBinopMatcher mleftleft(mleft.left().node());
1438         if (mleftleft.right().Is(base::bits::CountTrailingZeros(mask))) {
1439           // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
1440           node->ReplaceInput(
1441               0, a.WordNAnd(mleft.right().node(), m.right().node()));
1442           node->ReplaceInput(1, mleftleft.node());
1443           NodeProperties::ChangeOp(node, a.IntNAdd(machine()));
1444           Reduction const reduction = a.ReduceIntNAdd(node);
1445           return reduction.Changed() ? reduction : Changed(node);
1446         }
1447       }
1448       if (A::IsWordNShl(mleft.right())) {
1449         typename A::IntNBinopMatcher mleftright(mleft.right().node());
1450         if (mleftright.right().Is(base::bits::CountTrailingZeros(mask))) {
1451           // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
1452           node->ReplaceInput(0,
1453                              a.WordNAnd(mleft.left().node(), m.right().node()));
1454           node->ReplaceInput(1, mleftright.node());
1455           NodeProperties::ChangeOp(node, a.IntNAdd(machine()));
1456           Reduction const reduction = a.ReduceIntNAdd(node);
1457           return reduction.Changed() ? reduction : Changed(node);
1458         }
1459       }
1460     } else if (A::IsIntNMul(m.left())) {
1461       typename A::IntNBinopMatcher mleft(m.left().node());
1462       if (mleft.right().IsMultipleOf(neg_mask)) {
1463         // (x * (K << L)) & (-1 << L) => x * (K << L)
1464         return Replace(mleft.node());
1465       }
1466     }
1467   }
1468   return NoChange();
1469 }
1470 
ReduceWord32And(Node * node)1471 Reduction MachineOperatorReducer::ReduceWord32And(Node* node) {
1472   DCHECK_EQ(IrOpcode::kWord32And, node->opcode());
1473   return ReduceWordNAnd<Word32Adapter>(node);
1474 }
1475 
ReduceWord64And(Node * node)1476 Reduction MachineOperatorReducer::ReduceWord64And(Node* node) {
1477   DCHECK_EQ(IrOpcode::kWord64And, node->opcode());
1478   return ReduceWordNAnd<Word64Adapter>(node);
1479 }
1480 
TryMatchWord32Ror(Node * node)1481 Reduction MachineOperatorReducer::TryMatchWord32Ror(Node* node) {
1482   DCHECK(IrOpcode::kWord32Or == node->opcode() ||
1483          IrOpcode::kWord32Xor == node->opcode());
1484   Int32BinopMatcher m(node);
1485   Node* shl = nullptr;
1486   Node* shr = nullptr;
1487   // Recognize rotation, we are matching:
1488   //  * x << y | x >>> (32 - y) => x ror (32 - y), i.e  x rol y
1489   //  * x << (32 - y) | x >>> y => x ror y
1490   //  * x << y ^ x >>> (32 - y) => x ror (32 - y), i.e. x rol y
1491   //  * x << (32 - y) ^ x >>> y => x ror y
1492   // as well as their commuted form.
1493   if (m.left().IsWord32Shl() && m.right().IsWord32Shr()) {
1494     shl = m.left().node();
1495     shr = m.right().node();
1496   } else if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) {
1497     shl = m.right().node();
1498     shr = m.left().node();
1499   } else {
1500     return NoChange();
1501   }
1502 
1503   Int32BinopMatcher mshl(shl);
1504   Int32BinopMatcher mshr(shr);
1505   if (mshl.left().node() != mshr.left().node()) return NoChange();
1506 
1507   if (mshl.right().HasValue() && mshr.right().HasValue()) {
1508     // Case where y is a constant.
1509     if (mshl.right().Value() + mshr.right().Value() != 32) return NoChange();
1510   } else {
1511     Node* sub = nullptr;
1512     Node* y = nullptr;
1513     if (mshl.right().IsInt32Sub()) {
1514       sub = mshl.right().node();
1515       y = mshr.right().node();
1516     } else if (mshr.right().IsInt32Sub()) {
1517       sub = mshr.right().node();
1518       y = mshl.right().node();
1519     } else {
1520       return NoChange();
1521     }
1522 
1523     Int32BinopMatcher msub(sub);
1524     if (!msub.left().Is(32) || msub.right().node() != y) return NoChange();
1525   }
1526 
1527   node->ReplaceInput(0, mshl.left().node());
1528   node->ReplaceInput(1, mshr.right().node());
1529   NodeProperties::ChangeOp(node, machine()->Word32Ror());
1530   return Changed(node);
1531 }
1532 
1533 template <typename WordNAdapter>
ReduceWordNOr(Node * node)1534 Reduction MachineOperatorReducer::ReduceWordNOr(Node* node) {
1535   using A = WordNAdapter;
1536   A a(this);
1537 
1538   typename A::IntNBinopMatcher m(node);
1539   if (m.right().Is(0)) return Replace(m.left().node());    // x | 0  => x
1540   if (m.right().Is(-1)) return Replace(m.right().node());  // x | -1 => -1
1541   if (m.IsFoldable()) {                                    // K | K  => K
1542     return a.ReplaceIntN(m.left().Value() | m.right().Value());
1543   }
1544   if (m.LeftEqualsRight()) return Replace(m.left().node());  // x | x => x
1545 
1546   return a.TryMatchWordNRor(node);
1547 }
1548 
ReduceWord32Or(Node * node)1549 Reduction MachineOperatorReducer::ReduceWord32Or(Node* node) {
1550   DCHECK_EQ(IrOpcode::kWord32Or, node->opcode());
1551   return ReduceWordNOr<Word32Adapter>(node);
1552 }
1553 
ReduceWord64Or(Node * node)1554 Reduction MachineOperatorReducer::ReduceWord64Or(Node* node) {
1555   DCHECK_EQ(IrOpcode::kWord64Or, node->opcode());
1556   return ReduceWordNOr<Word64Adapter>(node);
1557 }
1558 
1559 template <typename WordNAdapter>
ReduceWordNXor(Node * node)1560 Reduction MachineOperatorReducer::ReduceWordNXor(Node* node) {
1561   using A = WordNAdapter;
1562   A a(this);
1563 
1564   typename A::IntNBinopMatcher m(node);
1565   if (m.right().Is(0)) return Replace(m.left().node());  // x ^ 0 => x
1566   if (m.IsFoldable()) {                                  // K ^ K => K
1567     return a.ReplaceIntN(m.left().Value() ^ m.right().Value());
1568   }
1569   if (m.LeftEqualsRight()) return ReplaceInt32(0);  // x ^ x => 0
1570   if (A::IsWordNXor(m.left()) && m.right().Is(-1)) {
1571     typename A::IntNBinopMatcher mleft(m.left().node());
1572     if (mleft.right().Is(-1)) {  // (x ^ -1) ^ -1 => x
1573       return Replace(mleft.left().node());
1574     }
1575   }
1576 
1577   return a.TryMatchWordNRor(node);
1578 }
1579 
ReduceWord32Xor(Node * node)1580 Reduction MachineOperatorReducer::ReduceWord32Xor(Node* node) {
1581   DCHECK_EQ(IrOpcode::kWord32Xor, node->opcode());
1582   return ReduceWordNXor<Word32Adapter>(node);
1583 }
1584 
ReduceWord64Xor(Node * node)1585 Reduction MachineOperatorReducer::ReduceWord64Xor(Node* node) {
1586   DCHECK_EQ(IrOpcode::kWord64Xor, node->opcode());
1587   return ReduceWordNXor<Word64Adapter>(node);
1588 }
1589 
ReduceFloat64InsertLowWord32(Node * node)1590 Reduction MachineOperatorReducer::ReduceFloat64InsertLowWord32(Node* node) {
1591   DCHECK_EQ(IrOpcode::kFloat64InsertLowWord32, node->opcode());
1592   Float64Matcher mlhs(node->InputAt(0));
1593   Uint32Matcher mrhs(node->InputAt(1));
1594   if (mlhs.HasValue() && mrhs.HasValue()) {
1595     return ReplaceFloat64(bit_cast<double>(
1596         (bit_cast<uint64_t>(mlhs.Value()) & uint64_t{0xFFFFFFFF00000000}) |
1597         mrhs.Value()));
1598   }
1599   return NoChange();
1600 }
1601 
ReduceFloat64InsertHighWord32(Node * node)1602 Reduction MachineOperatorReducer::ReduceFloat64InsertHighWord32(Node* node) {
1603   DCHECK_EQ(IrOpcode::kFloat64InsertHighWord32, node->opcode());
1604   Float64Matcher mlhs(node->InputAt(0));
1605   Uint32Matcher mrhs(node->InputAt(1));
1606   if (mlhs.HasValue() && mrhs.HasValue()) {
1607     return ReplaceFloat64(bit_cast<double>(
1608         (bit_cast<uint64_t>(mlhs.Value()) & uint64_t{0xFFFFFFFF}) |
1609         (static_cast<uint64_t>(mrhs.Value()) << 32)));
1610   }
1611   return NoChange();
1612 }
1613 
1614 namespace {
1615 
IsFloat64RepresentableAsFloat32(const Float64Matcher & m)1616 bool IsFloat64RepresentableAsFloat32(const Float64Matcher& m) {
1617   if (m.HasValue()) {
1618     double v = m.Value();
1619     return DoubleToFloat32(v) == v;
1620   }
1621   return false;
1622 }
1623 
1624 }  // namespace
1625 
1626 
ReduceFloat64Compare(Node * node)1627 Reduction MachineOperatorReducer::ReduceFloat64Compare(Node* node) {
1628   DCHECK(IrOpcode::kFloat64Equal == node->opcode() ||
1629          IrOpcode::kFloat64LessThan == node->opcode() ||
1630          IrOpcode::kFloat64LessThanOrEqual == node->opcode());
1631   Float64BinopMatcher m(node);
1632   if (m.IsFoldable()) {
1633     switch (node->opcode()) {
1634       case IrOpcode::kFloat64Equal:
1635         return ReplaceBool(m.left().Value() == m.right().Value());
1636       case IrOpcode::kFloat64LessThan:
1637         return ReplaceBool(m.left().Value() < m.right().Value());
1638       case IrOpcode::kFloat64LessThanOrEqual:
1639         return ReplaceBool(m.left().Value() <= m.right().Value());
1640       default:
1641         UNREACHABLE();
1642     }
1643   } else if ((m.left().IsChangeFloat32ToFloat64() &&
1644               m.right().IsChangeFloat32ToFloat64()) ||
1645              (m.left().IsChangeFloat32ToFloat64() &&
1646               IsFloat64RepresentableAsFloat32(m.right())) ||
1647              (IsFloat64RepresentableAsFloat32(m.left()) &&
1648               m.right().IsChangeFloat32ToFloat64())) {
1649     // As all Float32 values have an exact representation in Float64, comparing
1650     // two Float64 values both converted from Float32 is equivalent to comparing
1651     // the original Float32s, so we can ignore the conversions. We can also
1652     // reduce comparisons of converted Float64 values against constants that
1653     // can be represented exactly as Float32.
1654     switch (node->opcode()) {
1655       case IrOpcode::kFloat64Equal:
1656         NodeProperties::ChangeOp(node, machine()->Float32Equal());
1657         break;
1658       case IrOpcode::kFloat64LessThan:
1659         NodeProperties::ChangeOp(node, machine()->Float32LessThan());
1660         break;
1661       case IrOpcode::kFloat64LessThanOrEqual:
1662         NodeProperties::ChangeOp(node, machine()->Float32LessThanOrEqual());
1663         break;
1664       default:
1665         UNREACHABLE();
1666     }
1667     node->ReplaceInput(
1668         0, m.left().HasValue()
1669                ? Float32Constant(static_cast<float>(m.left().Value()))
1670                : m.left().InputAt(0));
1671     node->ReplaceInput(
1672         1, m.right().HasValue()
1673                ? Float32Constant(static_cast<float>(m.right().Value()))
1674                : m.right().InputAt(0));
1675     return Changed(node);
1676   }
1677   return NoChange();
1678 }
1679 
ReduceFloat64RoundDown(Node * node)1680 Reduction MachineOperatorReducer::ReduceFloat64RoundDown(Node* node) {
1681   DCHECK_EQ(IrOpcode::kFloat64RoundDown, node->opcode());
1682   Float64Matcher m(node->InputAt(0));
1683   if (m.HasValue()) {
1684     return ReplaceFloat64(std::floor(m.Value()));
1685   }
1686   return NoChange();
1687 }
1688 
ReduceConditional(Node * node)1689 Reduction MachineOperatorReducer::ReduceConditional(Node* node) {
1690   DCHECK(node->opcode() == IrOpcode::kBranch ||
1691          node->opcode() == IrOpcode::kDeoptimizeIf ||
1692          node->opcode() == IrOpcode::kDeoptimizeUnless ||
1693          node->opcode() == IrOpcode::kTrapIf ||
1694          node->opcode() == IrOpcode::kTrapUnless);
1695   // This reducer only applies operator reductions to the branch condition.
1696   // Reductions involving control flow happen elsewhere. Non-zero inputs are
1697   // considered true in all conditional ops.
1698   NodeMatcher condition(NodeProperties::GetValueInput(node, 0));
1699   if (condition.IsWord32And()) {
1700     Uint32BinopMatcher mand(condition.node());
1701     if ((mand.left().IsWord32Shr() || mand.left().IsWord32Sar()) &&
1702         mand.right().HasValue()) {
1703       Uint32BinopMatcher mshift(mand.left().node());
1704       // Branch condition (x >> K1) & K2 => x & (K2 << K1)
1705       if (mshift.right().HasValue()) {
1706         auto shift_bits = mshift.right().Value();
1707         auto mask = mand.right().Value();
1708         // Make sure that we won't shift data off the end.
1709         if (shift_bits <= base::bits::CountLeadingZeros(mask)) {
1710           NodeProperties::ReplaceValueInput(
1711               node, Word32And(mshift.left().node(), mask << shift_bits), 0);
1712           return Changed(node);
1713         }
1714       }
1715     }
1716   }
1717   return NoChange();
1718 }
1719 
common() const1720 CommonOperatorBuilder* MachineOperatorReducer::common() const {
1721   return mcgraph()->common();
1722 }
1723 
machine() const1724 MachineOperatorBuilder* MachineOperatorReducer::machine() const {
1725   return mcgraph()->machine();
1726 }
1727 
graph() const1728 Graph* MachineOperatorReducer::graph() const { return mcgraph()->graph(); }
1729 
1730 }  // namespace compiler
1731 }  // namespace internal
1732 }  // namespace v8
1733