Home | History | Annotate | Download | only in x64
      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 <algorithm>
      6 
      7 #include "src/base/adapters.h"
      8 #include "src/compiler/instruction-selector-impl.h"
      9 #include "src/compiler/node-matchers.h"
     10 #include "src/compiler/node-properties.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 namespace compiler {
     15 
     16 // Adds X64-specific methods for generating operands.
     17 class X64OperandGenerator final : public OperandGenerator {
     18  public:
     19   explicit X64OperandGenerator(InstructionSelector* selector)
     20       : OperandGenerator(selector) {}
     21 
     22   bool CanBeImmediate(Node* node) {
     23     switch (node->opcode()) {
     24       case IrOpcode::kInt32Constant:
     25         return true;
     26       case IrOpcode::kInt64Constant: {
     27         const int64_t value = OpParameter<int64_t>(node);
     28         return value == static_cast<int64_t>(static_cast<int32_t>(value));
     29       }
     30       case IrOpcode::kNumberConstant: {
     31         const double value = OpParameter<double>(node);
     32         return bit_cast<int64_t>(value) == 0;
     33       }
     34       default:
     35         return false;
     36     }
     37   }
     38 
     39   AddressingMode GenerateMemoryOperandInputs(Node* index, int scale_exponent,
     40                                              Node* base, Node* displacement,
     41                                              InstructionOperand inputs[],
     42                                              size_t* input_count) {
     43     AddressingMode mode = kMode_MRI;
     44     if (base != nullptr) {
     45       inputs[(*input_count)++] = UseRegister(base);
     46       if (index != nullptr) {
     47         DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
     48         inputs[(*input_count)++] = UseRegister(index);
     49         if (displacement != nullptr) {
     50           inputs[(*input_count)++] = UseImmediate(displacement);
     51           static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
     52                                                        kMode_MR4I, kMode_MR8I};
     53           mode = kMRnI_modes[scale_exponent];
     54         } else {
     55           static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2,
     56                                                       kMode_MR4, kMode_MR8};
     57           mode = kMRn_modes[scale_exponent];
     58         }
     59       } else {
     60         if (displacement == nullptr) {
     61           mode = kMode_MR;
     62         } else {
     63           inputs[(*input_count)++] = UseImmediate(displacement);
     64           mode = kMode_MRI;
     65         }
     66       }
     67     } else {
     68       DCHECK_NOT_NULL(index);
     69       DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
     70       inputs[(*input_count)++] = UseRegister(index);
     71       if (displacement != nullptr) {
     72         inputs[(*input_count)++] = UseImmediate(displacement);
     73         static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I,
     74                                                     kMode_M4I, kMode_M8I};
     75         mode = kMnI_modes[scale_exponent];
     76       } else {
     77         static const AddressingMode kMn_modes[] = {kMode_MR, kMode_MR1,
     78                                                    kMode_M4, kMode_M8};
     79         mode = kMn_modes[scale_exponent];
     80         if (mode == kMode_MR1) {
     81           // [%r1 + %r1*1] has a smaller encoding than [%r1*2+0]
     82           inputs[(*input_count)++] = UseRegister(index);
     83         }
     84       }
     85     }
     86     return mode;
     87   }
     88 
     89   AddressingMode GetEffectiveAddressMemoryOperand(Node* operand,
     90                                                   InstructionOperand inputs[],
     91                                                   size_t* input_count) {
     92     BaseWithIndexAndDisplacement64Matcher m(operand, true);
     93     DCHECK(m.matches());
     94     if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) {
     95       return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(),
     96                                          m.displacement(), inputs, input_count);
     97     } else {
     98       inputs[(*input_count)++] = UseRegister(operand->InputAt(0));
     99       inputs[(*input_count)++] = UseRegister(operand->InputAt(1));
    100       return kMode_MR1;
    101     }
    102   }
    103 
    104   bool CanBeBetterLeftOperand(Node* node) const {
    105     return !selector()->IsLive(node);
    106   }
    107 };
    108 
    109 
    110 void InstructionSelector::VisitLoad(Node* node) {
    111   LoadRepresentation load_rep = LoadRepresentationOf(node->op());
    112   X64OperandGenerator g(this);
    113 
    114   ArchOpcode opcode = kArchNop;
    115   switch (load_rep.representation()) {
    116     case MachineRepresentation::kFloat32:
    117       opcode = kX64Movss;
    118       break;
    119     case MachineRepresentation::kFloat64:
    120       opcode = kX64Movsd;
    121       break;
    122     case MachineRepresentation::kBit:  // Fall through.
    123     case MachineRepresentation::kWord8:
    124       opcode = load_rep.IsSigned() ? kX64Movsxbl : kX64Movzxbl;
    125       break;
    126     case MachineRepresentation::kWord16:
    127       opcode = load_rep.IsSigned() ? kX64Movsxwl : kX64Movzxwl;
    128       break;
    129     case MachineRepresentation::kWord32:
    130       opcode = kX64Movl;
    131       break;
    132     case MachineRepresentation::kTagged:  // Fall through.
    133     case MachineRepresentation::kWord64:
    134       opcode = kX64Movq;
    135       break;
    136     case MachineRepresentation::kNone:
    137       UNREACHABLE();
    138       return;
    139   }
    140 
    141   InstructionOperand outputs[1];
    142   outputs[0] = g.DefineAsRegister(node);
    143   InstructionOperand inputs[3];
    144   size_t input_count = 0;
    145   AddressingMode mode =
    146       g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
    147   InstructionCode code = opcode | AddressingModeField::encode(mode);
    148   Emit(code, 1, outputs, input_count, inputs);
    149 }
    150 
    151 
    152 void InstructionSelector::VisitStore(Node* node) {
    153   X64OperandGenerator g(this);
    154   Node* base = node->InputAt(0);
    155   Node* index = node->InputAt(1);
    156   Node* value = node->InputAt(2);
    157 
    158   StoreRepresentation store_rep = StoreRepresentationOf(node->op());
    159   WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
    160   MachineRepresentation rep = store_rep.representation();
    161 
    162   if (write_barrier_kind != kNoWriteBarrier) {
    163     DCHECK_EQ(MachineRepresentation::kTagged, rep);
    164     AddressingMode addressing_mode;
    165     InstructionOperand inputs[3];
    166     size_t input_count = 0;
    167     inputs[input_count++] = g.UseUniqueRegister(base);
    168     if (g.CanBeImmediate(index)) {
    169       inputs[input_count++] = g.UseImmediate(index);
    170       addressing_mode = kMode_MRI;
    171     } else {
    172       inputs[input_count++] = g.UseUniqueRegister(index);
    173       addressing_mode = kMode_MR1;
    174     }
    175     inputs[input_count++] = (write_barrier_kind == kMapWriteBarrier)
    176                                 ? g.UseRegister(value)
    177                                 : g.UseUniqueRegister(value);
    178     RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
    179     switch (write_barrier_kind) {
    180       case kNoWriteBarrier:
    181         UNREACHABLE();
    182         break;
    183       case kMapWriteBarrier:
    184         record_write_mode = RecordWriteMode::kValueIsMap;
    185         break;
    186       case kPointerWriteBarrier:
    187         record_write_mode = RecordWriteMode::kValueIsPointer;
    188         break;
    189       case kFullWriteBarrier:
    190         record_write_mode = RecordWriteMode::kValueIsAny;
    191         break;
    192     }
    193     InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
    194     size_t const temp_count = arraysize(temps);
    195     InstructionCode code = kArchStoreWithWriteBarrier;
    196     code |= AddressingModeField::encode(addressing_mode);
    197     code |= MiscField::encode(static_cast<int>(record_write_mode));
    198     Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
    199   } else {
    200     ArchOpcode opcode = kArchNop;
    201     switch (rep) {
    202       case MachineRepresentation::kFloat32:
    203         opcode = kX64Movss;
    204         break;
    205       case MachineRepresentation::kFloat64:
    206         opcode = kX64Movsd;
    207         break;
    208       case MachineRepresentation::kBit:  // Fall through.
    209       case MachineRepresentation::kWord8:
    210         opcode = kX64Movb;
    211         break;
    212       case MachineRepresentation::kWord16:
    213         opcode = kX64Movw;
    214         break;
    215       case MachineRepresentation::kWord32:
    216         opcode = kX64Movl;
    217         break;
    218       case MachineRepresentation::kTagged:  // Fall through.
    219       case MachineRepresentation::kWord64:
    220         opcode = kX64Movq;
    221         break;
    222       case MachineRepresentation::kNone:
    223         UNREACHABLE();
    224         return;
    225     }
    226     InstructionOperand inputs[4];
    227     size_t input_count = 0;
    228     AddressingMode addressing_mode =
    229         g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
    230     InstructionCode code =
    231         opcode | AddressingModeField::encode(addressing_mode);
    232     InstructionOperand value_operand =
    233         g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value);
    234     inputs[input_count++] = value_operand;
    235     Emit(code, 0, static_cast<InstructionOperand*>(nullptr), input_count,
    236          inputs);
    237   }
    238 }
    239 
    240 
    241 void InstructionSelector::VisitCheckedLoad(Node* node) {
    242   CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
    243   X64OperandGenerator g(this);
    244   Node* const buffer = node->InputAt(0);
    245   Node* const offset = node->InputAt(1);
    246   Node* const length = node->InputAt(2);
    247   ArchOpcode opcode = kArchNop;
    248   switch (load_rep.representation()) {
    249     case MachineRepresentation::kWord8:
    250       opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
    251       break;
    252     case MachineRepresentation::kWord16:
    253       opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
    254       break;
    255     case MachineRepresentation::kWord32:
    256       opcode = kCheckedLoadWord32;
    257       break;
    258     case MachineRepresentation::kWord64:
    259       opcode = kCheckedLoadWord64;
    260       break;
    261     case MachineRepresentation::kFloat32:
    262       opcode = kCheckedLoadFloat32;
    263       break;
    264     case MachineRepresentation::kFloat64:
    265       opcode = kCheckedLoadFloat64;
    266       break;
    267     case MachineRepresentation::kBit:
    268     case MachineRepresentation::kTagged:
    269     case MachineRepresentation::kNone:
    270       UNREACHABLE();
    271       return;
    272   }
    273   if (offset->opcode() == IrOpcode::kInt32Add && CanCover(node, offset)) {
    274     Int32Matcher mlength(length);
    275     Int32BinopMatcher moffset(offset);
    276     if (mlength.HasValue() && moffset.right().HasValue() &&
    277         moffset.right().Value() >= 0 &&
    278         mlength.Value() >= moffset.right().Value()) {
    279       Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer),
    280            g.UseRegister(moffset.left().node()),
    281            g.UseImmediate(moffset.right().node()), g.UseImmediate(length));
    282       return;
    283     }
    284   }
    285   InstructionOperand length_operand =
    286       g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
    287   Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer),
    288        g.UseRegister(offset), g.TempImmediate(0), length_operand);
    289 }
    290 
    291 
    292 void InstructionSelector::VisitCheckedStore(Node* node) {
    293   MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
    294   X64OperandGenerator g(this);
    295   Node* const buffer = node->InputAt(0);
    296   Node* const offset = node->InputAt(1);
    297   Node* const length = node->InputAt(2);
    298   Node* const value = node->InputAt(3);
    299   ArchOpcode opcode = kArchNop;
    300   switch (rep) {
    301     case MachineRepresentation::kWord8:
    302       opcode = kCheckedStoreWord8;
    303       break;
    304     case MachineRepresentation::kWord16:
    305       opcode = kCheckedStoreWord16;
    306       break;
    307     case MachineRepresentation::kWord32:
    308       opcode = kCheckedStoreWord32;
    309       break;
    310     case MachineRepresentation::kWord64:
    311       opcode = kCheckedStoreWord64;
    312       break;
    313     case MachineRepresentation::kFloat32:
    314       opcode = kCheckedStoreFloat32;
    315       break;
    316     case MachineRepresentation::kFloat64:
    317       opcode = kCheckedStoreFloat64;
    318       break;
    319     case MachineRepresentation::kBit:
    320     case MachineRepresentation::kTagged:
    321     case MachineRepresentation::kNone:
    322       UNREACHABLE();
    323       return;
    324   }
    325   InstructionOperand value_operand =
    326       g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value);
    327   if (offset->opcode() == IrOpcode::kInt32Add && CanCover(node, offset)) {
    328     Int32Matcher mlength(length);
    329     Int32BinopMatcher moffset(offset);
    330     if (mlength.HasValue() && moffset.right().HasValue() &&
    331         moffset.right().Value() >= 0 &&
    332         mlength.Value() >= moffset.right().Value()) {
    333       Emit(opcode, g.NoOutput(), g.UseRegister(buffer),
    334            g.UseRegister(moffset.left().node()),
    335            g.UseImmediate(moffset.right().node()), g.UseImmediate(length),
    336            value_operand);
    337       return;
    338     }
    339   }
    340   InstructionOperand length_operand =
    341       g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
    342   Emit(opcode, g.NoOutput(), g.UseRegister(buffer), g.UseRegister(offset),
    343        g.TempImmediate(0), length_operand, value_operand);
    344 }
    345 
    346 
    347 // Shared routine for multiple binary operations.
    348 static void VisitBinop(InstructionSelector* selector, Node* node,
    349                        InstructionCode opcode, FlagsContinuation* cont) {
    350   X64OperandGenerator g(selector);
    351   Int32BinopMatcher m(node);
    352   Node* left = m.left().node();
    353   Node* right = m.right().node();
    354   InstructionOperand inputs[4];
    355   size_t input_count = 0;
    356   InstructionOperand outputs[2];
    357   size_t output_count = 0;
    358 
    359   // TODO(turbofan): match complex addressing modes.
    360   if (left == right) {
    361     // If both inputs refer to the same operand, enforce allocating a register
    362     // for both of them to ensure that we don't end up generating code like
    363     // this:
    364     //
    365     //   mov rax, [rbp-0x10]
    366     //   add rax, [rbp-0x10]
    367     //   jo label
    368     InstructionOperand const input = g.UseRegister(left);
    369     inputs[input_count++] = input;
    370     inputs[input_count++] = input;
    371   } else if (g.CanBeImmediate(right)) {
    372     inputs[input_count++] = g.UseRegister(left);
    373     inputs[input_count++] = g.UseImmediate(right);
    374   } else {
    375     if (node->op()->HasProperty(Operator::kCommutative) &&
    376         g.CanBeBetterLeftOperand(right)) {
    377       std::swap(left, right);
    378     }
    379     inputs[input_count++] = g.UseRegister(left);
    380     inputs[input_count++] = g.Use(right);
    381   }
    382 
    383   if (cont->IsBranch()) {
    384     inputs[input_count++] = g.Label(cont->true_block());
    385     inputs[input_count++] = g.Label(cont->false_block());
    386   }
    387 
    388   outputs[output_count++] = g.DefineSameAsFirst(node);
    389   if (cont->IsSet()) {
    390     outputs[output_count++] = g.DefineAsRegister(cont->result());
    391   }
    392 
    393   DCHECK_NE(0u, input_count);
    394   DCHECK_NE(0u, output_count);
    395   DCHECK_GE(arraysize(inputs), input_count);
    396   DCHECK_GE(arraysize(outputs), output_count);
    397 
    398   selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
    399                  inputs);
    400 }
    401 
    402 
    403 // Shared routine for multiple binary operations.
    404 static void VisitBinop(InstructionSelector* selector, Node* node,
    405                        InstructionCode opcode) {
    406   FlagsContinuation cont;
    407   VisitBinop(selector, node, opcode, &cont);
    408 }
    409 
    410 
    411 void InstructionSelector::VisitWord32And(Node* node) {
    412   X64OperandGenerator g(this);
    413   Uint32BinopMatcher m(node);
    414   if (m.right().Is(0xff)) {
    415     Emit(kX64Movzxbl, g.DefineAsRegister(node), g.Use(m.left().node()));
    416   } else if (m.right().Is(0xffff)) {
    417     Emit(kX64Movzxwl, g.DefineAsRegister(node), g.Use(m.left().node()));
    418   } else {
    419     VisitBinop(this, node, kX64And32);
    420   }
    421 }
    422 
    423 
    424 void InstructionSelector::VisitWord64And(Node* node) {
    425   VisitBinop(this, node, kX64And);
    426 }
    427 
    428 
    429 void InstructionSelector::VisitWord32Or(Node* node) {
    430   VisitBinop(this, node, kX64Or32);
    431 }
    432 
    433 
    434 void InstructionSelector::VisitWord64Or(Node* node) {
    435   VisitBinop(this, node, kX64Or);
    436 }
    437 
    438 
    439 void InstructionSelector::VisitWord32Xor(Node* node) {
    440   X64OperandGenerator g(this);
    441   Uint32BinopMatcher m(node);
    442   if (m.right().Is(-1)) {
    443     Emit(kX64Not32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()));
    444   } else {
    445     VisitBinop(this, node, kX64Xor32);
    446   }
    447 }
    448 
    449 
    450 void InstructionSelector::VisitWord64Xor(Node* node) {
    451   X64OperandGenerator g(this);
    452   Uint64BinopMatcher m(node);
    453   if (m.right().Is(-1)) {
    454     Emit(kX64Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()));
    455   } else {
    456     VisitBinop(this, node, kX64Xor);
    457   }
    458 }
    459 
    460 
    461 namespace {
    462 
    463 // Shared routine for multiple 32-bit shift operations.
    464 // TODO(bmeurer): Merge this with VisitWord64Shift using template magic?
    465 void VisitWord32Shift(InstructionSelector* selector, Node* node,
    466                       ArchOpcode opcode) {
    467   X64OperandGenerator g(selector);
    468   Int32BinopMatcher m(node);
    469   Node* left = m.left().node();
    470   Node* right = m.right().node();
    471 
    472   if (g.CanBeImmediate(right)) {
    473     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
    474                    g.UseImmediate(right));
    475   } else {
    476     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
    477                    g.UseFixed(right, rcx));
    478   }
    479 }
    480 
    481 
    482 // Shared routine for multiple 64-bit shift operations.
    483 // TODO(bmeurer): Merge this with VisitWord32Shift using template magic?
    484 void VisitWord64Shift(InstructionSelector* selector, Node* node,
    485                       ArchOpcode opcode) {
    486   X64OperandGenerator g(selector);
    487   Int64BinopMatcher m(node);
    488   Node* left = m.left().node();
    489   Node* right = m.right().node();
    490 
    491   if (g.CanBeImmediate(right)) {
    492     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
    493                    g.UseImmediate(right));
    494   } else {
    495     if (m.right().IsWord64And()) {
    496       Int64BinopMatcher mright(right);
    497       if (mright.right().Is(0x3F)) {
    498         right = mright.left().node();
    499       }
    500     }
    501     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
    502                    g.UseFixed(right, rcx));
    503   }
    504 }
    505 
    506 
    507 void EmitLea(InstructionSelector* selector, InstructionCode opcode,
    508              Node* result, Node* index, int scale, Node* base,
    509              Node* displacement) {
    510   X64OperandGenerator g(selector);
    511 
    512   InstructionOperand inputs[4];
    513   size_t input_count = 0;
    514   AddressingMode mode = g.GenerateMemoryOperandInputs(
    515       index, scale, base, displacement, inputs, &input_count);
    516 
    517   DCHECK_NE(0u, input_count);
    518   DCHECK_GE(arraysize(inputs), input_count);
    519 
    520   InstructionOperand outputs[1];
    521   outputs[0] = g.DefineAsRegister(result);
    522 
    523   opcode = AddressingModeField::encode(mode) | opcode;
    524 
    525   selector->Emit(opcode, 1, outputs, input_count, inputs);
    526 }
    527 
    528 }  // namespace
    529 
    530 
    531 void InstructionSelector::VisitWord32Shl(Node* node) {
    532   Int32ScaleMatcher m(node, true);
    533   if (m.matches()) {
    534     Node* index = node->InputAt(0);
    535     Node* base = m.power_of_two_plus_one() ? index : nullptr;
    536     EmitLea(this, kX64Lea32, node, index, m.scale(), base, nullptr);
    537     return;
    538   }
    539   VisitWord32Shift(this, node, kX64Shl32);
    540 }
    541 
    542 
    543 void InstructionSelector::VisitWord64Shl(Node* node) {
    544   X64OperandGenerator g(this);
    545   Int64BinopMatcher m(node);
    546   if ((m.left().IsChangeInt32ToInt64() || m.left().IsChangeUint32ToUint64()) &&
    547       m.right().IsInRange(32, 63)) {
    548     // There's no need to sign/zero-extend to 64-bit if we shift out the upper
    549     // 32 bits anyway.
    550     Emit(kX64Shl, g.DefineSameAsFirst(node),
    551          g.UseRegister(m.left().node()->InputAt(0)),
    552          g.UseImmediate(m.right().node()));
    553     return;
    554   }
    555   VisitWord64Shift(this, node, kX64Shl);
    556 }
    557 
    558 
    559 void InstructionSelector::VisitWord32Shr(Node* node) {
    560   VisitWord32Shift(this, node, kX64Shr32);
    561 }
    562 
    563 
    564 void InstructionSelector::VisitWord64Shr(Node* node) {
    565   VisitWord64Shift(this, node, kX64Shr);
    566 }
    567 
    568 
    569 void InstructionSelector::VisitWord32Sar(Node* node) {
    570   X64OperandGenerator g(this);
    571   Int32BinopMatcher m(node);
    572   if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
    573     Int32BinopMatcher mleft(m.left().node());
    574     if (mleft.right().Is(16) && m.right().Is(16)) {
    575       Emit(kX64Movsxwl, g.DefineAsRegister(node), g.Use(mleft.left().node()));
    576       return;
    577     } else if (mleft.right().Is(24) && m.right().Is(24)) {
    578       Emit(kX64Movsxbl, g.DefineAsRegister(node), g.Use(mleft.left().node()));
    579       return;
    580     }
    581   }
    582   VisitWord32Shift(this, node, kX64Sar32);
    583 }
    584 
    585 
    586 void InstructionSelector::VisitWord64Sar(Node* node) {
    587   VisitWord64Shift(this, node, kX64Sar);
    588 }
    589 
    590 
    591 void InstructionSelector::VisitWord32Ror(Node* node) {
    592   VisitWord32Shift(this, node, kX64Ror32);
    593 }
    594 
    595 
    596 void InstructionSelector::VisitWord64Ror(Node* node) {
    597   VisitWord64Shift(this, node, kX64Ror);
    598 }
    599 
    600 
    601 void InstructionSelector::VisitWord64Clz(Node* node) {
    602   X64OperandGenerator g(this);
    603   Emit(kX64Lzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    604 }
    605 
    606 
    607 void InstructionSelector::VisitWord32Clz(Node* node) {
    608   X64OperandGenerator g(this);
    609   Emit(kX64Lzcnt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    610 }
    611 
    612 
    613 void InstructionSelector::VisitWord64Ctz(Node* node) {
    614   X64OperandGenerator g(this);
    615   Emit(kX64Tzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    616 }
    617 
    618 
    619 void InstructionSelector::VisitWord32Ctz(Node* node) {
    620   X64OperandGenerator g(this);
    621   Emit(kX64Tzcnt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    622 }
    623 
    624 
    625 void InstructionSelector::VisitWord32Popcnt(Node* node) {
    626   X64OperandGenerator g(this);
    627   Emit(kX64Popcnt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    628 }
    629 
    630 
    631 void InstructionSelector::VisitWord64Popcnt(Node* node) {
    632   X64OperandGenerator g(this);
    633   Emit(kX64Popcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    634 }
    635 
    636 
    637 void InstructionSelector::VisitInt32Add(Node* node) {
    638   X64OperandGenerator g(this);
    639 
    640   // Try to match the Add to a leal pattern
    641   BaseWithIndexAndDisplacement32Matcher m(node);
    642   if (m.matches() &&
    643       (m.displacement() == nullptr || g.CanBeImmediate(m.displacement()))) {
    644     EmitLea(this, kX64Lea32, node, m.index(), m.scale(), m.base(),
    645             m.displacement());
    646     return;
    647   }
    648 
    649   // No leal pattern match, use addl
    650   VisitBinop(this, node, kX64Add32);
    651 }
    652 
    653 
    654 void InstructionSelector::VisitInt64Add(Node* node) {
    655   VisitBinop(this, node, kX64Add);
    656 }
    657 
    658 
    659 void InstructionSelector::VisitInt64AddWithOverflow(Node* node) {
    660   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
    661     FlagsContinuation cont(kOverflow, ovf);
    662     VisitBinop(this, node, kX64Add, &cont);
    663   }
    664   FlagsContinuation cont;
    665   VisitBinop(this, node, kX64Add, &cont);
    666 }
    667 
    668 
    669 void InstructionSelector::VisitInt32Sub(Node* node) {
    670   X64OperandGenerator g(this);
    671   Int32BinopMatcher m(node);
    672   if (m.left().Is(0)) {
    673     Emit(kX64Neg32, g.DefineSameAsFirst(node), g.UseRegister(m.right().node()));
    674   } else {
    675     if (m.right().HasValue() && g.CanBeImmediate(m.right().node())) {
    676       // Turn subtractions of constant values into immediate "leal" instructions
    677       // by negating the value.
    678       Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI),
    679            g.DefineAsRegister(node), g.UseRegister(m.left().node()),
    680            g.TempImmediate(-m.right().Value()));
    681       return;
    682     }
    683     VisitBinop(this, node, kX64Sub32);
    684   }
    685 }
    686 
    687 
    688 void InstructionSelector::VisitInt64Sub(Node* node) {
    689   X64OperandGenerator g(this);
    690   Int64BinopMatcher m(node);
    691   if (m.left().Is(0)) {
    692     Emit(kX64Neg, g.DefineSameAsFirst(node), g.UseRegister(m.right().node()));
    693   } else {
    694     VisitBinop(this, node, kX64Sub);
    695   }
    696 }
    697 
    698 
    699 void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
    700   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
    701     FlagsContinuation cont(kOverflow, ovf);
    702     return VisitBinop(this, node, kX64Sub, &cont);
    703   }
    704   FlagsContinuation cont;
    705   VisitBinop(this, node, kX64Sub, &cont);
    706 }
    707 
    708 
    709 namespace {
    710 
    711 void VisitMul(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
    712   X64OperandGenerator g(selector);
    713   Int32BinopMatcher m(node);
    714   Node* left = m.left().node();
    715   Node* right = m.right().node();
    716   if (g.CanBeImmediate(right)) {
    717     selector->Emit(opcode, g.DefineAsRegister(node), g.Use(left),
    718                    g.UseImmediate(right));
    719   } else {
    720     if (g.CanBeBetterLeftOperand(right)) {
    721       std::swap(left, right);
    722     }
    723     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
    724                    g.Use(right));
    725   }
    726 }
    727 
    728 
    729 void VisitMulHigh(InstructionSelector* selector, Node* node,
    730                   ArchOpcode opcode) {
    731   X64OperandGenerator g(selector);
    732   Node* left = node->InputAt(0);
    733   Node* right = node->InputAt(1);
    734   if (selector->IsLive(left) && !selector->IsLive(right)) {
    735     std::swap(left, right);
    736   }
    737   // TODO(turbofan): We use UseUniqueRegister here to improve register
    738   // allocation.
    739   selector->Emit(opcode, g.DefineAsFixed(node, rdx), g.UseFixed(left, rax),
    740                  g.UseUniqueRegister(right));
    741 }
    742 
    743 
    744 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
    745   X64OperandGenerator g(selector);
    746   InstructionOperand temps[] = {g.TempRegister(rdx)};
    747   selector->Emit(
    748       opcode, g.DefineAsFixed(node, rax), g.UseFixed(node->InputAt(0), rax),
    749       g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
    750 }
    751 
    752 
    753 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
    754   X64OperandGenerator g(selector);
    755   selector->Emit(opcode, g.DefineAsFixed(node, rdx),
    756                  g.UseFixed(node->InputAt(0), rax),
    757                  g.UseUniqueRegister(node->InputAt(1)));
    758 }
    759 
    760 }  // namespace
    761 
    762 
    763 void InstructionSelector::VisitInt32Mul(Node* node) {
    764   Int32ScaleMatcher m(node, true);
    765   if (m.matches()) {
    766     Node* index = node->InputAt(0);
    767     Node* base = m.power_of_two_plus_one() ? index : nullptr;
    768     EmitLea(this, kX64Lea32, node, index, m.scale(), base, nullptr);
    769     return;
    770   }
    771   VisitMul(this, node, kX64Imul32);
    772 }
    773 
    774 
    775 void InstructionSelector::VisitInt64Mul(Node* node) {
    776   VisitMul(this, node, kX64Imul);
    777 }
    778 
    779 
    780 void InstructionSelector::VisitInt32MulHigh(Node* node) {
    781   VisitMulHigh(this, node, kX64ImulHigh32);
    782 }
    783 
    784 
    785 void InstructionSelector::VisitInt32Div(Node* node) {
    786   VisitDiv(this, node, kX64Idiv32);
    787 }
    788 
    789 
    790 void InstructionSelector::VisitInt64Div(Node* node) {
    791   VisitDiv(this, node, kX64Idiv);
    792 }
    793 
    794 
    795 void InstructionSelector::VisitUint32Div(Node* node) {
    796   VisitDiv(this, node, kX64Udiv32);
    797 }
    798 
    799 
    800 void InstructionSelector::VisitUint64Div(Node* node) {
    801   VisitDiv(this, node, kX64Udiv);
    802 }
    803 
    804 
    805 void InstructionSelector::VisitInt32Mod(Node* node) {
    806   VisitMod(this, node, kX64Idiv32);
    807 }
    808 
    809 
    810 void InstructionSelector::VisitInt64Mod(Node* node) {
    811   VisitMod(this, node, kX64Idiv);
    812 }
    813 
    814 
    815 void InstructionSelector::VisitUint32Mod(Node* node) {
    816   VisitMod(this, node, kX64Udiv32);
    817 }
    818 
    819 
    820 void InstructionSelector::VisitUint64Mod(Node* node) {
    821   VisitMod(this, node, kX64Udiv);
    822 }
    823 
    824 
    825 void InstructionSelector::VisitUint32MulHigh(Node* node) {
    826   VisitMulHigh(this, node, kX64UmulHigh32);
    827 }
    828 
    829 
    830 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
    831   X64OperandGenerator g(this);
    832   Emit(kSSEFloat32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    833 }
    834 
    835 
    836 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
    837   X64OperandGenerator g(this);
    838   Emit(kSSEInt32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    839 }
    840 
    841 
    842 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
    843   X64OperandGenerator g(this);
    844   Emit(kSSEUint32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    845 }
    846 
    847 
    848 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
    849   X64OperandGenerator g(this);
    850   Emit(kSSEFloat64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    851 }
    852 
    853 
    854 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
    855   X64OperandGenerator g(this);
    856   Emit(kSSEFloat64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    857 }
    858 
    859 
    860 void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
    861   X64OperandGenerator g(this);
    862   InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
    863   InstructionOperand outputs[2];
    864   size_t output_count = 0;
    865   outputs[output_count++] = g.DefineAsRegister(node);
    866 
    867   Node* success_output = NodeProperties::FindProjection(node, 1);
    868   if (success_output) {
    869     outputs[output_count++] = g.DefineAsRegister(success_output);
    870   }
    871 
    872   Emit(kSSEFloat32ToInt64, output_count, outputs, 1, inputs);
    873 }
    874 
    875 
    876 void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) {
    877   X64OperandGenerator g(this);
    878   InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
    879   InstructionOperand outputs[2];
    880   size_t output_count = 0;
    881   outputs[output_count++] = g.DefineAsRegister(node);
    882 
    883   Node* success_output = NodeProperties::FindProjection(node, 1);
    884   if (success_output) {
    885     outputs[output_count++] = g.DefineAsRegister(success_output);
    886   }
    887 
    888   Emit(kSSEFloat64ToInt64, output_count, outputs, 1, inputs);
    889 }
    890 
    891 
    892 void InstructionSelector::VisitTryTruncateFloat32ToUint64(Node* node) {
    893   X64OperandGenerator g(this);
    894   InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
    895   InstructionOperand outputs[2];
    896   size_t output_count = 0;
    897   outputs[output_count++] = g.DefineAsRegister(node);
    898 
    899   Node* success_output = NodeProperties::FindProjection(node, 1);
    900   if (success_output) {
    901     outputs[output_count++] = g.DefineAsRegister(success_output);
    902   }
    903 
    904   Emit(kSSEFloat32ToUint64, output_count, outputs, 1, inputs);
    905 }
    906 
    907 
    908 void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) {
    909   X64OperandGenerator g(this);
    910   InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
    911   InstructionOperand outputs[2];
    912   size_t output_count = 0;
    913   outputs[output_count++] = g.DefineAsRegister(node);
    914 
    915   Node* success_output = NodeProperties::FindProjection(node, 1);
    916   if (success_output) {
    917     outputs[output_count++] = g.DefineAsRegister(success_output);
    918   }
    919 
    920   Emit(kSSEFloat64ToUint64, output_count, outputs, 1, inputs);
    921 }
    922 
    923 
    924 void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
    925   X64OperandGenerator g(this);
    926   Emit(kX64Movsxlq, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    927 }
    928 
    929 
    930 void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
    931   X64OperandGenerator g(this);
    932   Node* value = node->InputAt(0);
    933   switch (value->opcode()) {
    934     case IrOpcode::kWord32And:
    935     case IrOpcode::kWord32Or:
    936     case IrOpcode::kWord32Xor:
    937     case IrOpcode::kWord32Shl:
    938     case IrOpcode::kWord32Shr:
    939     case IrOpcode::kWord32Sar:
    940     case IrOpcode::kWord32Ror:
    941     case IrOpcode::kWord32Equal:
    942     case IrOpcode::kInt32Add:
    943     case IrOpcode::kInt32Sub:
    944     case IrOpcode::kInt32Mul:
    945     case IrOpcode::kInt32MulHigh:
    946     case IrOpcode::kInt32Div:
    947     case IrOpcode::kInt32LessThan:
    948     case IrOpcode::kInt32LessThanOrEqual:
    949     case IrOpcode::kInt32Mod:
    950     case IrOpcode::kUint32Div:
    951     case IrOpcode::kUint32LessThan:
    952     case IrOpcode::kUint32LessThanOrEqual:
    953     case IrOpcode::kUint32Mod:
    954     case IrOpcode::kUint32MulHigh: {
    955       // These 32-bit operations implicitly zero-extend to 64-bit on x64, so the
    956       // zero-extension is a no-op.
    957       Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
    958       return;
    959     }
    960     default:
    961       break;
    962   }
    963   Emit(kX64Movl, g.DefineAsRegister(node), g.Use(value));
    964 }
    965 
    966 
    967 namespace {
    968 
    969 void VisitRO(InstructionSelector* selector, Node* node,
    970              InstructionCode opcode) {
    971   X64OperandGenerator g(selector);
    972   selector->Emit(opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
    973 }
    974 
    975 
    976 void VisitRR(InstructionSelector* selector, Node* node,
    977              InstructionCode opcode) {
    978   X64OperandGenerator g(selector);
    979   selector->Emit(opcode, g.DefineAsRegister(node),
    980                  g.UseRegister(node->InputAt(0)));
    981 }
    982 
    983 
    984 void VisitFloatBinop(InstructionSelector* selector, Node* node,
    985                      ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
    986   X64OperandGenerator g(selector);
    987   InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
    988   InstructionOperand operand1 = g.Use(node->InputAt(1));
    989   if (selector->IsSupported(AVX)) {
    990     selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0, operand1);
    991   } else {
    992     selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1);
    993   }
    994 }
    995 
    996 
    997 void VisitFloatUnop(InstructionSelector* selector, Node* node, Node* input,
    998                     ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
    999   X64OperandGenerator g(selector);
   1000   if (selector->IsSupported(AVX)) {
   1001     selector->Emit(avx_opcode, g.DefineAsRegister(node), g.Use(input));
   1002   } else {
   1003     selector->Emit(sse_opcode, g.DefineSameAsFirst(node), g.UseRegister(input));
   1004   }
   1005 }
   1006 
   1007 }  // namespace
   1008 
   1009 
   1010 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
   1011   VisitRO(this, node, kSSEFloat64ToFloat32);
   1012 }
   1013 
   1014 
   1015 void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
   1016   switch (TruncationModeOf(node->op())) {
   1017     case TruncationMode::kJavaScript:
   1018       return VisitRR(this, node, kArchTruncateDoubleToI);
   1019     case TruncationMode::kRoundToZero:
   1020       return VisitRO(this, node, kSSEFloat64ToInt32);
   1021   }
   1022   UNREACHABLE();
   1023 }
   1024 
   1025 
   1026 void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
   1027   X64OperandGenerator g(this);
   1028   Node* value = node->InputAt(0);
   1029   if (CanCover(node, value)) {
   1030     switch (value->opcode()) {
   1031       case IrOpcode::kWord64Sar:
   1032       case IrOpcode::kWord64Shr: {
   1033         Int64BinopMatcher m(value);
   1034         if (m.right().Is(32)) {
   1035           Emit(kX64Shr, g.DefineSameAsFirst(node),
   1036                g.UseRegister(m.left().node()), g.TempImmediate(32));
   1037           return;
   1038         }
   1039         break;
   1040       }
   1041       default:
   1042         break;
   1043     }
   1044   }
   1045   Emit(kX64Movl, g.DefineAsRegister(node), g.Use(value));
   1046 }
   1047 
   1048 
   1049 void InstructionSelector::VisitRoundInt64ToFloat32(Node* node) {
   1050   X64OperandGenerator g(this);
   1051   Emit(kSSEInt64ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
   1052 }
   1053 
   1054 
   1055 void InstructionSelector::VisitRoundInt64ToFloat64(Node* node) {
   1056   X64OperandGenerator g(this);
   1057   Emit(kSSEInt64ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
   1058 }
   1059 
   1060 
   1061 void InstructionSelector::VisitRoundUint64ToFloat32(Node* node) {
   1062   X64OperandGenerator g(this);
   1063   InstructionOperand temps[] = {g.TempRegister()};
   1064   Emit(kSSEUint64ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)),
   1065        arraysize(temps), temps);
   1066 }
   1067 
   1068 
   1069 void InstructionSelector::VisitRoundUint64ToFloat64(Node* node) {
   1070   X64OperandGenerator g(this);
   1071   InstructionOperand temps[] = {g.TempRegister()};
   1072   Emit(kSSEUint64ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)),
   1073        arraysize(temps), temps);
   1074 }
   1075 
   1076 
   1077 void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
   1078   X64OperandGenerator g(this);
   1079   Emit(kX64BitcastFI, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
   1080 }
   1081 
   1082 
   1083 void InstructionSelector::VisitBitcastFloat64ToInt64(Node* node) {
   1084   X64OperandGenerator g(this);
   1085   Emit(kX64BitcastDL, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
   1086 }
   1087 
   1088 
   1089 void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
   1090   X64OperandGenerator g(this);
   1091   Emit(kX64BitcastIF, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
   1092 }
   1093 
   1094 
   1095 void InstructionSelector::VisitBitcastInt64ToFloat64(Node* node) {
   1096   X64OperandGenerator g(this);
   1097   Emit(kX64BitcastLD, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
   1098 }
   1099 
   1100 
   1101 void InstructionSelector::VisitFloat32Add(Node* node) {
   1102   VisitFloatBinop(this, node, kAVXFloat32Add, kSSEFloat32Add);
   1103 }
   1104 
   1105 
   1106 void InstructionSelector::VisitFloat32Sub(Node* node) {
   1107   X64OperandGenerator g(this);
   1108   Float32BinopMatcher m(node);
   1109   if (m.left().IsMinusZero()) {
   1110     VisitFloatUnop(this, node, m.right().node(), kAVXFloat32Neg,
   1111                    kSSEFloat32Neg);
   1112     return;
   1113   }
   1114   VisitFloatBinop(this, node, kAVXFloat32Sub, kSSEFloat32Sub);
   1115 }
   1116 
   1117 
   1118 void InstructionSelector::VisitFloat32Mul(Node* node) {
   1119   VisitFloatBinop(this, node, kAVXFloat32Mul, kSSEFloat32Mul);
   1120 }
   1121 
   1122 
   1123 void InstructionSelector::VisitFloat32Div(Node* node) {
   1124   VisitFloatBinop(this, node, kAVXFloat32Div, kSSEFloat32Div);
   1125 }
   1126 
   1127 
   1128 void InstructionSelector::VisitFloat32Max(Node* node) {
   1129   VisitFloatBinop(this, node, kAVXFloat32Max, kSSEFloat32Max);
   1130 }
   1131 
   1132 
   1133 void InstructionSelector::VisitFloat32Min(Node* node) {
   1134   VisitFloatBinop(this, node, kAVXFloat32Min, kSSEFloat32Min);
   1135 }
   1136 
   1137 
   1138 void InstructionSelector::VisitFloat32Abs(Node* node) {
   1139   VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat32Abs, kSSEFloat32Abs);
   1140 }
   1141 
   1142 
   1143 void InstructionSelector::VisitFloat32Sqrt(Node* node) {
   1144   VisitRO(this, node, kSSEFloat32Sqrt);
   1145 }
   1146 
   1147 
   1148 void InstructionSelector::VisitFloat64Add(Node* node) {
   1149   VisitFloatBinop(this, node, kAVXFloat64Add, kSSEFloat64Add);
   1150 }
   1151 
   1152 
   1153 void InstructionSelector::VisitFloat64Sub(Node* node) {
   1154   X64OperandGenerator g(this);
   1155   Float64BinopMatcher m(node);
   1156   if (m.left().IsMinusZero()) {
   1157     if (m.right().IsFloat64RoundDown() &&
   1158         CanCover(m.node(), m.right().node())) {
   1159       if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
   1160           CanCover(m.right().node(), m.right().InputAt(0))) {
   1161         Float64BinopMatcher mright0(m.right().InputAt(0));
   1162         if (mright0.left().IsMinusZero()) {
   1163           Emit(kSSEFloat64Round | MiscField::encode(kRoundUp),
   1164                g.DefineAsRegister(node), g.UseRegister(mright0.right().node()));
   1165           return;
   1166         }
   1167       }
   1168     }
   1169     VisitFloatUnop(this, node, m.right().node(), kAVXFloat64Neg,
   1170                    kSSEFloat64Neg);
   1171     return;
   1172   }
   1173   VisitFloatBinop(this, node, kAVXFloat64Sub, kSSEFloat64Sub);
   1174 }
   1175 
   1176 
   1177 void InstructionSelector::VisitFloat64Mul(Node* node) {
   1178   VisitFloatBinop(this, node, kAVXFloat64Mul, kSSEFloat64Mul);
   1179 }
   1180 
   1181 
   1182 void InstructionSelector::VisitFloat64Div(Node* node) {
   1183   VisitFloatBinop(this, node, kAVXFloat64Div, kSSEFloat64Div);
   1184 }
   1185 
   1186 
   1187 void InstructionSelector::VisitFloat64Mod(Node* node) {
   1188   X64OperandGenerator g(this);
   1189   InstructionOperand temps[] = {g.TempRegister(rax)};
   1190   Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node),
   1191        g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1,
   1192        temps);
   1193 }
   1194 
   1195 
   1196 void InstructionSelector::VisitFloat64Max(Node* node) {
   1197   VisitFloatBinop(this, node, kAVXFloat64Max, kSSEFloat64Max);
   1198 }
   1199 
   1200 
   1201 void InstructionSelector::VisitFloat64Min(Node* node) {
   1202   VisitFloatBinop(this, node, kAVXFloat64Min, kSSEFloat64Min);
   1203 }
   1204 
   1205 
   1206 void InstructionSelector::VisitFloat64Abs(Node* node) {
   1207   VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat64Abs, kSSEFloat64Abs);
   1208 }
   1209 
   1210 
   1211 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
   1212   VisitRO(this, node, kSSEFloat64Sqrt);
   1213 }
   1214 
   1215 
   1216 void InstructionSelector::VisitFloat32RoundDown(Node* node) {
   1217   VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundDown));
   1218 }
   1219 
   1220 
   1221 void InstructionSelector::VisitFloat64RoundDown(Node* node) {
   1222   VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundDown));
   1223 }
   1224 
   1225 
   1226 void InstructionSelector::VisitFloat32RoundUp(Node* node) {
   1227   VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundUp));
   1228 }
   1229 
   1230 
   1231 void InstructionSelector::VisitFloat64RoundUp(Node* node) {
   1232   VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundUp));
   1233 }
   1234 
   1235 
   1236 void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
   1237   VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundToZero));
   1238 }
   1239 
   1240 
   1241 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
   1242   VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToZero));
   1243 }
   1244 
   1245 
   1246 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
   1247   UNREACHABLE();
   1248 }
   1249 
   1250 
   1251 void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
   1252   VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundToNearest));
   1253 }
   1254 
   1255 
   1256 void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
   1257   VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToNearest));
   1258 }
   1259 
   1260 
   1261 void InstructionSelector::EmitPrepareArguments(
   1262     ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
   1263     Node* node) {
   1264   X64OperandGenerator g(this);
   1265 
   1266   // Prepare for C function call.
   1267   if (descriptor->IsCFunctionCall()) {
   1268     Emit(kArchPrepareCallCFunction |
   1269              MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
   1270          0, nullptr, 0, nullptr);
   1271 
   1272     // Poke any stack arguments.
   1273     for (size_t n = 0; n < arguments->size(); ++n) {
   1274       PushParameter input = (*arguments)[n];
   1275       if (input.node()) {
   1276         int slot = static_cast<int>(n);
   1277         InstructionOperand value = g.CanBeImmediate(input.node())
   1278                                        ? g.UseImmediate(input.node())
   1279                                        : g.UseRegister(input.node());
   1280         Emit(kX64Poke | MiscField::encode(slot), g.NoOutput(), value);
   1281       }
   1282     }
   1283   } else {
   1284     // Push any stack arguments.
   1285     for (PushParameter input : base::Reversed(*arguments)) {
   1286       // TODO(titzer): X64Push cannot handle stack->stack double moves
   1287       // because there is no way to encode fixed double slots.
   1288       InstructionOperand value =
   1289           g.CanBeImmediate(input.node())
   1290               ? g.UseImmediate(input.node())
   1291               : IsSupported(ATOM) ||
   1292                         sequence()->IsFloat(GetVirtualRegister(input.node()))
   1293                     ? g.UseRegister(input.node())
   1294                     : g.Use(input.node());
   1295       Emit(kX64Push, g.NoOutput(), value);
   1296     }
   1297   }
   1298 }
   1299 
   1300 
   1301 bool InstructionSelector::IsTailCallAddressImmediate() { return true; }
   1302 
   1303 
   1304 namespace {
   1305 
   1306 // Shared routine for multiple compare operations.
   1307 void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
   1308                   InstructionOperand left, InstructionOperand right,
   1309                   FlagsContinuation* cont) {
   1310   X64OperandGenerator g(selector);
   1311   opcode = cont->Encode(opcode);
   1312   if (cont->IsBranch()) {
   1313     selector->Emit(opcode, g.NoOutput(), left, right,
   1314                    g.Label(cont->true_block()), g.Label(cont->false_block()));
   1315   } else {
   1316     DCHECK(cont->IsSet());
   1317     selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
   1318   }
   1319 }
   1320 
   1321 
   1322 // Shared routine for multiple compare operations.
   1323 void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
   1324                   Node* left, Node* right, FlagsContinuation* cont,
   1325                   bool commutative) {
   1326   X64OperandGenerator g(selector);
   1327   if (commutative && g.CanBeBetterLeftOperand(right)) {
   1328     std::swap(left, right);
   1329   }
   1330   VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
   1331 }
   1332 
   1333 
   1334 // Shared routine for multiple word compare operations.
   1335 void VisitWordCompare(InstructionSelector* selector, Node* node,
   1336                       InstructionCode opcode, FlagsContinuation* cont) {
   1337   X64OperandGenerator g(selector);
   1338   Node* const left = node->InputAt(0);
   1339   Node* const right = node->InputAt(1);
   1340 
   1341   // Match immediates on left or right side of comparison.
   1342   if (g.CanBeImmediate(right)) {
   1343     VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont);
   1344   } else if (g.CanBeImmediate(left)) {
   1345     if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
   1346     VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont);
   1347   } else {
   1348     VisitCompare(selector, opcode, left, right, cont,
   1349                  node->op()->HasProperty(Operator::kCommutative));
   1350   }
   1351 }
   1352 
   1353 
   1354 // Shared routine for 64-bit word comparison operations.
   1355 void VisitWord64Compare(InstructionSelector* selector, Node* node,
   1356                         FlagsContinuation* cont) {
   1357   X64OperandGenerator g(selector);
   1358   Int64BinopMatcher m(node);
   1359   if (m.left().IsLoad() && m.right().IsLoadStackPointer()) {
   1360     LoadMatcher<ExternalReferenceMatcher> mleft(m.left().node());
   1361     ExternalReference js_stack_limit =
   1362         ExternalReference::address_of_stack_limit(selector->isolate());
   1363     if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) {
   1364       // Compare(Load(js_stack_limit), LoadStackPointer)
   1365       if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
   1366       InstructionCode opcode = cont->Encode(kX64StackCheck);
   1367       if (cont->IsBranch()) {
   1368         selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()),
   1369                        g.Label(cont->false_block()));
   1370       } else {
   1371         DCHECK(cont->IsSet());
   1372         selector->Emit(opcode, g.DefineAsRegister(cont->result()));
   1373       }
   1374       return;
   1375     }
   1376   }
   1377   VisitWordCompare(selector, node, kX64Cmp, cont);
   1378 }
   1379 
   1380 
   1381 // Shared routine for comparison with zero.
   1382 void VisitCompareZero(InstructionSelector* selector, Node* node,
   1383                       InstructionCode opcode, FlagsContinuation* cont) {
   1384   X64OperandGenerator g(selector);
   1385   VisitCompare(selector, opcode, g.Use(node), g.TempImmediate(0), cont);
   1386 }
   1387 
   1388 
   1389 // Shared routine for multiple float32 compare operations (inputs commuted).
   1390 void VisitFloat32Compare(InstructionSelector* selector, Node* node,
   1391                          FlagsContinuation* cont) {
   1392   Node* const left = node->InputAt(0);
   1393   Node* const right = node->InputAt(1);
   1394   InstructionCode const opcode =
   1395       selector->IsSupported(AVX) ? kAVXFloat32Cmp : kSSEFloat32Cmp;
   1396   VisitCompare(selector, opcode, right, left, cont, false);
   1397 }
   1398 
   1399 
   1400 // Shared routine for multiple float64 compare operations (inputs commuted).
   1401 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
   1402                          FlagsContinuation* cont) {
   1403   Node* const left = node->InputAt(0);
   1404   Node* const right = node->InputAt(1);
   1405   InstructionCode const opcode =
   1406       selector->IsSupported(AVX) ? kAVXFloat64Cmp : kSSEFloat64Cmp;
   1407   VisitCompare(selector, opcode, right, left, cont, false);
   1408 }
   1409 
   1410 }  // namespace
   1411 
   1412 
   1413 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
   1414                                       BasicBlock* fbranch) {
   1415   X64OperandGenerator g(this);
   1416   Node* user = branch;
   1417   Node* value = branch->InputAt(0);
   1418 
   1419   FlagsContinuation cont(kNotEqual, tbranch, fbranch);
   1420 
   1421   // Try to combine with comparisons against 0 by simply inverting the branch.
   1422   while (CanCover(user, value) && value->opcode() == IrOpcode::kWord32Equal) {
   1423     Int32BinopMatcher m(value);
   1424     if (m.right().Is(0)) {
   1425       user = value;
   1426       value = m.left().node();
   1427       cont.Negate();
   1428     } else {
   1429       break;
   1430     }
   1431   }
   1432 
   1433   // Try to combine the branch with a comparison.
   1434   if (CanCover(user, value)) {
   1435     switch (value->opcode()) {
   1436       case IrOpcode::kWord32Equal:
   1437         cont.OverwriteAndNegateIfEqual(kEqual);
   1438         return VisitWordCompare(this, value, kX64Cmp32, &cont);
   1439       case IrOpcode::kInt32LessThan:
   1440         cont.OverwriteAndNegateIfEqual(kSignedLessThan);
   1441         return VisitWordCompare(this, value, kX64Cmp32, &cont);
   1442       case IrOpcode::kInt32LessThanOrEqual:
   1443         cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
   1444         return VisitWordCompare(this, value, kX64Cmp32, &cont);
   1445       case IrOpcode::kUint32LessThan:
   1446         cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
   1447         return VisitWordCompare(this, value, kX64Cmp32, &cont);
   1448       case IrOpcode::kUint32LessThanOrEqual:
   1449         cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
   1450         return VisitWordCompare(this, value, kX64Cmp32, &cont);
   1451       case IrOpcode::kWord64Equal: {
   1452         cont.OverwriteAndNegateIfEqual(kEqual);
   1453         Int64BinopMatcher m(value);
   1454         if (m.right().Is(0)) {
   1455           // Try to combine the branch with a comparison.
   1456           Node* const user = m.node();
   1457           Node* const value = m.left().node();
   1458           if (CanCover(user, value)) {
   1459             switch (value->opcode()) {
   1460               case IrOpcode::kInt64Sub:
   1461                 return VisitWord64Compare(this, value, &cont);
   1462               case IrOpcode::kWord64And:
   1463                 return VisitWordCompare(this, value, kX64Test, &cont);
   1464               default:
   1465                 break;
   1466             }
   1467           }
   1468           return VisitCompareZero(this, value, kX64Cmp, &cont);
   1469         }
   1470         return VisitWord64Compare(this, value, &cont);
   1471       }
   1472       case IrOpcode::kInt64LessThan:
   1473         cont.OverwriteAndNegateIfEqual(kSignedLessThan);
   1474         return VisitWord64Compare(this, value, &cont);
   1475       case IrOpcode::kInt64LessThanOrEqual:
   1476         cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
   1477         return VisitWord64Compare(this, value, &cont);
   1478       case IrOpcode::kUint64LessThan:
   1479         cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
   1480         return VisitWord64Compare(this, value, &cont);
   1481       case IrOpcode::kUint64LessThanOrEqual:
   1482         cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
   1483         return VisitWord64Compare(this, value, &cont);
   1484       case IrOpcode::kFloat32Equal:
   1485         cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
   1486         return VisitFloat32Compare(this, value, &cont);
   1487       case IrOpcode::kFloat32LessThan:
   1488         cont.OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
   1489         return VisitFloat32Compare(this, value, &cont);
   1490       case IrOpcode::kFloat32LessThanOrEqual:
   1491         cont.OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
   1492         return VisitFloat32Compare(this, value, &cont);
   1493       case IrOpcode::kFloat64Equal:
   1494         cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
   1495         return VisitFloat64Compare(this, value, &cont);
   1496       case IrOpcode::kFloat64LessThan:
   1497         cont.OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
   1498         return VisitFloat64Compare(this, value, &cont);
   1499       case IrOpcode::kFloat64LessThanOrEqual:
   1500         cont.OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
   1501         return VisitFloat64Compare(this, value, &cont);
   1502       case IrOpcode::kProjection:
   1503         // Check if this is the overflow output projection of an
   1504         // <Operation>WithOverflow node.
   1505         if (ProjectionIndexOf(value->op()) == 1u) {
   1506           // We cannot combine the <Operation>WithOverflow with this branch
   1507           // unless the 0th projection (the use of the actual value of the
   1508           // <Operation> is either nullptr, which means there's no use of the
   1509           // actual value, or was already defined, which means it is scheduled
   1510           // *AFTER* this branch).
   1511           Node* const node = value->InputAt(0);
   1512           Node* const result = NodeProperties::FindProjection(node, 0);
   1513           if (result == nullptr || IsDefined(result)) {
   1514             switch (node->opcode()) {
   1515               case IrOpcode::kInt32AddWithOverflow:
   1516                 cont.OverwriteAndNegateIfEqual(kOverflow);
   1517                 return VisitBinop(this, node, kX64Add32, &cont);
   1518               case IrOpcode::kInt32SubWithOverflow:
   1519                 cont.OverwriteAndNegateIfEqual(kOverflow);
   1520                 return VisitBinop(this, node, kX64Sub32, &cont);
   1521               case IrOpcode::kInt64AddWithOverflow:
   1522                 cont.OverwriteAndNegateIfEqual(kOverflow);
   1523                 return VisitBinop(this, node, kX64Add, &cont);
   1524               case IrOpcode::kInt64SubWithOverflow:
   1525                 cont.OverwriteAndNegateIfEqual(kOverflow);
   1526                 return VisitBinop(this, node, kX64Sub, &cont);
   1527               default:
   1528                 break;
   1529             }
   1530           }
   1531         }
   1532         break;
   1533       case IrOpcode::kInt32Sub:
   1534         return VisitWordCompare(this, value, kX64Cmp32, &cont);
   1535       case IrOpcode::kInt64Sub:
   1536         return VisitWord64Compare(this, value, &cont);
   1537       case IrOpcode::kWord32And:
   1538         return VisitWordCompare(this, value, kX64Test32, &cont);
   1539       case IrOpcode::kWord64And:
   1540         return VisitWordCompare(this, value, kX64Test, &cont);
   1541       default:
   1542         break;
   1543     }
   1544   }
   1545 
   1546   // Branch could not be combined with a compare, emit compare against 0.
   1547   VisitCompareZero(this, value, kX64Cmp32, &cont);
   1548 }
   1549 
   1550 
   1551 void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
   1552   X64OperandGenerator g(this);
   1553   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
   1554 
   1555   // Emit either ArchTableSwitch or ArchLookupSwitch.
   1556   size_t table_space_cost = 4 + sw.value_range;
   1557   size_t table_time_cost = 3;
   1558   size_t lookup_space_cost = 3 + 2 * sw.case_count;
   1559   size_t lookup_time_cost = sw.case_count;
   1560   if (sw.case_count > 4 &&
   1561       table_space_cost + 3 * table_time_cost <=
   1562           lookup_space_cost + 3 * lookup_time_cost &&
   1563       sw.min_value > std::numeric_limits<int32_t>::min()) {
   1564     InstructionOperand index_operand = g.TempRegister();
   1565     if (sw.min_value) {
   1566       // The leal automatically zero extends, so result is a valid 64-bit index.
   1567       Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI), index_operand,
   1568            value_operand, g.TempImmediate(-sw.min_value));
   1569     } else {
   1570       // Zero extend, because we use it as 64-bit index into the jump table.
   1571       Emit(kX64Movl, index_operand, value_operand);
   1572     }
   1573     // Generate a table lookup.
   1574     return EmitTableSwitch(sw, index_operand);
   1575   }
   1576 
   1577   // Generate a sequence of conditional jumps.
   1578   return EmitLookupSwitch(sw, value_operand);
   1579 }
   1580 
   1581 
   1582 void InstructionSelector::VisitWord32Equal(Node* const node) {
   1583   Node* user = node;
   1584   FlagsContinuation cont(kEqual, node);
   1585   Int32BinopMatcher m(user);
   1586   if (m.right().Is(0)) {
   1587     Node* value = m.left().node();
   1588 
   1589     // Try to combine with comparisons against 0 by simply inverting the branch.
   1590     while (CanCover(user, value) && value->opcode() == IrOpcode::kWord32Equal) {
   1591       Int32BinopMatcher m(value);
   1592       if (m.right().Is(0)) {
   1593         user = value;
   1594         value = m.left().node();
   1595         cont.Negate();
   1596       } else {
   1597         break;
   1598       }
   1599     }
   1600 
   1601     // Try to combine the branch with a comparison.
   1602     if (CanCover(user, value)) {
   1603       switch (value->opcode()) {
   1604         case IrOpcode::kInt32Sub:
   1605           return VisitWordCompare(this, value, kX64Cmp32, &cont);
   1606         case IrOpcode::kWord32And:
   1607           return VisitWordCompare(this, value, kX64Test32, &cont);
   1608         default:
   1609           break;
   1610       }
   1611     }
   1612     return VisitCompareZero(this, value, kX64Cmp32, &cont);
   1613   }
   1614   VisitWordCompare(this, node, kX64Cmp32, &cont);
   1615 }
   1616 
   1617 
   1618 void InstructionSelector::VisitInt32LessThan(Node* node) {
   1619   FlagsContinuation cont(kSignedLessThan, node);
   1620   VisitWordCompare(this, node, kX64Cmp32, &cont);
   1621 }
   1622 
   1623 
   1624 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
   1625   FlagsContinuation cont(kSignedLessThanOrEqual, node);
   1626   VisitWordCompare(this, node, kX64Cmp32, &cont);
   1627 }
   1628 
   1629 
   1630 void InstructionSelector::VisitUint32LessThan(Node* node) {
   1631   FlagsContinuation cont(kUnsignedLessThan, node);
   1632   VisitWordCompare(this, node, kX64Cmp32, &cont);
   1633 }
   1634 
   1635 
   1636 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
   1637   FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
   1638   VisitWordCompare(this, node, kX64Cmp32, &cont);
   1639 }
   1640 
   1641 
   1642 void InstructionSelector::VisitWord64Equal(Node* const node) {
   1643   FlagsContinuation cont(kEqual, node);
   1644   Int64BinopMatcher m(node);
   1645   if (m.right().Is(0)) {
   1646     // Try to combine the equality check with a comparison.
   1647     Node* const user = m.node();
   1648     Node* const value = m.left().node();
   1649     if (CanCover(user, value)) {
   1650       switch (value->opcode()) {
   1651         case IrOpcode::kInt64Sub:
   1652           return VisitWord64Compare(this, value, &cont);
   1653         case IrOpcode::kWord64And:
   1654           return VisitWordCompare(this, value, kX64Test, &cont);
   1655         default:
   1656           break;
   1657       }
   1658     }
   1659   }
   1660   VisitWord64Compare(this, node, &cont);
   1661 }
   1662 
   1663 
   1664 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
   1665   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
   1666     FlagsContinuation cont(kOverflow, ovf);
   1667     VisitBinop(this, node, kX64Add32, &cont);
   1668   }
   1669   FlagsContinuation cont;
   1670   VisitBinop(this, node, kX64Add32, &cont);
   1671 }
   1672 
   1673 
   1674 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
   1675   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
   1676     FlagsContinuation cont(kOverflow, ovf);
   1677     return VisitBinop(this, node, kX64Sub32, &cont);
   1678   }
   1679   FlagsContinuation cont;
   1680   VisitBinop(this, node, kX64Sub32, &cont);
   1681 }
   1682 
   1683 
   1684 void InstructionSelector::VisitInt64LessThan(Node* node) {
   1685   FlagsContinuation cont(kSignedLessThan, node);
   1686   VisitWord64Compare(this, node, &cont);
   1687 }
   1688 
   1689 
   1690 void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
   1691   FlagsContinuation cont(kSignedLessThanOrEqual, node);
   1692   VisitWord64Compare(this, node, &cont);
   1693 }
   1694 
   1695 
   1696 void InstructionSelector::VisitUint64LessThan(Node* node) {
   1697   FlagsContinuation cont(kUnsignedLessThan, node);
   1698   VisitWord64Compare(this, node, &cont);
   1699 }
   1700 
   1701 
   1702 void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) {
   1703   FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
   1704   VisitWord64Compare(this, node, &cont);
   1705 }
   1706 
   1707 
   1708 void InstructionSelector::VisitFloat32Equal(Node* node) {
   1709   FlagsContinuation cont(kUnorderedEqual, node);
   1710   VisitFloat32Compare(this, node, &cont);
   1711 }
   1712 
   1713 
   1714 void InstructionSelector::VisitFloat32LessThan(Node* node) {
   1715   FlagsContinuation cont(kUnsignedGreaterThan, node);
   1716   VisitFloat32Compare(this, node, &cont);
   1717 }
   1718 
   1719 
   1720 void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
   1721   FlagsContinuation cont(kUnsignedGreaterThanOrEqual, node);
   1722   VisitFloat32Compare(this, node, &cont);
   1723 }
   1724 
   1725 
   1726 void InstructionSelector::VisitFloat64Equal(Node* node) {
   1727   FlagsContinuation cont(kUnorderedEqual, node);
   1728   VisitFloat64Compare(this, node, &cont);
   1729 }
   1730 
   1731 
   1732 void InstructionSelector::VisitFloat64LessThan(Node* node) {
   1733   FlagsContinuation cont(kUnsignedGreaterThan, node);
   1734   VisitFloat64Compare(this, node, &cont);
   1735 }
   1736 
   1737 
   1738 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
   1739   FlagsContinuation cont(kUnsignedGreaterThanOrEqual, node);
   1740   VisitFloat64Compare(this, node, &cont);
   1741 }
   1742 
   1743 
   1744 void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
   1745   X64OperandGenerator g(this);
   1746   Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node),
   1747        g.Use(node->InputAt(0)));
   1748 }
   1749 
   1750 
   1751 void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
   1752   X64OperandGenerator g(this);
   1753   Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node),
   1754        g.Use(node->InputAt(0)));
   1755 }
   1756 
   1757 
   1758 void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
   1759   X64OperandGenerator g(this);
   1760   Node* left = node->InputAt(0);
   1761   Node* right = node->InputAt(1);
   1762   Float64Matcher mleft(left);
   1763   if (mleft.HasValue() && (bit_cast<uint64_t>(mleft.Value()) >> 32) == 0u) {
   1764     Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right));
   1765     return;
   1766   }
   1767   Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node),
   1768        g.UseRegister(left), g.Use(right));
   1769 }
   1770 
   1771 
   1772 void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
   1773   X64OperandGenerator g(this);
   1774   Node* left = node->InputAt(0);
   1775   Node* right = node->InputAt(1);
   1776   Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node),
   1777        g.UseRegister(left), g.Use(right));
   1778 }
   1779 
   1780 
   1781 // static
   1782 MachineOperatorBuilder::Flags
   1783 InstructionSelector::SupportedMachineOperatorFlags() {
   1784   MachineOperatorBuilder::Flags flags =
   1785       MachineOperatorBuilder::kFloat32Max |
   1786       MachineOperatorBuilder::kFloat32Min |
   1787       MachineOperatorBuilder::kFloat64Max |
   1788       MachineOperatorBuilder::kFloat64Min |
   1789       MachineOperatorBuilder::kWord32ShiftIsSafe |
   1790       MachineOperatorBuilder::kWord32Ctz | MachineOperatorBuilder::kWord64Ctz;
   1791   if (CpuFeatures::IsSupported(POPCNT)) {
   1792     flags |= MachineOperatorBuilder::kWord32Popcnt |
   1793              MachineOperatorBuilder::kWord64Popcnt;
   1794   }
   1795   if (CpuFeatures::IsSupported(SSE4_1)) {
   1796     flags |= MachineOperatorBuilder::kFloat32RoundDown |
   1797              MachineOperatorBuilder::kFloat64RoundDown |
   1798              MachineOperatorBuilder::kFloat32RoundUp |
   1799              MachineOperatorBuilder::kFloat64RoundUp |
   1800              MachineOperatorBuilder::kFloat32RoundTruncate |
   1801              MachineOperatorBuilder::kFloat64RoundTruncate |
   1802              MachineOperatorBuilder::kFloat32RoundTiesEven |
   1803              MachineOperatorBuilder::kFloat64RoundTiesEven;
   1804   }
   1805   return flags;
   1806 }
   1807 
   1808 }  // namespace compiler
   1809 }  // namespace internal
   1810 }  // namespace v8
   1811