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