Home | History | Annotate | Download | only in compiler
      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/base/ieee754.h"
     10 #include "src/codegen.h"
     11 #include "src/compiler/diamond.h"
     12 #include "src/compiler/graph.h"
     13 #include "src/compiler/js-graph.h"
     14 #include "src/compiler/node-matchers.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 namespace compiler {
     19 
     20 MachineOperatorReducer::MachineOperatorReducer(JSGraph* jsgraph)
     21     : jsgraph_(jsgraph) {}
     22 
     23 
     24 MachineOperatorReducer::~MachineOperatorReducer() {}
     25 
     26 
     27 Node* MachineOperatorReducer::Float32Constant(volatile float value) {
     28   return graph()->NewNode(common()->Float32Constant(value));
     29 }
     30 
     31 
     32 Node* MachineOperatorReducer::Float64Constant(volatile double value) {
     33   return jsgraph()->Float64Constant(value);
     34 }
     35 
     36 
     37 Node* MachineOperatorReducer::Int32Constant(int32_t value) {
     38   return jsgraph()->Int32Constant(value);
     39 }
     40 
     41 
     42 Node* MachineOperatorReducer::Int64Constant(int64_t value) {
     43   return graph()->NewNode(common()->Int64Constant(value));
     44 }
     45 
     46 Node* MachineOperatorReducer::Float64Mul(Node* lhs, Node* rhs) {
     47   return graph()->NewNode(machine()->Float64Mul(), lhs, rhs);
     48 }
     49 
     50 Node* MachineOperatorReducer::Float64PowHalf(Node* value) {
     51   value =
     52       graph()->NewNode(machine()->Float64Add(), Float64Constant(0.0), value);
     53   return graph()->NewNode(
     54       common()->Select(MachineRepresentation::kFloat64, BranchHint::kFalse),
     55       graph()->NewNode(machine()->Float64LessThanOrEqual(), value,
     56                        Float64Constant(-V8_INFINITY)),
     57       Float64Constant(V8_INFINITY),
     58       graph()->NewNode(machine()->Float64Sqrt(), value));
     59 }
     60 
     61 Node* MachineOperatorReducer::Word32And(Node* lhs, Node* rhs) {
     62   Node* const node = graph()->NewNode(machine()->Word32And(), lhs, rhs);
     63   Reduction const reduction = ReduceWord32And(node);
     64   return reduction.Changed() ? reduction.replacement() : node;
     65 }
     66 
     67 
     68 Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) {
     69   if (rhs == 0) return lhs;
     70   return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs));
     71 }
     72 
     73 
     74 Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
     75   if (rhs == 0) return lhs;
     76   return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs));
     77 }
     78 
     79 
     80 Node* MachineOperatorReducer::Word32Equal(Node* lhs, Node* rhs) {
     81   return graph()->NewNode(machine()->Word32Equal(), lhs, rhs);
     82 }
     83 
     84 
     85 Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
     86   Node* const node = graph()->NewNode(machine()->Int32Add(), lhs, rhs);
     87   Reduction const reduction = ReduceInt32Add(node);
     88   return reduction.Changed() ? reduction.replacement() : node;
     89 }
     90 
     91 
     92 Node* MachineOperatorReducer::Int32Sub(Node* lhs, Node* rhs) {
     93   Node* const node = graph()->NewNode(machine()->Int32Sub(), lhs, rhs);
     94   Reduction const reduction = ReduceInt32Sub(node);
     95   return reduction.Changed() ? reduction.replacement() : node;
     96 }
     97 
     98 
     99 Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) {
    100   return graph()->NewNode(machine()->Int32Mul(), lhs, rhs);
    101 }
    102 
    103 
    104 Node* MachineOperatorReducer::Int32Div(Node* dividend, int32_t divisor) {
    105   DCHECK_NE(0, divisor);
    106   DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
    107   base::MagicNumbersForDivision<uint32_t> const mag =
    108       base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
    109   Node* quotient = graph()->NewNode(machine()->Int32MulHigh(), dividend,
    110                                     Uint32Constant(mag.multiplier));
    111   if (divisor > 0 && bit_cast<int32_t>(mag.multiplier) < 0) {
    112     quotient = Int32Add(quotient, dividend);
    113   } else if (divisor < 0 && bit_cast<int32_t>(mag.multiplier) > 0) {
    114     quotient = Int32Sub(quotient, dividend);
    115   }
    116   return Int32Add(Word32Sar(quotient, mag.shift), Word32Shr(dividend, 31));
    117 }
    118 
    119 
    120 Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
    121   DCHECK_LT(0u, divisor);
    122   // If the divisor is even, we can avoid using the expensive fixup by shifting
    123   // the dividend upfront.
    124   unsigned const shift = base::bits::CountTrailingZeros32(divisor);
    125   dividend = Word32Shr(dividend, shift);
    126   divisor >>= shift;
    127   // Compute the magic number for the (shifted) divisor.
    128   base::MagicNumbersForDivision<uint32_t> const mag =
    129       base::UnsignedDivisionByConstant(divisor, shift);
    130   Node* quotient = graph()->NewNode(machine()->Uint32MulHigh(), dividend,
    131                                     Uint32Constant(mag.multiplier));
    132   if (mag.add) {
    133     DCHECK_LE(1u, mag.shift);
    134     quotient = Word32Shr(
    135         Int32Add(Word32Shr(Int32Sub(dividend, quotient), 1), quotient),
    136         mag.shift - 1);
    137   } else {
    138     quotient = Word32Shr(quotient, mag.shift);
    139   }
    140   return quotient;
    141 }
    142 
    143 
    144 // Perform constant folding and strength reduction on machine operators.
    145 Reduction MachineOperatorReducer::Reduce(Node* node) {
    146   switch (node->opcode()) {
    147     case IrOpcode::kProjection:
    148       return ReduceProjection(ProjectionIndexOf(node->op()), node->InputAt(0));
    149     case IrOpcode::kWord32And:
    150       return ReduceWord32And(node);
    151     case IrOpcode::kWord32Or:
    152       return ReduceWord32Or(node);
    153     case IrOpcode::kWord32Xor:
    154       return ReduceWord32Xor(node);
    155     case IrOpcode::kWord32Shl:
    156       return ReduceWord32Shl(node);
    157     case IrOpcode::kWord64Shl:
    158       return ReduceWord64Shl(node);
    159     case IrOpcode::kWord32Shr:
    160       return ReduceWord32Shr(node);
    161     case IrOpcode::kWord64Shr:
    162       return ReduceWord64Shr(node);
    163     case IrOpcode::kWord32Sar:
    164       return ReduceWord32Sar(node);
    165     case IrOpcode::kWord64Sar:
    166       return ReduceWord64Sar(node);
    167     case IrOpcode::kWord32Ror: {
    168       Int32BinopMatcher m(node);
    169       if (m.right().Is(0)) return Replace(m.left().node());  // x ror 0 => x
    170       if (m.IsFoldable()) {                                  // K ror K => K
    171         return ReplaceInt32(
    172             base::bits::RotateRight32(m.left().Value(), m.right().Value()));
    173       }
    174       break;
    175     }
    176     case IrOpcode::kWord32Equal: {
    177       Int32BinopMatcher m(node);
    178       if (m.IsFoldable()) {  // K == K => K
    179         return ReplaceBool(m.left().Value() == m.right().Value());
    180       }
    181       if (m.left().IsInt32Sub() && m.right().Is(0)) {  // x - y == 0 => x == y
    182         Int32BinopMatcher msub(m.left().node());
    183         node->ReplaceInput(0, msub.left().node());
    184         node->ReplaceInput(1, msub.right().node());
    185         return Changed(node);
    186       }
    187       // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
    188       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x == x => true
    189       break;
    190     }
    191     case IrOpcode::kWord64Equal: {
    192       Int64BinopMatcher m(node);
    193       if (m.IsFoldable()) {  // K == K => K
    194         return ReplaceBool(m.left().Value() == m.right().Value());
    195       }
    196       if (m.left().IsInt64Sub() && m.right().Is(0)) {  // x - y == 0 => x == y
    197         Int64BinopMatcher msub(m.left().node());
    198         node->ReplaceInput(0, msub.left().node());
    199         node->ReplaceInput(1, msub.right().node());
    200         return Changed(node);
    201       }
    202       // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
    203       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x == x => true
    204       break;
    205     }
    206     case IrOpcode::kInt32Add:
    207       return ReduceInt32Add(node);
    208     case IrOpcode::kInt64Add:
    209       return ReduceInt64Add(node);
    210     case IrOpcode::kInt32Sub:
    211       return ReduceInt32Sub(node);
    212     case IrOpcode::kInt64Sub:
    213       return ReduceInt64Sub(node);
    214     case IrOpcode::kInt32Mul: {
    215       Int32BinopMatcher m(node);
    216       if (m.right().Is(0)) return Replace(m.right().node());  // x * 0 => 0
    217       if (m.right().Is(1)) return Replace(m.left().node());   // x * 1 => x
    218       if (m.IsFoldable()) {                                   // K * K => K
    219         return ReplaceInt32(m.left().Value() * m.right().Value());
    220       }
    221       if (m.right().Is(-1)) {  // x * -1 => 0 - x
    222         node->ReplaceInput(0, Int32Constant(0));
    223         node->ReplaceInput(1, m.left().node());
    224         NodeProperties::ChangeOp(node, machine()->Int32Sub());
    225         return Changed(node);
    226       }
    227       if (m.right().IsPowerOf2()) {  // x * 2^n => x << n
    228         node->ReplaceInput(1, Int32Constant(WhichPowerOf2(m.right().Value())));
    229         NodeProperties::ChangeOp(node, machine()->Word32Shl());
    230         Reduction reduction = ReduceWord32Shl(node);
    231         return reduction.Changed() ? reduction : Changed(node);
    232       }
    233       break;
    234     }
    235     case IrOpcode::kInt32MulWithOverflow: {
    236       Int32BinopMatcher m(node);
    237       if (m.right().Is(2)) {
    238         node->ReplaceInput(1, m.left().node());
    239         NodeProperties::ChangeOp(node, machine()->Int32AddWithOverflow());
    240         return Changed(node);
    241       }
    242       if (m.right().Is(-1)) {
    243         node->ReplaceInput(0, Int32Constant(0));
    244         node->ReplaceInput(1, m.left().node());
    245         NodeProperties::ChangeOp(node, machine()->Int32SubWithOverflow());
    246         return 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.LeftEqualsRight()) return ReplaceBool(false);  // x < x => false
    264       if (m.left().IsWord32Or() && m.right().Is(0)) {
    265         // (x | K) < 0 => true or (K | x) < 0 => true iff K < 0
    266         Int32BinopMatcher mleftmatcher(m.left().node());
    267         if (mleftmatcher.left().IsNegative() ||
    268             mleftmatcher.right().IsNegative()) {
    269           return ReplaceBool(true);
    270         }
    271       }
    272       break;
    273     }
    274     case IrOpcode::kInt32LessThanOrEqual: {
    275       Int32BinopMatcher m(node);
    276       if (m.IsFoldable()) {  // K <= K => K
    277         return ReplaceBool(m.left().Value() <= m.right().Value());
    278       }
    279       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x <= x => true
    280       break;
    281     }
    282     case IrOpcode::kUint32LessThan: {
    283       Uint32BinopMatcher m(node);
    284       if (m.left().Is(kMaxUInt32)) return ReplaceBool(false);  // M < x => false
    285       if (m.right().Is(0)) return ReplaceBool(false);          // x < 0 => false
    286       if (m.IsFoldable()) {                                    // K < K => K
    287         return ReplaceBool(m.left().Value() < m.right().Value());
    288       }
    289       if (m.LeftEqualsRight()) return ReplaceBool(false);  // x < x => false
    290       if (m.left().IsWord32Sar() && m.right().HasValue()) {
    291         Int32BinopMatcher mleft(m.left().node());
    292         if (mleft.right().HasValue()) {
    293           // (x >> K) < C => x < (C << K)
    294           // when C < (M >> K)
    295           const uint32_t c = m.right().Value();
    296           const uint32_t k = mleft.right().Value() & 0x1f;
    297           if (c < static_cast<uint32_t>(kMaxInt >> k)) {
    298             node->ReplaceInput(0, mleft.left().node());
    299             node->ReplaceInput(1, Uint32Constant(c << k));
    300             return Changed(node);
    301           }
    302           // TODO(turbofan): else the comparison is always true.
    303         }
    304       }
    305       break;
    306     }
    307     case IrOpcode::kUint32LessThanOrEqual: {
    308       Uint32BinopMatcher m(node);
    309       if (m.left().Is(0)) return ReplaceBool(true);            // 0 <= x => true
    310       if (m.right().Is(kMaxUInt32)) return ReplaceBool(true);  // x <= M => true
    311       if (m.IsFoldable()) {                                    // K <= K => K
    312         return ReplaceBool(m.left().Value() <= m.right().Value());
    313       }
    314       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x <= x => true
    315       break;
    316     }
    317     case IrOpcode::kFloat32Sub: {
    318       Float32BinopMatcher m(node);
    319       if (m.right().Is(0) && (copysign(1.0, m.right().Value()) > 0)) {
    320         return Replace(m.left().node());  // x - 0 => x
    321       }
    322       if (m.right().IsNaN()) {  // x - NaN => NaN
    323         return Replace(m.right().node());
    324       }
    325       if (m.left().IsNaN()) {  // NaN - x => NaN
    326         return Replace(m.left().node());
    327       }
    328       if (m.IsFoldable()) {  // L - R => (L - R)
    329         return ReplaceFloat32(m.left().Value() - m.right().Value());
    330       }
    331       if (m.left().IsMinusZero()) {
    332         // -0.0 - round_down(-0.0 - R) => round_up(R)
    333         if (machine()->Float32RoundUp().IsSupported() &&
    334             m.right().IsFloat32RoundDown()) {
    335           if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat32Sub) {
    336             Float32BinopMatcher mright0(m.right().InputAt(0));
    337             if (mright0.left().IsMinusZero()) {
    338               return Replace(graph()->NewNode(machine()->Float32RoundUp().op(),
    339                                               mright0.right().node()));
    340             }
    341           }
    342         }
    343         // -0.0 - R => -R
    344         node->RemoveInput(0);
    345         NodeProperties::ChangeOp(node, machine()->Float32Neg());
    346         return Changed(node);
    347       }
    348       break;
    349     }
    350     case IrOpcode::kFloat64Add: {
    351       Float64BinopMatcher m(node);
    352       if (m.right().IsNaN()) {  // x + NaN => NaN
    353         return Replace(m.right().node());
    354       }
    355       if (m.IsFoldable()) {  // K + K => K
    356         return ReplaceFloat64(m.left().Value() + m.right().Value());
    357       }
    358       break;
    359     }
    360     case IrOpcode::kFloat64Sub: {
    361       Float64BinopMatcher m(node);
    362       if (m.right().Is(0) && (Double(m.right().Value()).Sign() > 0)) {
    363         return Replace(m.left().node());  // x - 0 => x
    364       }
    365       if (m.right().IsNaN()) {  // x - NaN => NaN
    366         return Replace(m.right().node());
    367       }
    368       if (m.left().IsNaN()) {  // NaN - x => NaN
    369         return Replace(m.left().node());
    370       }
    371       if (m.IsFoldable()) {  // L - R => (L - R)
    372         return ReplaceFloat64(m.left().Value() - m.right().Value());
    373       }
    374       if (m.left().IsMinusZero()) {
    375         // -0.0 - round_down(-0.0 - R) => round_up(R)
    376         if (machine()->Float64RoundUp().IsSupported() &&
    377             m.right().IsFloat64RoundDown()) {
    378           if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub) {
    379             Float64BinopMatcher mright0(m.right().InputAt(0));
    380             if (mright0.left().IsMinusZero()) {
    381               return Replace(graph()->NewNode(machine()->Float64RoundUp().op(),
    382                                               mright0.right().node()));
    383             }
    384           }
    385         }
    386         // -0.0 - R => -R
    387         node->RemoveInput(0);
    388         NodeProperties::ChangeOp(node, machine()->Float64Neg());
    389         return Changed(node);
    390       }
    391       break;
    392     }
    393     case IrOpcode::kFloat64Mul: {
    394       Float64BinopMatcher m(node);
    395       if (m.right().Is(-1)) {  // x * -1.0 => -0.0 - x
    396         node->ReplaceInput(0, Float64Constant(-0.0));
    397         node->ReplaceInput(1, m.left().node());
    398         NodeProperties::ChangeOp(node, machine()->Float64Sub());
    399         return Changed(node);
    400       }
    401       if (m.right().Is(1)) return Replace(m.left().node());  // x * 1.0 => x
    402       if (m.right().IsNaN()) {                               // x * NaN => NaN
    403         return Replace(m.right().node());
    404       }
    405       if (m.IsFoldable()) {  // K * K => K
    406         return ReplaceFloat64(m.left().Value() * m.right().Value());
    407       }
    408       if (m.right().Is(2)) {  // x * 2.0 => x + x
    409         node->ReplaceInput(1, m.left().node());
    410         NodeProperties::ChangeOp(node, machine()->Float64Add());
    411         return Changed(node);
    412       }
    413       break;
    414     }
    415     case IrOpcode::kFloat64Div: {
    416       Float64BinopMatcher m(node);
    417       if (m.right().Is(1)) return Replace(m.left().node());  // x / 1.0 => x
    418       if (m.right().IsNaN()) {                               // x / NaN => NaN
    419         return Replace(m.right().node());
    420       }
    421       if (m.left().IsNaN()) {  // NaN / x => NaN
    422         return Replace(m.left().node());
    423       }
    424       if (m.IsFoldable()) {  // K / K => K
    425         return ReplaceFloat64(m.left().Value() / m.right().Value());
    426       }
    427       if (m.right().Is(-1)) {  // x / -1.0 => -x
    428         node->RemoveInput(1);
    429         NodeProperties::ChangeOp(node, machine()->Float64Neg());
    430         return Changed(node);
    431       }
    432       if (m.right().IsNormal() && m.right().IsPositiveOrNegativePowerOf2()) {
    433         // All reciprocals of non-denormal powers of two can be represented
    434         // exactly, so division by power of two can be reduced to
    435         // multiplication by reciprocal, with the same result.
    436         node->ReplaceInput(1, Float64Constant(1.0 / m.right().Value()));
    437         NodeProperties::ChangeOp(node, machine()->Float64Mul());
    438         return Changed(node);
    439       }
    440       break;
    441     }
    442     case IrOpcode::kFloat64Mod: {
    443       Float64BinopMatcher m(node);
    444       if (m.right().Is(0)) {  // x % 0 => NaN
    445         return ReplaceFloat64(std::numeric_limits<double>::quiet_NaN());
    446       }
    447       if (m.right().IsNaN()) {  // x % NaN => NaN
    448         return Replace(m.right().node());
    449       }
    450       if (m.left().IsNaN()) {  // NaN % x => NaN
    451         return Replace(m.left().node());
    452       }
    453       if (m.IsFoldable()) {  // K % K => K
    454         return ReplaceFloat64(modulo(m.left().Value(), m.right().Value()));
    455       }
    456       break;
    457     }
    458     case IrOpcode::kFloat64Acos: {
    459       Float64Matcher m(node->InputAt(0));
    460       if (m.HasValue()) return ReplaceFloat64(base::ieee754::acos(m.Value()));
    461       break;
    462     }
    463     case IrOpcode::kFloat64Acosh: {
    464       Float64Matcher m(node->InputAt(0));
    465       if (m.HasValue()) return ReplaceFloat64(base::ieee754::acosh(m.Value()));
    466       break;
    467     }
    468     case IrOpcode::kFloat64Asin: {
    469       Float64Matcher m(node->InputAt(0));
    470       if (m.HasValue()) return ReplaceFloat64(base::ieee754::asin(m.Value()));
    471       break;
    472     }
    473     case IrOpcode::kFloat64Asinh: {
    474       Float64Matcher m(node->InputAt(0));
    475       if (m.HasValue()) return ReplaceFloat64(base::ieee754::asinh(m.Value()));
    476       break;
    477     }
    478     case IrOpcode::kFloat64Atan: {
    479       Float64Matcher m(node->InputAt(0));
    480       if (m.HasValue()) return ReplaceFloat64(base::ieee754::atan(m.Value()));
    481       break;
    482     }
    483     case IrOpcode::kFloat64Atanh: {
    484       Float64Matcher m(node->InputAt(0));
    485       if (m.HasValue()) return ReplaceFloat64(base::ieee754::atanh(m.Value()));
    486       break;
    487     }
    488     case IrOpcode::kFloat64Atan2: {
    489       Float64BinopMatcher m(node);
    490       if (m.right().IsNaN()) {
    491         return Replace(m.right().node());
    492       }
    493       if (m.left().IsNaN()) {
    494         return Replace(m.left().node());
    495       }
    496       if (m.IsFoldable()) {
    497         return ReplaceFloat64(
    498             base::ieee754::atan2(m.left().Value(), m.right().Value()));
    499       }
    500       break;
    501     }
    502     case IrOpcode::kFloat64Cbrt: {
    503       Float64Matcher m(node->InputAt(0));
    504       if (m.HasValue()) return ReplaceFloat64(base::ieee754::cbrt(m.Value()));
    505       break;
    506     }
    507     case IrOpcode::kFloat64Cos: {
    508       Float64Matcher m(node->InputAt(0));
    509       if (m.HasValue()) return ReplaceFloat64(base::ieee754::cos(m.Value()));
    510       break;
    511     }
    512     case IrOpcode::kFloat64Cosh: {
    513       Float64Matcher m(node->InputAt(0));
    514       if (m.HasValue()) return ReplaceFloat64(base::ieee754::cosh(m.Value()));
    515       break;
    516     }
    517     case IrOpcode::kFloat64Exp: {
    518       Float64Matcher m(node->InputAt(0));
    519       if (m.HasValue()) return ReplaceFloat64(base::ieee754::exp(m.Value()));
    520       break;
    521     }
    522     case IrOpcode::kFloat64Expm1: {
    523       Float64Matcher m(node->InputAt(0));
    524       if (m.HasValue()) return ReplaceFloat64(base::ieee754::expm1(m.Value()));
    525       break;
    526     }
    527     case IrOpcode::kFloat64Log: {
    528       Float64Matcher m(node->InputAt(0));
    529       if (m.HasValue()) return ReplaceFloat64(base::ieee754::log(m.Value()));
    530       break;
    531     }
    532     case IrOpcode::kFloat64Log1p: {
    533       Float64Matcher m(node->InputAt(0));
    534       if (m.HasValue()) return ReplaceFloat64(base::ieee754::log1p(m.Value()));
    535       break;
    536     }
    537     case IrOpcode::kFloat64Log10: {
    538       Float64Matcher m(node->InputAt(0));
    539       if (m.HasValue()) return ReplaceFloat64(base::ieee754::log10(m.Value()));
    540       break;
    541     }
    542     case IrOpcode::kFloat64Log2: {
    543       Float64Matcher m(node->InputAt(0));
    544       if (m.HasValue()) return ReplaceFloat64(base::ieee754::log2(m.Value()));
    545       break;
    546     }
    547     case IrOpcode::kFloat64Pow: {
    548       Float64BinopMatcher m(node);
    549       if (m.IsFoldable()) {
    550         return ReplaceFloat64(Pow(m.left().Value(), m.right().Value()));
    551       } else if (m.right().Is(0.0)) {  // x ** +-0.0 => 1.0
    552         return ReplaceFloat64(1.0);
    553       } else if (m.right().Is(-2.0)) {  // x ** -2.0 => 1 / (x * x)
    554         node->ReplaceInput(0, Float64Constant(1.0));
    555         node->ReplaceInput(1, Float64Mul(m.left().node(), m.left().node()));
    556         NodeProperties::ChangeOp(node, machine()->Float64Div());
    557         return Changed(node);
    558       } else if (m.right().Is(2.0)) {  // x ** 2.0 => x * x
    559         node->ReplaceInput(1, m.left().node());
    560         NodeProperties::ChangeOp(node, machine()->Float64Mul());
    561         return Changed(node);
    562       } else if (m.right().Is(-0.5)) {
    563         // x ** 0.5 => 1 / (if x <= -Infinity then Infinity else sqrt(0.0 + x))
    564         node->ReplaceInput(0, Float64Constant(1.0));
    565         node->ReplaceInput(1, Float64PowHalf(m.left().node()));
    566         NodeProperties::ChangeOp(node, machine()->Float64Div());
    567         return Changed(node);
    568       } else if (m.right().Is(0.5)) {
    569         // x ** 0.5 => if x <= -Infinity then Infinity else sqrt(0.0 + x)
    570         return Replace(Float64PowHalf(m.left().node()));
    571       }
    572       break;
    573     }
    574     case IrOpcode::kFloat64Sin: {
    575       Float64Matcher m(node->InputAt(0));
    576       if (m.HasValue()) return ReplaceFloat64(base::ieee754::sin(m.Value()));
    577       break;
    578     }
    579     case IrOpcode::kFloat64Sinh: {
    580       Float64Matcher m(node->InputAt(0));
    581       if (m.HasValue()) return ReplaceFloat64(base::ieee754::sinh(m.Value()));
    582       break;
    583     }
    584     case IrOpcode::kFloat64Tan: {
    585       Float64Matcher m(node->InputAt(0));
    586       if (m.HasValue()) return ReplaceFloat64(base::ieee754::tan(m.Value()));
    587       break;
    588     }
    589     case IrOpcode::kFloat64Tanh: {
    590       Float64Matcher m(node->InputAt(0));
    591       if (m.HasValue()) return ReplaceFloat64(base::ieee754::tanh(m.Value()));
    592       break;
    593     }
    594     case IrOpcode::kChangeFloat32ToFloat64: {
    595       Float32Matcher m(node->InputAt(0));
    596       if (m.HasValue()) return ReplaceFloat64(m.Value());
    597       break;
    598     }
    599     case IrOpcode::kChangeFloat64ToInt32: {
    600       Float64Matcher m(node->InputAt(0));
    601       if (m.HasValue()) return ReplaceInt32(FastD2I(m.Value()));
    602       if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
    603       break;
    604     }
    605     case IrOpcode::kChangeFloat64ToUint32: {
    606       Float64Matcher m(node->InputAt(0));
    607       if (m.HasValue()) return ReplaceInt32(FastD2UI(m.Value()));
    608       if (m.IsChangeUint32ToFloat64()) return Replace(m.node()->InputAt(0));
    609       break;
    610     }
    611     case IrOpcode::kChangeInt32ToFloat64: {
    612       Int32Matcher m(node->InputAt(0));
    613       if (m.HasValue()) return ReplaceFloat64(FastI2D(m.Value()));
    614       break;
    615     }
    616     case IrOpcode::kChangeInt32ToInt64: {
    617       Int32Matcher m(node->InputAt(0));
    618       if (m.HasValue()) return ReplaceInt64(m.Value());
    619       break;
    620     }
    621     case IrOpcode::kChangeUint32ToFloat64: {
    622       Uint32Matcher m(node->InputAt(0));
    623       if (m.HasValue()) return ReplaceFloat64(FastUI2D(m.Value()));
    624       break;
    625     }
    626     case IrOpcode::kChangeUint32ToUint64: {
    627       Uint32Matcher m(node->InputAt(0));
    628       if (m.HasValue()) return ReplaceInt64(static_cast<uint64_t>(m.Value()));
    629       break;
    630     }
    631     case IrOpcode::kTruncateFloat64ToWord32: {
    632       Float64Matcher m(node->InputAt(0));
    633       if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value()));
    634       if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
    635       return NoChange();
    636     }
    637     case IrOpcode::kTruncateInt64ToInt32: {
    638       Int64Matcher m(node->InputAt(0));
    639       if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value()));
    640       if (m.IsChangeInt32ToInt64()) return Replace(m.node()->InputAt(0));
    641       break;
    642     }
    643     case IrOpcode::kTruncateFloat64ToFloat32: {
    644       Float64Matcher m(node->InputAt(0));
    645       if (m.HasValue()) return ReplaceFloat32(DoubleToFloat32(m.Value()));
    646       if (m.IsChangeFloat32ToFloat64()) return Replace(m.node()->InputAt(0));
    647       break;
    648     }
    649     case IrOpcode::kRoundFloat64ToInt32: {
    650       Float64Matcher m(node->InputAt(0));
    651       if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value()));
    652       if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
    653       break;
    654     }
    655     case IrOpcode::kFloat64InsertLowWord32:
    656       return ReduceFloat64InsertLowWord32(node);
    657     case IrOpcode::kFloat64InsertHighWord32:
    658       return ReduceFloat64InsertHighWord32(node);
    659     case IrOpcode::kStore:
    660     case IrOpcode::kUnalignedStore:
    661     case IrOpcode::kCheckedStore:
    662       return ReduceStore(node);
    663     case IrOpcode::kFloat64Equal:
    664     case IrOpcode::kFloat64LessThan:
    665     case IrOpcode::kFloat64LessThanOrEqual:
    666       return ReduceFloat64Compare(node);
    667     default:
    668       break;
    669   }
    670   return NoChange();
    671 }
    672 
    673 Reduction MachineOperatorReducer::ReduceInt32Add(Node* node) {
    674   DCHECK_EQ(IrOpcode::kInt32Add, node->opcode());
    675   Int32BinopMatcher m(node);
    676   if (m.right().Is(0)) return Replace(m.left().node());  // x + 0 => x
    677   if (m.IsFoldable()) {                                  // K + K => K
    678     return ReplaceUint32(bit_cast<uint32_t>(m.left().Value()) +
    679                          bit_cast<uint32_t>(m.right().Value()));
    680   }
    681   if (m.left().IsInt32Sub()) {
    682     Int32BinopMatcher mleft(m.left().node());
    683     if (mleft.left().Is(0)) {  // (0 - x) + y => y - x
    684       node->ReplaceInput(0, m.right().node());
    685       node->ReplaceInput(1, mleft.right().node());
    686       NodeProperties::ChangeOp(node, machine()->Int32Sub());
    687       Reduction const reduction = ReduceInt32Sub(node);
    688       return reduction.Changed() ? reduction : Changed(node);
    689     }
    690   }
    691   if (m.right().IsInt32Sub()) {
    692     Int32BinopMatcher mright(m.right().node());
    693     if (mright.left().Is(0)) {  // y + (0 - x) => y - x
    694       node->ReplaceInput(1, mright.right().node());
    695       NodeProperties::ChangeOp(node, machine()->Int32Sub());
    696       Reduction const reduction = ReduceInt32Sub(node);
    697       return reduction.Changed() ? reduction : Changed(node);
    698     }
    699   }
    700   return NoChange();
    701 }
    702 
    703 Reduction MachineOperatorReducer::ReduceInt64Add(Node* node) {
    704   DCHECK_EQ(IrOpcode::kInt64Add, node->opcode());
    705   Int64BinopMatcher m(node);
    706   if (m.right().Is(0)) return Replace(m.left().node());  // x + 0 => 0
    707   if (m.IsFoldable()) {
    708     return Replace(Uint64Constant(bit_cast<uint64_t>(m.left().Value()) +
    709                                   bit_cast<uint64_t>(m.right().Value())));
    710   }
    711   return NoChange();
    712 }
    713 
    714 Reduction MachineOperatorReducer::ReduceInt32Sub(Node* node) {
    715   DCHECK_EQ(IrOpcode::kInt32Sub, node->opcode());
    716   Int32BinopMatcher m(node);
    717   if (m.right().Is(0)) return Replace(m.left().node());  // x - 0 => x
    718   if (m.IsFoldable()) {                                  // K - K => K
    719     return ReplaceInt32(static_cast<uint32_t>(m.left().Value()) -
    720                         static_cast<uint32_t>(m.right().Value()));
    721   }
    722   if (m.LeftEqualsRight()) return ReplaceInt32(0);  // x - x => 0
    723   if (m.right().HasValue()) {                       // x - K => x + -K
    724     node->ReplaceInput(1, Int32Constant(-m.right().Value()));
    725     NodeProperties::ChangeOp(node, machine()->Int32Add());
    726     Reduction const reduction = ReduceInt32Add(node);
    727     return reduction.Changed() ? reduction : Changed(node);
    728   }
    729   return NoChange();
    730 }
    731 
    732 Reduction MachineOperatorReducer::ReduceInt64Sub(Node* node) {
    733   DCHECK_EQ(IrOpcode::kInt64Sub, node->opcode());
    734   Int64BinopMatcher m(node);
    735   if (m.right().Is(0)) return Replace(m.left().node());  // x - 0 => x
    736   if (m.IsFoldable()) {                                  // K - K => K
    737     return Replace(Uint64Constant(bit_cast<uint64_t>(m.left().Value()) -
    738                                   bit_cast<uint64_t>(m.right().Value())));
    739   }
    740   if (m.LeftEqualsRight()) return Replace(Int64Constant(0));  // x - x => 0
    741   if (m.right().HasValue()) {                                 // x - K => x + -K
    742     node->ReplaceInput(1, Int64Constant(-m.right().Value()));
    743     NodeProperties::ChangeOp(node, machine()->Int64Add());
    744     Reduction const reduction = ReduceInt64Add(node);
    745     return reduction.Changed() ? reduction : Changed(node);
    746   }
    747   return NoChange();
    748 }
    749 
    750 Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
    751   Int32BinopMatcher m(node);
    752   if (m.left().Is(0)) return Replace(m.left().node());    // 0 / x => 0
    753   if (m.right().Is(0)) return Replace(m.right().node());  // x / 0 => 0
    754   if (m.right().Is(1)) return Replace(m.left().node());   // x / 1 => x
    755   if (m.IsFoldable()) {                                   // K / K => K
    756     return ReplaceInt32(
    757         base::bits::SignedDiv32(m.left().Value(), m.right().Value()));
    758   }
    759   if (m.LeftEqualsRight()) {  // x / x => x != 0
    760     Node* const zero = Int32Constant(0);
    761     return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
    762   }
    763   if (m.right().Is(-1)) {  // x / -1 => 0 - x
    764     node->ReplaceInput(0, Int32Constant(0));
    765     node->ReplaceInput(1, m.left().node());
    766     node->TrimInputCount(2);
    767     NodeProperties::ChangeOp(node, machine()->Int32Sub());
    768     return Changed(node);
    769   }
    770   if (m.right().HasValue()) {
    771     int32_t const divisor = m.right().Value();
    772     Node* const dividend = m.left().node();
    773     Node* quotient = dividend;
    774     if (base::bits::IsPowerOfTwo32(Abs(divisor))) {
    775       uint32_t const shift = WhichPowerOf2Abs(divisor);
    776       DCHECK_NE(0u, shift);
    777       if (shift > 1) {
    778         quotient = Word32Sar(quotient, 31);
    779       }
    780       quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend);
    781       quotient = Word32Sar(quotient, shift);
    782     } else {
    783       quotient = Int32Div(quotient, Abs(divisor));
    784     }
    785     if (divisor < 0) {
    786       node->ReplaceInput(0, Int32Constant(0));
    787       node->ReplaceInput(1, quotient);
    788       node->TrimInputCount(2);
    789       NodeProperties::ChangeOp(node, machine()->Int32Sub());
    790       return Changed(node);
    791     }
    792     return Replace(quotient);
    793   }
    794   return NoChange();
    795 }
    796 
    797 
    798 Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
    799   Uint32BinopMatcher m(node);
    800   if (m.left().Is(0)) return Replace(m.left().node());    // 0 / x => 0
    801   if (m.right().Is(0)) return Replace(m.right().node());  // x / 0 => 0
    802   if (m.right().Is(1)) return Replace(m.left().node());   // x / 1 => x
    803   if (m.IsFoldable()) {                                   // K / K => K
    804     return ReplaceUint32(
    805         base::bits::UnsignedDiv32(m.left().Value(), m.right().Value()));
    806   }
    807   if (m.LeftEqualsRight()) {  // x / x => x != 0
    808     Node* const zero = Int32Constant(0);
    809     return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
    810   }
    811   if (m.right().HasValue()) {
    812     Node* const dividend = m.left().node();
    813     uint32_t const divisor = m.right().Value();
    814     if (base::bits::IsPowerOfTwo32(divisor)) {  // x / 2^n => x >> n
    815       node->ReplaceInput(1, Uint32Constant(WhichPowerOf2(m.right().Value())));
    816       node->TrimInputCount(2);
    817       NodeProperties::ChangeOp(node, machine()->Word32Shr());
    818       return Changed(node);
    819     } else {
    820       return Replace(Uint32Div(dividend, divisor));
    821     }
    822   }
    823   return NoChange();
    824 }
    825 
    826 
    827 Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
    828   Int32BinopMatcher m(node);
    829   if (m.left().Is(0)) return Replace(m.left().node());    // 0 % x  => 0
    830   if (m.right().Is(0)) return Replace(m.right().node());  // x % 0  => 0
    831   if (m.right().Is(1)) return ReplaceInt32(0);            // x % 1  => 0
    832   if (m.right().Is(-1)) return ReplaceInt32(0);           // x % -1 => 0
    833   if (m.LeftEqualsRight()) return ReplaceInt32(0);        // x % x  => 0
    834   if (m.IsFoldable()) {                                   // K % K => K
    835     return ReplaceInt32(
    836         base::bits::SignedMod32(m.left().Value(), m.right().Value()));
    837   }
    838   if (m.right().HasValue()) {
    839     Node* const dividend = m.left().node();
    840     int32_t const divisor = Abs(m.right().Value());
    841     if (base::bits::IsPowerOfTwo32(divisor)) {
    842       uint32_t const mask = divisor - 1;
    843       Node* const zero = Int32Constant(0);
    844       node->ReplaceInput(
    845           0, graph()->NewNode(machine()->Int32LessThan(), dividend, zero));
    846       node->ReplaceInput(
    847           1, Int32Sub(zero, Word32And(Int32Sub(zero, dividend), mask)));
    848       node->ReplaceInput(2, Word32And(dividend, mask));
    849       NodeProperties::ChangeOp(
    850           node,
    851           common()->Select(MachineRepresentation::kWord32, BranchHint::kFalse));
    852     } else {
    853       Node* quotient = Int32Div(dividend, divisor);
    854       DCHECK_EQ(dividend, node->InputAt(0));
    855       node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
    856       node->TrimInputCount(2);
    857       NodeProperties::ChangeOp(node, machine()->Int32Sub());
    858     }
    859     return Changed(node);
    860   }
    861   return NoChange();
    862 }
    863 
    864 
    865 Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) {
    866   Uint32BinopMatcher m(node);
    867   if (m.left().Is(0)) return Replace(m.left().node());    // 0 % x => 0
    868   if (m.right().Is(0)) return Replace(m.right().node());  // x % 0 => 0
    869   if (m.right().Is(1)) return ReplaceUint32(0);           // x % 1 => 0
    870   if (m.LeftEqualsRight()) return ReplaceInt32(0);        // x % x  => 0
    871   if (m.IsFoldable()) {                                   // K % K => K
    872     return ReplaceUint32(
    873         base::bits::UnsignedMod32(m.left().Value(), m.right().Value()));
    874   }
    875   if (m.right().HasValue()) {
    876     Node* const dividend = m.left().node();
    877     uint32_t const divisor = m.right().Value();
    878     if (base::bits::IsPowerOfTwo32(divisor)) {  // x % 2^n => x & 2^n-1
    879       node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1));
    880       node->TrimInputCount(2);
    881       NodeProperties::ChangeOp(node, machine()->Word32And());
    882     } else {
    883       Node* quotient = Uint32Div(dividend, divisor);
    884       DCHECK_EQ(dividend, node->InputAt(0));
    885       node->ReplaceInput(1, Int32Mul(quotient, Uint32Constant(divisor)));
    886       node->TrimInputCount(2);
    887       NodeProperties::ChangeOp(node, machine()->Int32Sub());
    888     }
    889     return Changed(node);
    890   }
    891   return NoChange();
    892 }
    893 
    894 
    895 Reduction MachineOperatorReducer::ReduceStore(Node* node) {
    896   NodeMatcher nm(node);
    897   MachineRepresentation rep;
    898   int value_input;
    899   if (nm.IsCheckedStore()) {
    900     rep = CheckedStoreRepresentationOf(node->op());
    901     value_input = 3;
    902   } else if (nm.IsStore()) {
    903     rep = StoreRepresentationOf(node->op()).representation();
    904     value_input = 2;
    905   } else {
    906     DCHECK(nm.IsUnalignedStore());
    907     rep = UnalignedStoreRepresentationOf(node->op());
    908     value_input = 2;
    909   }
    910 
    911   Node* const value = node->InputAt(value_input);
    912 
    913   switch (value->opcode()) {
    914     case IrOpcode::kWord32And: {
    915       Uint32BinopMatcher m(value);
    916       if (m.right().HasValue() && ((rep == MachineRepresentation::kWord8 &&
    917                                     (m.right().Value() & 0xff) == 0xff) ||
    918                                    (rep == MachineRepresentation::kWord16 &&
    919                                     (m.right().Value() & 0xffff) == 0xffff))) {
    920         node->ReplaceInput(value_input, m.left().node());
    921         return Changed(node);
    922       }
    923       break;
    924     }
    925     case IrOpcode::kWord32Sar: {
    926       Int32BinopMatcher m(value);
    927       if (m.left().IsWord32Shl() && ((rep == MachineRepresentation::kWord8 &&
    928                                       m.right().IsInRange(1, 24)) ||
    929                                      (rep == MachineRepresentation::kWord16 &&
    930                                       m.right().IsInRange(1, 16)))) {
    931         Int32BinopMatcher mleft(m.left().node());
    932         if (mleft.right().Is(m.right().Value())) {
    933           node->ReplaceInput(value_input, mleft.left().node());
    934           return Changed(node);
    935         }
    936       }
    937       break;
    938     }
    939     default:
    940       break;
    941   }
    942   return NoChange();
    943 }
    944 
    945 
    946 Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) {
    947   switch (node->opcode()) {
    948     case IrOpcode::kInt32AddWithOverflow: {
    949       DCHECK(index == 0 || index == 1);
    950       Int32BinopMatcher m(node);
    951       if (m.IsFoldable()) {
    952         int32_t val;
    953         bool ovf = base::bits::SignedAddOverflow32(m.left().Value(),
    954                                                    m.right().Value(), &val);
    955         return ReplaceInt32(index == 0 ? val : ovf);
    956       }
    957       if (m.right().Is(0)) {
    958         return Replace(index == 0 ? m.left().node() : m.right().node());
    959       }
    960       break;
    961     }
    962     case IrOpcode::kInt32SubWithOverflow: {
    963       DCHECK(index == 0 || index == 1);
    964       Int32BinopMatcher m(node);
    965       if (m.IsFoldable()) {
    966         int32_t val;
    967         bool ovf = base::bits::SignedSubOverflow32(m.left().Value(),
    968                                                    m.right().Value(), &val);
    969         return ReplaceInt32(index == 0 ? val : ovf);
    970       }
    971       if (m.right().Is(0)) {
    972         return Replace(index == 0 ? m.left().node() : m.right().node());
    973       }
    974       break;
    975     }
    976     case IrOpcode::kInt32MulWithOverflow: {
    977       DCHECK(index == 0 || index == 1);
    978       Int32BinopMatcher m(node);
    979       if (m.IsFoldable()) {
    980         int32_t val;
    981         bool ovf = base::bits::SignedMulOverflow32(m.left().Value(),
    982                                                    m.right().Value(), &val);
    983         return ReplaceInt32(index == 0 ? val : ovf);
    984       }
    985       if (m.right().Is(0)) {
    986         return Replace(m.right().node());
    987       }
    988       if (m.right().Is(1)) {
    989         return index == 0 ? Replace(m.left().node()) : ReplaceInt32(0);
    990       }
    991       break;
    992     }
    993     default:
    994       break;
    995   }
    996   return NoChange();
    997 }
    998 
    999 
   1000 Reduction MachineOperatorReducer::ReduceWord32Shifts(Node* node) {
   1001   DCHECK((node->opcode() == IrOpcode::kWord32Shl) ||
   1002          (node->opcode() == IrOpcode::kWord32Shr) ||
   1003          (node->opcode() == IrOpcode::kWord32Sar));
   1004   if (machine()->Word32ShiftIsSafe()) {
   1005     // Remove the explicit 'and' with 0x1f if the shift provided by the machine
   1006     // instruction matches that required by JavaScript.
   1007     Int32BinopMatcher m(node);
   1008     if (m.right().IsWord32And()) {
   1009       Int32BinopMatcher mright(m.right().node());
   1010       if (mright.right().Is(0x1f)) {
   1011         node->ReplaceInput(1, mright.left().node());
   1012         return Changed(node);
   1013       }
   1014     }
   1015   }
   1016   return NoChange();
   1017 }
   1018 
   1019 
   1020 Reduction MachineOperatorReducer::ReduceWord32Shl(Node* node) {
   1021   DCHECK_EQ(IrOpcode::kWord32Shl, node->opcode());
   1022   Int32BinopMatcher m(node);
   1023   if (m.right().Is(0)) return Replace(m.left().node());  // x << 0 => x
   1024   if (m.IsFoldable()) {                                  // K << K => K
   1025     return ReplaceInt32(m.left().Value() << m.right().Value());
   1026   }
   1027   if (m.right().IsInRange(1, 31)) {
   1028     // (x >>> K) << K => x & ~(2^K - 1)
   1029     // (x >> K) << K => x & ~(2^K - 1)
   1030     if (m.left().IsWord32Sar() || m.left().IsWord32Shr()) {
   1031       Int32BinopMatcher mleft(m.left().node());
   1032       if (mleft.right().Is(m.right().Value())) {
   1033         node->ReplaceInput(0, mleft.left().node());
   1034         node->ReplaceInput(1,
   1035                            Uint32Constant(~((1U << m.right().Value()) - 1U)));
   1036         NodeProperties::ChangeOp(node, machine()->Word32And());
   1037         Reduction reduction = ReduceWord32And(node);
   1038         return reduction.Changed() ? reduction : Changed(node);
   1039       }
   1040     }
   1041   }
   1042   return ReduceWord32Shifts(node);
   1043 }
   1044 
   1045 Reduction MachineOperatorReducer::ReduceWord64Shl(Node* node) {
   1046   DCHECK_EQ(IrOpcode::kWord64Shl, node->opcode());
   1047   Int64BinopMatcher m(node);
   1048   if (m.right().Is(0)) return Replace(m.left().node());  // x << 0 => x
   1049   if (m.IsFoldable()) {                                  // K << K => K
   1050     return ReplaceInt64(m.left().Value() << m.right().Value());
   1051   }
   1052   return NoChange();
   1053 }
   1054 
   1055 Reduction MachineOperatorReducer::ReduceWord32Shr(Node* node) {
   1056   Uint32BinopMatcher m(node);
   1057   if (m.right().Is(0)) return Replace(m.left().node());  // x >>> 0 => x
   1058   if (m.IsFoldable()) {                                  // K >>> K => K
   1059     return ReplaceInt32(m.left().Value() >> m.right().Value());
   1060   }
   1061   if (m.left().IsWord32And() && m.right().HasValue()) {
   1062     Uint32BinopMatcher mleft(m.left().node());
   1063     if (mleft.right().HasValue()) {
   1064       uint32_t shift = m.right().Value() & 0x1f;
   1065       uint32_t mask = mleft.right().Value();
   1066       if ((mask >> shift) == 0) {
   1067         // (m >>> s) == 0 implies ((x & m) >>> s) == 0
   1068         return ReplaceInt32(0);
   1069       }
   1070     }
   1071   }
   1072   return ReduceWord32Shifts(node);
   1073 }
   1074 
   1075 Reduction MachineOperatorReducer::ReduceWord64Shr(Node* node) {
   1076   DCHECK_EQ(IrOpcode::kWord64Shr, node->opcode());
   1077   Uint64BinopMatcher m(node);
   1078   if (m.right().Is(0)) return Replace(m.left().node());  // x >>> 0 => x
   1079   if (m.IsFoldable()) {                                  // K >> K => K
   1080     return ReplaceInt64(m.left().Value() >> m.right().Value());
   1081   }
   1082   return NoChange();
   1083 }
   1084 
   1085 Reduction MachineOperatorReducer::ReduceWord32Sar(Node* node) {
   1086   Int32BinopMatcher m(node);
   1087   if (m.right().Is(0)) return Replace(m.left().node());  // x >> 0 => x
   1088   if (m.IsFoldable()) {                                  // K >> K => K
   1089     return ReplaceInt32(m.left().Value() >> m.right().Value());
   1090   }
   1091   if (m.left().IsWord32Shl()) {
   1092     Int32BinopMatcher mleft(m.left().node());
   1093     if (mleft.left().IsComparison()) {
   1094       if (m.right().Is(31) && mleft.right().Is(31)) {
   1095         // Comparison << 31 >> 31 => 0 - Comparison
   1096         node->ReplaceInput(0, Int32Constant(0));
   1097         node->ReplaceInput(1, mleft.left().node());
   1098         NodeProperties::ChangeOp(node, machine()->Int32Sub());
   1099         Reduction const reduction = ReduceInt32Sub(node);
   1100         return reduction.Changed() ? reduction : Changed(node);
   1101       }
   1102     } else if (mleft.left().IsLoad()) {
   1103       LoadRepresentation const rep =
   1104           LoadRepresentationOf(mleft.left().node()->op());
   1105       if (m.right().Is(24) && mleft.right().Is(24) &&
   1106           rep == MachineType::Int8()) {
   1107         // Load[kMachInt8] << 24 >> 24 => Load[kMachInt8]
   1108         return Replace(mleft.left().node());
   1109       }
   1110       if (m.right().Is(16) && mleft.right().Is(16) &&
   1111           rep == MachineType::Int16()) {
   1112         // Load[kMachInt16] << 16 >> 16 => Load[kMachInt8]
   1113         return Replace(mleft.left().node());
   1114       }
   1115     }
   1116   }
   1117   return ReduceWord32Shifts(node);
   1118 }
   1119 
   1120 Reduction MachineOperatorReducer::ReduceWord64Sar(Node* node) {
   1121   Int64BinopMatcher m(node);
   1122   if (m.right().Is(0)) return Replace(m.left().node());  // x >> 0 => x
   1123   if (m.IsFoldable()) {
   1124     return ReplaceInt64(m.left().Value() >> m.right().Value());
   1125   }
   1126   return NoChange();
   1127 }
   1128 
   1129 Reduction MachineOperatorReducer::ReduceWord32And(Node* node) {
   1130   DCHECK_EQ(IrOpcode::kWord32And, node->opcode());
   1131   Int32BinopMatcher m(node);
   1132   if (m.right().Is(0)) return Replace(m.right().node());  // x & 0  => 0
   1133   if (m.right().Is(-1)) return Replace(m.left().node());  // x & -1 => x
   1134   if (m.left().IsComparison() && m.right().Is(1)) {       // CMP & 1 => CMP
   1135     return Replace(m.left().node());
   1136   }
   1137   if (m.IsFoldable()) {                                   // K & K  => K
   1138     return ReplaceInt32(m.left().Value() & m.right().Value());
   1139   }
   1140   if (m.LeftEqualsRight()) return Replace(m.left().node());  // x & x => x
   1141   if (m.left().IsWord32And() && m.right().HasValue()) {
   1142     Int32BinopMatcher mleft(m.left().node());
   1143     if (mleft.right().HasValue()) {  // (x & K) & K => x & K
   1144       node->ReplaceInput(0, mleft.left().node());
   1145       node->ReplaceInput(
   1146           1, Int32Constant(m.right().Value() & mleft.right().Value()));
   1147       Reduction const reduction = ReduceWord32And(node);
   1148       return reduction.Changed() ? reduction : Changed(node);
   1149     }
   1150   }
   1151   if (m.right().IsNegativePowerOf2()) {
   1152     int32_t const mask = m.right().Value();
   1153     if (m.left().IsWord32Shl()) {
   1154       Uint32BinopMatcher mleft(m.left().node());
   1155       if (mleft.right().HasValue() &&
   1156           mleft.right().Value() >= base::bits::CountTrailingZeros32(mask)) {
   1157         // (x << L) & (-1 << K) => x << L iff K >= L
   1158         return Replace(mleft.node());
   1159       }
   1160     } else if (m.left().IsInt32Add()) {
   1161       Int32BinopMatcher mleft(m.left().node());
   1162       if (mleft.right().HasValue() &&
   1163           (mleft.right().Value() & mask) == mleft.right().Value()) {
   1164         // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
   1165         node->ReplaceInput(0, Word32And(mleft.left().node(), m.right().node()));
   1166         node->ReplaceInput(1, mleft.right().node());
   1167         NodeProperties::ChangeOp(node, machine()->Int32Add());
   1168         Reduction const reduction = ReduceInt32Add(node);
   1169         return reduction.Changed() ? reduction : Changed(node);
   1170       }
   1171       if (mleft.left().IsInt32Mul()) {
   1172         Int32BinopMatcher mleftleft(mleft.left().node());
   1173         if (mleftleft.right().IsMultipleOf(-mask)) {
   1174           // (y * (K << L) + x) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
   1175           node->ReplaceInput(0,
   1176                              Word32And(mleft.right().node(), m.right().node()));
   1177           node->ReplaceInput(1, mleftleft.node());
   1178           NodeProperties::ChangeOp(node, machine()->Int32Add());
   1179           Reduction const reduction = ReduceInt32Add(node);
   1180           return reduction.Changed() ? reduction : Changed(node);
   1181         }
   1182       }
   1183       if (mleft.right().IsInt32Mul()) {
   1184         Int32BinopMatcher mleftright(mleft.right().node());
   1185         if (mleftright.right().IsMultipleOf(-mask)) {
   1186           // (x + y * (K << L)) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
   1187           node->ReplaceInput(0,
   1188                              Word32And(mleft.left().node(), m.right().node()));
   1189           node->ReplaceInput(1, mleftright.node());
   1190           NodeProperties::ChangeOp(node, machine()->Int32Add());
   1191           Reduction const reduction = ReduceInt32Add(node);
   1192           return reduction.Changed() ? reduction : Changed(node);
   1193         }
   1194       }
   1195       if (mleft.left().IsWord32Shl()) {
   1196         Int32BinopMatcher mleftleft(mleft.left().node());
   1197         if (mleftleft.right().Is(base::bits::CountTrailingZeros32(mask))) {
   1198           // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
   1199           node->ReplaceInput(0,
   1200                              Word32And(mleft.right().node(), m.right().node()));
   1201           node->ReplaceInput(1, mleftleft.node());
   1202           NodeProperties::ChangeOp(node, machine()->Int32Add());
   1203           Reduction const reduction = ReduceInt32Add(node);
   1204           return reduction.Changed() ? reduction : Changed(node);
   1205         }
   1206       }
   1207       if (mleft.right().IsWord32Shl()) {
   1208         Int32BinopMatcher mleftright(mleft.right().node());
   1209         if (mleftright.right().Is(base::bits::CountTrailingZeros32(mask))) {
   1210           // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
   1211           node->ReplaceInput(0,
   1212                              Word32And(mleft.left().node(), m.right().node()));
   1213           node->ReplaceInput(1, mleftright.node());
   1214           NodeProperties::ChangeOp(node, machine()->Int32Add());
   1215           Reduction const reduction = ReduceInt32Add(node);
   1216           return reduction.Changed() ? reduction : Changed(node);
   1217         }
   1218       }
   1219     } else if (m.left().IsInt32Mul()) {
   1220       Int32BinopMatcher mleft(m.left().node());
   1221       if (mleft.right().IsMultipleOf(-mask)) {
   1222         // (x * (K << L)) & (-1 << L) => x * (K << L)
   1223         return Replace(mleft.node());
   1224       }
   1225     }
   1226   }
   1227   return NoChange();
   1228 }
   1229 
   1230 Reduction MachineOperatorReducer::TryMatchWord32Ror(Node* node) {
   1231   DCHECK(IrOpcode::kWord32Or == node->opcode() ||
   1232          IrOpcode::kWord32Xor == node->opcode());
   1233   Int32BinopMatcher m(node);
   1234   Node* shl = nullptr;
   1235   Node* shr = nullptr;
   1236   // Recognize rotation, we are matching:
   1237   //  * x << y | x >>> (32 - y) => x ror (32 - y), i.e  x rol y
   1238   //  * x << (32 - y) | x >>> y => x ror y
   1239   //  * x << y ^ x >>> (32 - y) => x ror (32 - y), i.e. x rol y
   1240   //  * x << (32 - y) ^ x >>> y => x ror y
   1241   // as well as their commuted form.
   1242   if (m.left().IsWord32Shl() && m.right().IsWord32Shr()) {
   1243     shl = m.left().node();
   1244     shr = m.right().node();
   1245   } else if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) {
   1246     shl = m.right().node();
   1247     shr = m.left().node();
   1248   } else {
   1249     return NoChange();
   1250   }
   1251 
   1252   Int32BinopMatcher mshl(shl);
   1253   Int32BinopMatcher mshr(shr);
   1254   if (mshl.left().node() != mshr.left().node()) return NoChange();
   1255 
   1256   if (mshl.right().HasValue() && mshr.right().HasValue()) {
   1257     // Case where y is a constant.
   1258     if (mshl.right().Value() + mshr.right().Value() != 32) return NoChange();
   1259   } else {
   1260     Node* sub = nullptr;
   1261     Node* y = nullptr;
   1262     if (mshl.right().IsInt32Sub()) {
   1263       sub = mshl.right().node();
   1264       y = mshr.right().node();
   1265     } else if (mshr.right().IsInt32Sub()) {
   1266       sub = mshr.right().node();
   1267       y = mshl.right().node();
   1268     } else {
   1269       return NoChange();
   1270     }
   1271 
   1272     Int32BinopMatcher msub(sub);
   1273     if (!msub.left().Is(32) || msub.right().node() != y) return NoChange();
   1274   }
   1275 
   1276   node->ReplaceInput(0, mshl.left().node());
   1277   node->ReplaceInput(1, mshr.right().node());
   1278   NodeProperties::ChangeOp(node, machine()->Word32Ror());
   1279   return Changed(node);
   1280 }
   1281 
   1282 Reduction MachineOperatorReducer::ReduceWord32Or(Node* node) {
   1283   DCHECK_EQ(IrOpcode::kWord32Or, node->opcode());
   1284   Int32BinopMatcher m(node);
   1285   if (m.right().Is(0)) return Replace(m.left().node());    // x | 0  => x
   1286   if (m.right().Is(-1)) return Replace(m.right().node());  // x | -1 => -1
   1287   if (m.IsFoldable()) {                                    // K | K  => K
   1288     return ReplaceInt32(m.left().Value() | m.right().Value());
   1289   }
   1290   if (m.LeftEqualsRight()) return Replace(m.left().node());  // x | x => x
   1291 
   1292   return TryMatchWord32Ror(node);
   1293 }
   1294 
   1295 Reduction MachineOperatorReducer::ReduceWord32Xor(Node* node) {
   1296   DCHECK_EQ(IrOpcode::kWord32Xor, node->opcode());
   1297   Int32BinopMatcher m(node);
   1298   if (m.right().Is(0)) return Replace(m.left().node());  // x ^ 0 => x
   1299   if (m.IsFoldable()) {                                  // K ^ K => K
   1300     return ReplaceInt32(m.left().Value() ^ m.right().Value());
   1301   }
   1302   if (m.LeftEqualsRight()) return ReplaceInt32(0);  // x ^ x => 0
   1303   if (m.left().IsWord32Xor() && m.right().Is(-1)) {
   1304     Int32BinopMatcher mleft(m.left().node());
   1305     if (mleft.right().Is(-1)) {  // (x ^ -1) ^ -1 => x
   1306       return Replace(mleft.left().node());
   1307     }
   1308   }
   1309 
   1310   return TryMatchWord32Ror(node);
   1311 }
   1312 
   1313 Reduction MachineOperatorReducer::ReduceFloat64InsertLowWord32(Node* node) {
   1314   DCHECK_EQ(IrOpcode::kFloat64InsertLowWord32, node->opcode());
   1315   Float64Matcher mlhs(node->InputAt(0));
   1316   Uint32Matcher mrhs(node->InputAt(1));
   1317   if (mlhs.HasValue() && mrhs.HasValue()) {
   1318     return ReplaceFloat64(bit_cast<double>(
   1319         (bit_cast<uint64_t>(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF00000000)) |
   1320         mrhs.Value()));
   1321   }
   1322   return NoChange();
   1323 }
   1324 
   1325 
   1326 Reduction MachineOperatorReducer::ReduceFloat64InsertHighWord32(Node* node) {
   1327   DCHECK_EQ(IrOpcode::kFloat64InsertHighWord32, node->opcode());
   1328   Float64Matcher mlhs(node->InputAt(0));
   1329   Uint32Matcher mrhs(node->InputAt(1));
   1330   if (mlhs.HasValue() && mrhs.HasValue()) {
   1331     return ReplaceFloat64(bit_cast<double>(
   1332         (bit_cast<uint64_t>(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF)) |
   1333         (static_cast<uint64_t>(mrhs.Value()) << 32)));
   1334   }
   1335   return NoChange();
   1336 }
   1337 
   1338 
   1339 namespace {
   1340 
   1341 bool IsFloat64RepresentableAsFloat32(const Float64Matcher& m) {
   1342   if (m.HasValue()) {
   1343     double v = m.Value();
   1344     float fv = static_cast<float>(v);
   1345     return static_cast<double>(fv) == v;
   1346   }
   1347   return false;
   1348 }
   1349 
   1350 }  // namespace
   1351 
   1352 
   1353 Reduction MachineOperatorReducer::ReduceFloat64Compare(Node* node) {
   1354   DCHECK((IrOpcode::kFloat64Equal == node->opcode()) ||
   1355          (IrOpcode::kFloat64LessThan == node->opcode()) ||
   1356          (IrOpcode::kFloat64LessThanOrEqual == node->opcode()));
   1357   // As all Float32 values have an exact representation in Float64, comparing
   1358   // two Float64 values both converted from Float32 is equivalent to comparing
   1359   // the original Float32s, so we can ignore the conversions. We can also reduce
   1360   // comparisons of converted Float64 values against constants that can be
   1361   // represented exactly as Float32.
   1362   Float64BinopMatcher m(node);
   1363   if ((m.left().IsChangeFloat32ToFloat64() &&
   1364        m.right().IsChangeFloat32ToFloat64()) ||
   1365       (m.left().IsChangeFloat32ToFloat64() &&
   1366        IsFloat64RepresentableAsFloat32(m.right())) ||
   1367       (IsFloat64RepresentableAsFloat32(m.left()) &&
   1368        m.right().IsChangeFloat32ToFloat64())) {
   1369     switch (node->opcode()) {
   1370       case IrOpcode::kFloat64Equal:
   1371         NodeProperties::ChangeOp(node, machine()->Float32Equal());
   1372         break;
   1373       case IrOpcode::kFloat64LessThan:
   1374         NodeProperties::ChangeOp(node, machine()->Float32LessThan());
   1375         break;
   1376       case IrOpcode::kFloat64LessThanOrEqual:
   1377         NodeProperties::ChangeOp(node, machine()->Float32LessThanOrEqual());
   1378         break;
   1379       default:
   1380         return NoChange();
   1381     }
   1382     node->ReplaceInput(
   1383         0, m.left().HasValue()
   1384                ? Float32Constant(static_cast<float>(m.left().Value()))
   1385                : m.left().InputAt(0));
   1386     node->ReplaceInput(
   1387         1, m.right().HasValue()
   1388                ? Float32Constant(static_cast<float>(m.right().Value()))
   1389                : m.right().InputAt(0));
   1390     return Changed(node);
   1391   }
   1392   return NoChange();
   1393 }
   1394 
   1395 
   1396 CommonOperatorBuilder* MachineOperatorReducer::common() const {
   1397   return jsgraph()->common();
   1398 }
   1399 
   1400 
   1401 MachineOperatorBuilder* MachineOperatorReducer::machine() const {
   1402   return jsgraph()->machine();
   1403 }
   1404 
   1405 
   1406 Graph* MachineOperatorReducer::graph() const { return jsgraph()->graph(); }
   1407 
   1408 }  // namespace compiler
   1409 }  // namespace internal
   1410 }  // namespace v8
   1411