• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/base/adapters.h"
6 #include "src/compiler/instruction-selector-impl.h"
7 #include "src/compiler/node-matchers.h"
8 #include "src/compiler/node-properties.h"
9 
10 namespace v8 {
11 namespace internal {
12 namespace compiler {
13 
14 // Adds IA32-specific methods for generating operands.
15 class IA32OperandGenerator final : public OperandGenerator {
16  public:
IA32OperandGenerator(InstructionSelector * selector)17   explicit IA32OperandGenerator(InstructionSelector* selector)
18       : OperandGenerator(selector) {}
19 
UseByteRegister(Node * node)20   InstructionOperand UseByteRegister(Node* node) {
21     // TODO(titzer): encode byte register use constraints.
22     return UseFixed(node, edx);
23   }
24 
DefineAsByteRegister(Node * node)25   InstructionOperand DefineAsByteRegister(Node* node) {
26     // TODO(titzer): encode byte register def constraints.
27     return DefineAsRegister(node);
28   }
29 
CanBeMemoryOperand(InstructionCode opcode,Node * node,Node * input,int effect_level)30   bool CanBeMemoryOperand(InstructionCode opcode, Node* node, Node* input,
31                           int effect_level) {
32     if (input->opcode() != IrOpcode::kLoad ||
33         !selector()->CanCover(node, input)) {
34       return false;
35     }
36     if (effect_level != selector()->GetEffectLevel(input)) {
37       return false;
38     }
39     MachineRepresentation rep =
40         LoadRepresentationOf(input->op()).representation();
41     switch (opcode) {
42       case kIA32And:
43       case kIA32Or:
44       case kIA32Xor:
45       case kIA32Add:
46       case kIA32Sub:
47       case kIA32Cmp:
48       case kIA32Test:
49         return rep == MachineRepresentation::kWord32 || IsAnyTagged(rep);
50       case kIA32Cmp16:
51       case kIA32Test16:
52         return rep == MachineRepresentation::kWord16;
53       case kIA32Cmp8:
54       case kIA32Test8:
55         return rep == MachineRepresentation::kWord8;
56       default:
57         break;
58     }
59     return false;
60   }
61 
CanBeImmediate(Node * node)62   bool CanBeImmediate(Node* node) {
63     switch (node->opcode()) {
64       case IrOpcode::kInt32Constant:
65       case IrOpcode::kNumberConstant:
66       case IrOpcode::kExternalConstant:
67       case IrOpcode::kRelocatableInt32Constant:
68       case IrOpcode::kRelocatableInt64Constant:
69         return true;
70       case IrOpcode::kHeapConstant: {
71 // TODO(bmeurer): We must not dereference handles concurrently. If we
72 // really have to this here, then we need to find a way to put this
73 // information on the HeapConstant node already.
74 #if 0
75         // Constants in new space cannot be used as immediates in V8 because
76         // the GC does not scan code objects when collecting the new generation.
77         Handle<HeapObject> value = HeapConstantOf(node->op());
78         return !Heap::InNewSpace(*value);
79 #else
80         return false;
81 #endif
82       }
83       default:
84         return false;
85     }
86   }
87 
GenerateMemoryOperandInputs(Node * index,int scale,Node * base,Node * displacement_node,DisplacementMode displacement_mode,InstructionOperand inputs[],size_t * input_count)88   AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base,
89                                              Node* displacement_node,
90                                              DisplacementMode displacement_mode,
91                                              InstructionOperand inputs[],
92                                              size_t* input_count) {
93     AddressingMode mode = kMode_MRI;
94     int32_t displacement = (displacement_node == nullptr)
95                                ? 0
96                                : OpParameter<int32_t>(displacement_node->op());
97     if (displacement_mode == kNegativeDisplacement) {
98       displacement = -displacement;
99     }
100     if (base != nullptr) {
101       if (base->opcode() == IrOpcode::kInt32Constant) {
102         displacement += OpParameter<int32_t>(base->op());
103         base = nullptr;
104       }
105     }
106     if (base != nullptr) {
107       inputs[(*input_count)++] = UseRegister(base);
108       if (index != nullptr) {
109         DCHECK(scale >= 0 && scale <= 3);
110         inputs[(*input_count)++] = UseRegister(index);
111         if (displacement != 0) {
112           inputs[(*input_count)++] = TempImmediate(displacement);
113           static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
114                                                        kMode_MR4I, kMode_MR8I};
115           mode = kMRnI_modes[scale];
116         } else {
117           static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2,
118                                                       kMode_MR4, kMode_MR8};
119           mode = kMRn_modes[scale];
120         }
121       } else {
122         if (displacement == 0) {
123           mode = kMode_MR;
124         } else {
125           inputs[(*input_count)++] = TempImmediate(displacement);
126           mode = kMode_MRI;
127         }
128       }
129     } else {
130       DCHECK(scale >= 0 && scale <= 3);
131       if (index != nullptr) {
132         inputs[(*input_count)++] = UseRegister(index);
133         if (displacement != 0) {
134           inputs[(*input_count)++] = TempImmediate(displacement);
135           static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I,
136                                                       kMode_M4I, kMode_M8I};
137           mode = kMnI_modes[scale];
138         } else {
139           static const AddressingMode kMn_modes[] = {kMode_MR, kMode_M2,
140                                                      kMode_M4, kMode_M8};
141           mode = kMn_modes[scale];
142         }
143       } else {
144         inputs[(*input_count)++] = TempImmediate(displacement);
145         return kMode_MI;
146       }
147     }
148     return mode;
149   }
150 
GetEffectiveAddressMemoryOperand(Node * node,InstructionOperand inputs[],size_t * input_count)151   AddressingMode GetEffectiveAddressMemoryOperand(Node* node,
152                                                   InstructionOperand inputs[],
153                                                   size_t* input_count) {
154     BaseWithIndexAndDisplacement32Matcher m(node, AddressOption::kAllowAll);
155     DCHECK(m.matches());
156     if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) {
157       return GenerateMemoryOperandInputs(
158           m.index(), m.scale(), m.base(), m.displacement(),
159           m.displacement_mode(), inputs, input_count);
160     } else {
161       inputs[(*input_count)++] = UseRegister(node->InputAt(0));
162       inputs[(*input_count)++] = UseRegister(node->InputAt(1));
163       return kMode_MR1;
164     }
165   }
166 
GetEffectiveIndexOperand(Node * index,AddressingMode * mode)167   InstructionOperand GetEffectiveIndexOperand(Node* index,
168                                               AddressingMode* mode) {
169     if (CanBeImmediate(index)) {
170       *mode = kMode_MRI;
171       return UseImmediate(index);
172     } else {
173       *mode = kMode_MR1;
174       return UseUniqueRegister(index);
175     }
176   }
177 
CanBeBetterLeftOperand(Node * node) const178   bool CanBeBetterLeftOperand(Node* node) const {
179     return !selector()->IsLive(node);
180   }
181 };
182 
183 
184 namespace {
185 
VisitRO(InstructionSelector * selector,Node * node,ArchOpcode opcode)186 void VisitRO(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
187   IA32OperandGenerator g(selector);
188   selector->Emit(opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
189 }
190 
191 
VisitRR(InstructionSelector * selector,Node * node,InstructionCode opcode)192 void VisitRR(InstructionSelector* selector, Node* node,
193              InstructionCode opcode) {
194   IA32OperandGenerator g(selector);
195   selector->Emit(opcode, g.DefineAsRegister(node),
196                  g.UseRegister(node->InputAt(0)));
197 }
198 
199 
VisitRROFloat(InstructionSelector * selector,Node * node,ArchOpcode avx_opcode,ArchOpcode sse_opcode)200 void VisitRROFloat(InstructionSelector* selector, Node* node,
201                    ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
202   IA32OperandGenerator g(selector);
203   InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
204   InstructionOperand operand1 = g.Use(node->InputAt(1));
205   if (selector->IsSupported(AVX)) {
206     selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0, operand1);
207   } else {
208     selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1);
209   }
210 }
211 
212 
VisitFloatUnop(InstructionSelector * selector,Node * node,Node * input,ArchOpcode avx_opcode,ArchOpcode sse_opcode)213 void VisitFloatUnop(InstructionSelector* selector, Node* node, Node* input,
214                     ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
215   IA32OperandGenerator g(selector);
216   if (selector->IsSupported(AVX)) {
217     selector->Emit(avx_opcode, g.DefineAsRegister(node), g.Use(input));
218   } else {
219     selector->Emit(sse_opcode, g.DefineSameAsFirst(node), g.UseRegister(input));
220   }
221 }
222 
VisitRRSimd(InstructionSelector * selector,Node * node,ArchOpcode avx_opcode,ArchOpcode sse_opcode)223 void VisitRRSimd(InstructionSelector* selector, Node* node,
224                  ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
225   IA32OperandGenerator g(selector);
226   InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
227   if (selector->IsSupported(AVX)) {
228     selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0);
229   } else {
230     selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0);
231   }
232 }
233 
VisitRRISimd(InstructionSelector * selector,Node * node,ArchOpcode opcode)234 void VisitRRISimd(InstructionSelector* selector, Node* node,
235                   ArchOpcode opcode) {
236   IA32OperandGenerator g(selector);
237   InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
238   InstructionOperand operand1 =
239       g.UseImmediate(OpParameter<int32_t>(node->op()));
240   selector->Emit(opcode, g.DefineAsRegister(node), operand0, operand1);
241 }
242 
VisitRRISimd(InstructionSelector * selector,Node * node,ArchOpcode avx_opcode,ArchOpcode sse_opcode)243 void VisitRRISimd(InstructionSelector* selector, Node* node,
244                   ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
245   IA32OperandGenerator g(selector);
246   InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
247   InstructionOperand operand1 =
248       g.UseImmediate(OpParameter<int32_t>(node->op()));
249   if (selector->IsSupported(AVX)) {
250     selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0, operand1);
251   } else {
252     selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1);
253   }
254 }
255 
256 }  // namespace
257 
VisitStackSlot(Node * node)258 void InstructionSelector::VisitStackSlot(Node* node) {
259   StackSlotRepresentation rep = StackSlotRepresentationOf(node->op());
260   int slot = frame_->AllocateSpillSlot(rep.size());
261   OperandGenerator g(this);
262 
263   Emit(kArchStackSlot, g.DefineAsRegister(node),
264        sequence()->AddImmediate(Constant(slot)), 0, nullptr);
265 }
266 
VisitDebugAbort(Node * node)267 void InstructionSelector::VisitDebugAbort(Node* node) {
268   IA32OperandGenerator g(this);
269   Emit(kArchDebugAbort, g.NoOutput(), g.UseFixed(node->InputAt(0), edx));
270 }
271 
VisitSpeculationFence(Node * node)272 void InstructionSelector::VisitSpeculationFence(Node* node) {
273   IA32OperandGenerator g(this);
274   Emit(kLFence, g.NoOutput());
275 }
276 
VisitLoad(Node * node)277 void InstructionSelector::VisitLoad(Node* node) {
278   LoadRepresentation load_rep = LoadRepresentationOf(node->op());
279 
280   ArchOpcode opcode = kArchNop;
281   switch (load_rep.representation()) {
282     case MachineRepresentation::kFloat32:
283       opcode = kIA32Movss;
284       break;
285     case MachineRepresentation::kFloat64:
286       opcode = kIA32Movsd;
287       break;
288     case MachineRepresentation::kBit:  // Fall through.
289     case MachineRepresentation::kWord8:
290       opcode = load_rep.IsSigned() ? kIA32Movsxbl : kIA32Movzxbl;
291       break;
292     case MachineRepresentation::kWord16:
293       opcode = load_rep.IsSigned() ? kIA32Movsxwl : kIA32Movzxwl;
294       break;
295     case MachineRepresentation::kTaggedSigned:   // Fall through.
296     case MachineRepresentation::kTaggedPointer:  // Fall through.
297     case MachineRepresentation::kTagged:         // Fall through.
298     case MachineRepresentation::kWord32:
299       opcode = kIA32Movl;
300       break;
301     case MachineRepresentation::kSimd128:
302       opcode = kIA32Movdqu;
303       break;
304     case MachineRepresentation::kWord64:   // Fall through.
305     case MachineRepresentation::kNone:
306       UNREACHABLE();
307       return;
308   }
309 
310   IA32OperandGenerator g(this);
311   InstructionOperand outputs[1];
312   outputs[0] = g.DefineAsRegister(node);
313   InstructionOperand inputs[3];
314   size_t input_count = 0;
315   AddressingMode mode =
316       g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
317   InstructionCode code = opcode | AddressingModeField::encode(mode);
318   if (node->opcode() == IrOpcode::kPoisonedLoad) {
319     CHECK_NE(poisoning_level_, PoisoningMitigationLevel::kDontPoison);
320     code |= MiscField::encode(kMemoryAccessPoisoned);
321   }
322   Emit(code, 1, outputs, input_count, inputs);
323 }
324 
VisitPoisonedLoad(Node * node)325 void InstructionSelector::VisitPoisonedLoad(Node* node) { VisitLoad(node); }
326 
VisitProtectedLoad(Node * node)327 void InstructionSelector::VisitProtectedLoad(Node* node) {
328   // TODO(eholk)
329   UNIMPLEMENTED();
330 }
331 
VisitStore(Node * node)332 void InstructionSelector::VisitStore(Node* node) {
333   IA32OperandGenerator g(this);
334   Node* base = node->InputAt(0);
335   Node* index = node->InputAt(1);
336   Node* value = node->InputAt(2);
337 
338   StoreRepresentation store_rep = StoreRepresentationOf(node->op());
339   WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
340   MachineRepresentation rep = store_rep.representation();
341 
342   if (write_barrier_kind != kNoWriteBarrier) {
343     DCHECK(CanBeTaggedPointer(rep));
344     AddressingMode addressing_mode;
345     InstructionOperand inputs[] = {
346         g.UseUniqueRegister(base),
347         g.GetEffectiveIndexOperand(index, &addressing_mode),
348         g.UseUniqueRegister(value)};
349     RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
350     switch (write_barrier_kind) {
351       case kNoWriteBarrier:
352         UNREACHABLE();
353         break;
354       case kMapWriteBarrier:
355         record_write_mode = RecordWriteMode::kValueIsMap;
356         break;
357       case kPointerWriteBarrier:
358         record_write_mode = RecordWriteMode::kValueIsPointer;
359         break;
360       case kFullWriteBarrier:
361         record_write_mode = RecordWriteMode::kValueIsAny;
362         break;
363     }
364     InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
365     size_t const temp_count = arraysize(temps);
366     InstructionCode code = kArchStoreWithWriteBarrier;
367     code |= AddressingModeField::encode(addressing_mode);
368     code |= MiscField::encode(static_cast<int>(record_write_mode));
369     Emit(code, 0, nullptr, arraysize(inputs), inputs, temp_count, temps);
370   } else {
371     ArchOpcode opcode = kArchNop;
372     switch (rep) {
373       case MachineRepresentation::kFloat32:
374         opcode = kIA32Movss;
375         break;
376       case MachineRepresentation::kFloat64:
377         opcode = kIA32Movsd;
378         break;
379       case MachineRepresentation::kBit:  // Fall through.
380       case MachineRepresentation::kWord8:
381         opcode = kIA32Movb;
382         break;
383       case MachineRepresentation::kWord16:
384         opcode = kIA32Movw;
385         break;
386       case MachineRepresentation::kTaggedSigned:   // Fall through.
387       case MachineRepresentation::kTaggedPointer:  // Fall through.
388       case MachineRepresentation::kTagged:         // Fall through.
389       case MachineRepresentation::kWord32:
390         opcode = kIA32Movl;
391         break;
392       case MachineRepresentation::kSimd128:
393         opcode = kIA32Movdqu;
394         break;
395       case MachineRepresentation::kWord64:   // Fall through.
396       case MachineRepresentation::kNone:
397         UNREACHABLE();
398         return;
399     }
400 
401     InstructionOperand val;
402     if (g.CanBeImmediate(value)) {
403       val = g.UseImmediate(value);
404     } else if (rep == MachineRepresentation::kWord8 ||
405                rep == MachineRepresentation::kBit) {
406       val = g.UseByteRegister(value);
407     } else {
408       val = g.UseRegister(value);
409     }
410 
411     InstructionOperand inputs[4];
412     size_t input_count = 0;
413     AddressingMode addressing_mode =
414         g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
415     InstructionCode code =
416         opcode | AddressingModeField::encode(addressing_mode);
417     inputs[input_count++] = val;
418     Emit(code, 0, static_cast<InstructionOperand*>(nullptr), input_count,
419          inputs);
420   }
421 }
422 
VisitProtectedStore(Node * node)423 void InstructionSelector::VisitProtectedStore(Node* node) {
424   // TODO(eholk)
425   UNIMPLEMENTED();
426 }
427 
428 // Architecture supports unaligned access, therefore VisitLoad is used instead
VisitUnalignedLoad(Node * node)429 void InstructionSelector::VisitUnalignedLoad(Node* node) { UNREACHABLE(); }
430 
431 // Architecture supports unaligned access, therefore VisitStore is used instead
VisitUnalignedStore(Node * node)432 void InstructionSelector::VisitUnalignedStore(Node* node) { UNREACHABLE(); }
433 
434 namespace {
435 
436 // Shared routine for multiple binary operations.
VisitBinop(InstructionSelector * selector,Node * node,InstructionCode opcode,FlagsContinuation * cont)437 void VisitBinop(InstructionSelector* selector, Node* node,
438                 InstructionCode opcode, FlagsContinuation* cont) {
439   IA32OperandGenerator g(selector);
440   Int32BinopMatcher m(node);
441   Node* left = m.left().node();
442   Node* right = m.right().node();
443   InstructionOperand inputs[6];
444   size_t input_count = 0;
445   InstructionOperand outputs[1];
446   size_t output_count = 0;
447 
448   // TODO(turbofan): match complex addressing modes.
449   if (left == right) {
450     // If both inputs refer to the same operand, enforce allocating a register
451     // for both of them to ensure that we don't end up generating code like
452     // this:
453     //
454     //   mov eax, [ebp-0x10]
455     //   add eax, [ebp-0x10]
456     //   jo label
457     InstructionOperand const input = g.UseRegister(left);
458     inputs[input_count++] = input;
459     inputs[input_count++] = input;
460   } else if (g.CanBeImmediate(right)) {
461     inputs[input_count++] = g.UseRegister(left);
462     inputs[input_count++] = g.UseImmediate(right);
463   } else {
464     int effect_level = selector->GetEffectLevel(node);
465     if (cont->IsBranch()) {
466       effect_level = selector->GetEffectLevel(
467           cont->true_block()->PredecessorAt(0)->control_input());
468     }
469     if (node->op()->HasProperty(Operator::kCommutative) &&
470         g.CanBeBetterLeftOperand(right) &&
471         (!g.CanBeBetterLeftOperand(left) ||
472          !g.CanBeMemoryOperand(opcode, node, right, effect_level))) {
473       std::swap(left, right);
474     }
475     if (g.CanBeMemoryOperand(opcode, node, right, effect_level)) {
476       inputs[input_count++] = g.UseRegister(left);
477       AddressingMode addressing_mode =
478           g.GetEffectiveAddressMemoryOperand(right, inputs, &input_count);
479       opcode |= AddressingModeField::encode(addressing_mode);
480     } else {
481       inputs[input_count++] = g.UseRegister(left);
482       inputs[input_count++] = g.Use(right);
483     }
484   }
485 
486   outputs[output_count++] = g.DefineSameAsFirst(node);
487 
488   DCHECK_NE(0u, input_count);
489   DCHECK_EQ(1u, output_count);
490   DCHECK_GE(arraysize(inputs), input_count);
491   DCHECK_GE(arraysize(outputs), output_count);
492 
493   selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
494                                  inputs, cont);
495 }
496 
497 
498 // Shared routine for multiple binary operations.
VisitBinop(InstructionSelector * selector,Node * node,InstructionCode opcode)499 void VisitBinop(InstructionSelector* selector, Node* node,
500                 InstructionCode opcode) {
501   FlagsContinuation cont;
502   VisitBinop(selector, node, opcode, &cont);
503 }
504 
505 }  // namespace
506 
VisitWord32And(Node * node)507 void InstructionSelector::VisitWord32And(Node* node) {
508   VisitBinop(this, node, kIA32And);
509 }
510 
511 
VisitWord32Or(Node * node)512 void InstructionSelector::VisitWord32Or(Node* node) {
513   VisitBinop(this, node, kIA32Or);
514 }
515 
516 
VisitWord32Xor(Node * node)517 void InstructionSelector::VisitWord32Xor(Node* node) {
518   IA32OperandGenerator g(this);
519   Int32BinopMatcher m(node);
520   if (m.right().Is(-1)) {
521     Emit(kIA32Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()));
522   } else {
523     VisitBinop(this, node, kIA32Xor);
524   }
525 }
526 
527 
528 // Shared routine for multiple shift operations.
VisitShift(InstructionSelector * selector,Node * node,ArchOpcode opcode)529 static inline void VisitShift(InstructionSelector* selector, Node* node,
530                               ArchOpcode opcode) {
531   IA32OperandGenerator g(selector);
532   Node* left = node->InputAt(0);
533   Node* right = node->InputAt(1);
534 
535   if (g.CanBeImmediate(right)) {
536     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
537                    g.UseImmediate(right));
538   } else {
539     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
540                    g.UseFixed(right, ecx));
541   }
542 }
543 
544 
545 namespace {
546 
VisitMulHigh(InstructionSelector * selector,Node * node,ArchOpcode opcode)547 void VisitMulHigh(InstructionSelector* selector, Node* node,
548                   ArchOpcode opcode) {
549   IA32OperandGenerator g(selector);
550   InstructionOperand temps[] = {g.TempRegister(eax)};
551   selector->Emit(
552       opcode, g.DefineAsFixed(node, edx), g.UseFixed(node->InputAt(0), eax),
553       g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
554 }
555 
556 
VisitDiv(InstructionSelector * selector,Node * node,ArchOpcode opcode)557 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
558   IA32OperandGenerator g(selector);
559   InstructionOperand temps[] = {g.TempRegister(edx)};
560   selector->Emit(opcode, g.DefineAsFixed(node, eax),
561                  g.UseFixed(node->InputAt(0), eax),
562                  g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
563 }
564 
565 
VisitMod(InstructionSelector * selector,Node * node,ArchOpcode opcode)566 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
567   IA32OperandGenerator g(selector);
568   InstructionOperand temps[] = {g.TempRegister(eax)};
569   selector->Emit(opcode, g.DefineAsFixed(node, edx),
570                  g.UseFixed(node->InputAt(0), eax),
571                  g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
572 }
573 
EmitLea(InstructionSelector * selector,Node * result,Node * index,int scale,Node * base,Node * displacement,DisplacementMode displacement_mode)574 void EmitLea(InstructionSelector* selector, Node* result, Node* index,
575              int scale, Node* base, Node* displacement,
576              DisplacementMode displacement_mode) {
577   IA32OperandGenerator g(selector);
578   InstructionOperand inputs[4];
579   size_t input_count = 0;
580   AddressingMode mode =
581       g.GenerateMemoryOperandInputs(index, scale, base, displacement,
582                                     displacement_mode, inputs, &input_count);
583 
584   DCHECK_NE(0u, input_count);
585   DCHECK_GE(arraysize(inputs), input_count);
586 
587   InstructionOperand outputs[1];
588   outputs[0] = g.DefineAsRegister(result);
589 
590   InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
591 
592   selector->Emit(opcode, 1, outputs, input_count, inputs);
593 }
594 
595 }  // namespace
596 
597 
VisitWord32Shl(Node * node)598 void InstructionSelector::VisitWord32Shl(Node* node) {
599   Int32ScaleMatcher m(node, true);
600   if (m.matches()) {
601     Node* index = node->InputAt(0);
602     Node* base = m.power_of_two_plus_one() ? index : nullptr;
603     EmitLea(this, node, index, m.scale(), base, nullptr, kPositiveDisplacement);
604     return;
605   }
606   VisitShift(this, node, kIA32Shl);
607 }
608 
609 
VisitWord32Shr(Node * node)610 void InstructionSelector::VisitWord32Shr(Node* node) {
611   VisitShift(this, node, kIA32Shr);
612 }
613 
614 
VisitWord32Sar(Node * node)615 void InstructionSelector::VisitWord32Sar(Node* node) {
616   VisitShift(this, node, kIA32Sar);
617 }
618 
VisitInt32PairAdd(Node * node)619 void InstructionSelector::VisitInt32PairAdd(Node* node) {
620   IA32OperandGenerator g(this);
621 
622   Node* projection1 = NodeProperties::FindProjection(node, 1);
623   if (projection1) {
624     // We use UseUniqueRegister here to avoid register sharing with the temp
625     // register.
626     InstructionOperand inputs[] = {
627         g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
628         g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
629 
630     InstructionOperand outputs[] = {g.DefineSameAsFirst(node),
631                                     g.DefineAsRegister(projection1)};
632 
633     InstructionOperand temps[] = {g.TempRegister()};
634 
635     Emit(kIA32AddPair, 2, outputs, 4, inputs, 1, temps);
636   } else {
637     // The high word of the result is not used, so we emit the standard 32 bit
638     // instruction.
639     Emit(kIA32Add, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
640          g.Use(node->InputAt(2)));
641   }
642 }
643 
VisitInt32PairSub(Node * node)644 void InstructionSelector::VisitInt32PairSub(Node* node) {
645   IA32OperandGenerator g(this);
646 
647   Node* projection1 = NodeProperties::FindProjection(node, 1);
648   if (projection1) {
649     // We use UseUniqueRegister here to avoid register sharing with the temp
650     // register.
651     InstructionOperand inputs[] = {
652         g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
653         g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
654 
655     InstructionOperand outputs[] = {g.DefineSameAsFirst(node),
656                                     g.DefineAsRegister(projection1)};
657 
658     InstructionOperand temps[] = {g.TempRegister()};
659 
660     Emit(kIA32SubPair, 2, outputs, 4, inputs, 1, temps);
661   } else {
662     // The high word of the result is not used, so we emit the standard 32 bit
663     // instruction.
664     Emit(kIA32Sub, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
665          g.Use(node->InputAt(2)));
666   }
667 }
668 
VisitInt32PairMul(Node * node)669 void InstructionSelector::VisitInt32PairMul(Node* node) {
670   IA32OperandGenerator g(this);
671 
672   Node* projection1 = NodeProperties::FindProjection(node, 1);
673   if (projection1) {
674     // InputAt(3) explicitly shares ecx with OutputRegister(1) to save one
675     // register and one mov instruction.
676     InstructionOperand inputs[] = {g.UseUnique(node->InputAt(0)),
677                                    g.UseUnique(node->InputAt(1)),
678                                    g.UseUniqueRegister(node->InputAt(2)),
679                                    g.UseFixed(node->InputAt(3), ecx)};
680 
681     InstructionOperand outputs[] = {
682         g.DefineAsFixed(node, eax),
683         g.DefineAsFixed(NodeProperties::FindProjection(node, 1), ecx)};
684 
685     InstructionOperand temps[] = {g.TempRegister(edx)};
686 
687     Emit(kIA32MulPair, 2, outputs, 4, inputs, 1, temps);
688   } else {
689     // The high word of the result is not used, so we emit the standard 32 bit
690     // instruction.
691     Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
692          g.Use(node->InputAt(2)));
693   }
694 }
695 
VisitWord32PairShift(InstructionSelector * selector,InstructionCode opcode,Node * node)696 void VisitWord32PairShift(InstructionSelector* selector, InstructionCode opcode,
697                           Node* node) {
698   IA32OperandGenerator g(selector);
699 
700   Node* shift = node->InputAt(2);
701   InstructionOperand shift_operand;
702   if (g.CanBeImmediate(shift)) {
703     shift_operand = g.UseImmediate(shift);
704   } else {
705     shift_operand = g.UseFixed(shift, ecx);
706   }
707   InstructionOperand inputs[] = {g.UseFixed(node->InputAt(0), eax),
708                                  g.UseFixed(node->InputAt(1), edx),
709                                  shift_operand};
710 
711   InstructionOperand outputs[2];
712   InstructionOperand temps[1];
713   int32_t output_count = 0;
714   int32_t temp_count = 0;
715   outputs[output_count++] = g.DefineAsFixed(node, eax);
716   Node* projection1 = NodeProperties::FindProjection(node, 1);
717   if (projection1) {
718     outputs[output_count++] = g.DefineAsFixed(projection1, edx);
719   } else {
720     temps[temp_count++] = g.TempRegister(edx);
721   }
722 
723   selector->Emit(opcode, output_count, outputs, 3, inputs, temp_count, temps);
724 }
725 
VisitWord32PairShl(Node * node)726 void InstructionSelector::VisitWord32PairShl(Node* node) {
727   VisitWord32PairShift(this, kIA32ShlPair, node);
728 }
729 
VisitWord32PairShr(Node * node)730 void InstructionSelector::VisitWord32PairShr(Node* node) {
731   VisitWord32PairShift(this, kIA32ShrPair, node);
732 }
733 
VisitWord32PairSar(Node * node)734 void InstructionSelector::VisitWord32PairSar(Node* node) {
735   VisitWord32PairShift(this, kIA32SarPair, node);
736 }
737 
VisitWord32Ror(Node * node)738 void InstructionSelector::VisitWord32Ror(Node* node) {
739   VisitShift(this, node, kIA32Ror);
740 }
741 
742 #define RO_OP_LIST(V)                                       \
743   V(Word32Clz, kIA32Lzcnt)                                  \
744   V(Word32Ctz, kIA32Tzcnt)                                  \
745   V(Word32Popcnt, kIA32Popcnt)                              \
746   V(ChangeFloat32ToFloat64, kSSEFloat32ToFloat64)           \
747   V(RoundInt32ToFloat32, kSSEInt32ToFloat32)                \
748   V(ChangeInt32ToFloat64, kSSEInt32ToFloat64)               \
749   V(ChangeUint32ToFloat64, kSSEUint32ToFloat64)             \
750   V(TruncateFloat32ToInt32, kSSEFloat32ToInt32)             \
751   V(TruncateFloat32ToUint32, kSSEFloat32ToUint32)           \
752   V(ChangeFloat64ToInt32, kSSEFloat64ToInt32)               \
753   V(ChangeFloat64ToUint32, kSSEFloat64ToUint32)             \
754   V(TruncateFloat64ToUint32, kSSEFloat64ToUint32)           \
755   V(TruncateFloat64ToFloat32, kSSEFloat64ToFloat32)         \
756   V(RoundFloat64ToInt32, kSSEFloat64ToInt32)                \
757   V(BitcastFloat32ToInt32, kIA32BitcastFI)                  \
758   V(BitcastInt32ToFloat32, kIA32BitcastIF)                  \
759   V(Float32Sqrt, kSSEFloat32Sqrt)                           \
760   V(Float64Sqrt, kSSEFloat64Sqrt)                           \
761   V(Float64ExtractLowWord32, kSSEFloat64ExtractLowWord32)   \
762   V(Float64ExtractHighWord32, kSSEFloat64ExtractHighWord32) \
763   V(SignExtendWord8ToInt32, kIA32Movsxbl)                   \
764   V(SignExtendWord16ToInt32, kIA32Movsxwl)
765 
766 #define RR_OP_LIST(V)                                                         \
767   V(TruncateFloat64ToWord32, kArchTruncateDoubleToI)                          \
768   V(Float32RoundDown, kSSEFloat32Round | MiscField::encode(kRoundDown))       \
769   V(Float64RoundDown, kSSEFloat64Round | MiscField::encode(kRoundDown))       \
770   V(Float32RoundUp, kSSEFloat32Round | MiscField::encode(kRoundUp))           \
771   V(Float64RoundUp, kSSEFloat64Round | MiscField::encode(kRoundUp))           \
772   V(Float32RoundTruncate, kSSEFloat32Round | MiscField::encode(kRoundToZero)) \
773   V(Float64RoundTruncate, kSSEFloat64Round | MiscField::encode(kRoundToZero)) \
774   V(Float32RoundTiesEven,                                                     \
775     kSSEFloat32Round | MiscField::encode(kRoundToNearest))                    \
776   V(Float64RoundTiesEven, kSSEFloat64Round | MiscField::encode(kRoundToNearest))
777 
778 #define RRO_FLOAT_OP_LIST(V)                    \
779   V(Float32Add, kAVXFloat32Add, kSSEFloat32Add) \
780   V(Float64Add, kAVXFloat64Add, kSSEFloat64Add) \
781   V(Float32Sub, kAVXFloat32Sub, kSSEFloat32Sub) \
782   V(Float64Sub, kAVXFloat64Sub, kSSEFloat64Sub) \
783   V(Float32Mul, kAVXFloat32Mul, kSSEFloat32Mul) \
784   V(Float64Mul, kAVXFloat64Mul, kSSEFloat64Mul) \
785   V(Float32Div, kAVXFloat32Div, kSSEFloat32Div) \
786   V(Float64Div, kAVXFloat64Div, kSSEFloat64Div)
787 
788 #define FLOAT_UNOP_LIST(V)                      \
789   V(Float32Abs, kAVXFloat32Abs, kSSEFloat32Abs) \
790   V(Float64Abs, kAVXFloat64Abs, kSSEFloat64Abs) \
791   V(Float32Neg, kAVXFloat32Neg, kSSEFloat32Neg) \
792   V(Float64Neg, kAVXFloat64Neg, kSSEFloat64Neg)
793 
794 #define RO_VISITOR(Name, opcode)                      \
795   void InstructionSelector::Visit##Name(Node* node) { \
796     VisitRO(this, node, opcode);                      \
797   }
798 RO_OP_LIST(RO_VISITOR)
799 #undef RO_VISITOR
800 #undef RO_OP_LIST
801 
802 #define RR_VISITOR(Name, opcode)                      \
803   void InstructionSelector::Visit##Name(Node* node) { \
804     VisitRR(this, node, opcode);                      \
805   }
RR_OP_LIST(RR_VISITOR)806 RR_OP_LIST(RR_VISITOR)
807 #undef RR_VISITOR
808 #undef RR_OP_LIST
809 
810 #define RRO_FLOAT_VISITOR(Name, avx, sse)             \
811   void InstructionSelector::Visit##Name(Node* node) { \
812     VisitRROFloat(this, node, avx, sse);              \
813   }
814 RRO_FLOAT_OP_LIST(RRO_FLOAT_VISITOR)
815 #undef RRO_FLOAT_VISITOR
816 #undef RRO_FLOAT_OP_LIST
817 
818 #define FLOAT_UNOP_VISITOR(Name, avx, sse)                  \
819   void InstructionSelector::Visit##Name(Node* node) {       \
820     VisitFloatUnop(this, node, node->InputAt(0), avx, sse); \
821   }
822 FLOAT_UNOP_LIST(FLOAT_UNOP_VISITOR)
823 #undef FLOAT_UNOP_VISITOR
824 #undef FLOAT_UNOP_LIST
825 
826 void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
827 
VisitWord64ReverseBytes(Node * node)828 void InstructionSelector::VisitWord64ReverseBytes(Node* node) { UNREACHABLE(); }
829 
VisitWord32ReverseBytes(Node * node)830 void InstructionSelector::VisitWord32ReverseBytes(Node* node) {
831   IA32OperandGenerator g(this);
832   Emit(kIA32Bswap, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)));
833 }
834 
VisitInt32Add(Node * node)835 void InstructionSelector::VisitInt32Add(Node* node) {
836   IA32OperandGenerator g(this);
837 
838   // Try to match the Add to a lea pattern
839   BaseWithIndexAndDisplacement32Matcher m(node);
840   if (m.matches() &&
841       (m.displacement() == nullptr || g.CanBeImmediate(m.displacement()))) {
842     InstructionOperand inputs[4];
843     size_t input_count = 0;
844     AddressingMode mode = g.GenerateMemoryOperandInputs(
845         m.index(), m.scale(), m.base(), m.displacement(), m.displacement_mode(),
846         inputs, &input_count);
847 
848     DCHECK_NE(0u, input_count);
849     DCHECK_GE(arraysize(inputs), input_count);
850 
851     InstructionOperand outputs[1];
852     outputs[0] = g.DefineAsRegister(node);
853 
854     InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
855     Emit(opcode, 1, outputs, input_count, inputs);
856     return;
857   }
858 
859   // No lea pattern match, use add
860   VisitBinop(this, node, kIA32Add);
861 }
862 
863 
VisitInt32Sub(Node * node)864 void InstructionSelector::VisitInt32Sub(Node* node) {
865   IA32OperandGenerator g(this);
866   Int32BinopMatcher m(node);
867   if (m.left().Is(0)) {
868     Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node()));
869   } else {
870     VisitBinop(this, node, kIA32Sub);
871   }
872 }
873 
874 
VisitInt32Mul(Node * node)875 void InstructionSelector::VisitInt32Mul(Node* node) {
876   Int32ScaleMatcher m(node, true);
877   if (m.matches()) {
878     Node* index = node->InputAt(0);
879     Node* base = m.power_of_two_plus_one() ? index : nullptr;
880     EmitLea(this, node, index, m.scale(), base, nullptr, kPositiveDisplacement);
881     return;
882   }
883   IA32OperandGenerator g(this);
884   Node* left = node->InputAt(0);
885   Node* right = node->InputAt(1);
886   if (g.CanBeImmediate(right)) {
887     Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left),
888          g.UseImmediate(right));
889   } else {
890     if (g.CanBeBetterLeftOperand(right)) {
891       std::swap(left, right);
892     }
893     Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
894          g.Use(right));
895   }
896 }
897 
898 
VisitInt32MulHigh(Node * node)899 void InstructionSelector::VisitInt32MulHigh(Node* node) {
900   VisitMulHigh(this, node, kIA32ImulHigh);
901 }
902 
903 
VisitUint32MulHigh(Node * node)904 void InstructionSelector::VisitUint32MulHigh(Node* node) {
905   VisitMulHigh(this, node, kIA32UmulHigh);
906 }
907 
908 
VisitInt32Div(Node * node)909 void InstructionSelector::VisitInt32Div(Node* node) {
910   VisitDiv(this, node, kIA32Idiv);
911 }
912 
913 
VisitUint32Div(Node * node)914 void InstructionSelector::VisitUint32Div(Node* node) {
915   VisitDiv(this, node, kIA32Udiv);
916 }
917 
918 
VisitInt32Mod(Node * node)919 void InstructionSelector::VisitInt32Mod(Node* node) {
920   VisitMod(this, node, kIA32Idiv);
921 }
922 
923 
VisitUint32Mod(Node * node)924 void InstructionSelector::VisitUint32Mod(Node* node) {
925   VisitMod(this, node, kIA32Udiv);
926 }
927 
928 
VisitRoundUint32ToFloat32(Node * node)929 void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
930   IA32OperandGenerator g(this);
931   InstructionOperand temps[] = {g.TempRegister()};
932   Emit(kSSEUint32ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)),
933        arraysize(temps), temps);
934 }
935 
VisitFloat64Mod(Node * node)936 void InstructionSelector::VisitFloat64Mod(Node* node) {
937   IA32OperandGenerator g(this);
938   InstructionOperand temps[] = {g.TempRegister(eax)};
939   Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node),
940        g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1,
941        temps);
942 }
943 
VisitFloat32Max(Node * node)944 void InstructionSelector::VisitFloat32Max(Node* node) {
945   IA32OperandGenerator g(this);
946   InstructionOperand temps[] = {g.TempRegister()};
947   Emit(kSSEFloat32Max, g.DefineSameAsFirst(node),
948        g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)),
949        arraysize(temps), temps);
950 }
951 
VisitFloat64Max(Node * node)952 void InstructionSelector::VisitFloat64Max(Node* node) {
953   IA32OperandGenerator g(this);
954   InstructionOperand temps[] = {g.TempRegister()};
955   Emit(kSSEFloat64Max, g.DefineSameAsFirst(node),
956        g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)),
957        arraysize(temps), temps);
958 }
959 
VisitFloat32Min(Node * node)960 void InstructionSelector::VisitFloat32Min(Node* node) {
961   IA32OperandGenerator g(this);
962   InstructionOperand temps[] = {g.TempRegister()};
963   Emit(kSSEFloat32Min, g.DefineSameAsFirst(node),
964        g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)),
965        arraysize(temps), temps);
966 }
967 
VisitFloat64Min(Node * node)968 void InstructionSelector::VisitFloat64Min(Node* node) {
969   IA32OperandGenerator g(this);
970   InstructionOperand temps[] = {g.TempRegister()};
971   Emit(kSSEFloat64Min, g.DefineSameAsFirst(node),
972        g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)),
973        arraysize(temps), temps);
974 }
975 
VisitFloat64RoundTiesAway(Node * node)976 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
977   UNREACHABLE();
978 }
979 
VisitFloat64Ieee754Binop(Node * node,InstructionCode opcode)980 void InstructionSelector::VisitFloat64Ieee754Binop(Node* node,
981                                                    InstructionCode opcode) {
982   IA32OperandGenerator g(this);
983   Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
984        g.UseRegister(node->InputAt(1)))
985       ->MarkAsCall();
986 }
987 
VisitFloat64Ieee754Unop(Node * node,InstructionCode opcode)988 void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
989                                                   InstructionCode opcode) {
990   IA32OperandGenerator g(this);
991   Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)))
992       ->MarkAsCall();
993 }
994 
EmitPrepareArguments(ZoneVector<PushParameter> * arguments,const CallDescriptor * call_descriptor,Node * node)995 void InstructionSelector::EmitPrepareArguments(
996     ZoneVector<PushParameter>* arguments, const CallDescriptor* call_descriptor,
997     Node* node) {
998   IA32OperandGenerator g(this);
999 
1000   // Prepare for C function call.
1001   if (call_descriptor->IsCFunctionCall()) {
1002     InstructionOperand temps[] = {g.TempRegister()};
1003     size_t const temp_count = arraysize(temps);
1004     Emit(kArchPrepareCallCFunction | MiscField::encode(static_cast<int>(
1005                                          call_descriptor->ParameterCount())),
1006          0, nullptr, 0, nullptr, temp_count, temps);
1007 
1008     // Poke any stack arguments.
1009     for (size_t n = 0; n < arguments->size(); ++n) {
1010       PushParameter input = (*arguments)[n];
1011       if (input.node) {
1012         int const slot = static_cast<int>(n);
1013         InstructionOperand value = g.CanBeImmediate(node)
1014                                        ? g.UseImmediate(input.node)
1015                                        : g.UseRegister(input.node);
1016         Emit(kIA32Poke | MiscField::encode(slot), g.NoOutput(), value);
1017       }
1018     }
1019   } else {
1020     // Push any stack arguments.
1021     int effect_level = GetEffectLevel(node);
1022     for (PushParameter input : base::Reversed(*arguments)) {
1023       // Skip any alignment holes in pushed nodes.
1024       if (input.node == nullptr) continue;
1025       if (g.CanBeMemoryOperand(kIA32Push, node, input.node, effect_level)) {
1026         InstructionOperand outputs[1];
1027         InstructionOperand inputs[4];
1028         size_t input_count = 0;
1029         InstructionCode opcode = kIA32Push;
1030         AddressingMode mode = g.GetEffectiveAddressMemoryOperand(
1031             input.node, inputs, &input_count);
1032         opcode |= AddressingModeField::encode(mode);
1033         Emit(opcode, 0, outputs, input_count, inputs);
1034       } else {
1035         InstructionOperand value =
1036             g.CanBeImmediate(input.node)
1037                 ? g.UseImmediate(input.node)
1038                 : IsSupported(ATOM) ||
1039                           sequence()->IsFP(GetVirtualRegister(input.node))
1040                       ? g.UseRegister(input.node)
1041                       : g.Use(input.node);
1042         if (input.location.GetType() == MachineType::Float32()) {
1043           Emit(kIA32PushFloat32, g.NoOutput(), value);
1044         } else if (input.location.GetType() == MachineType::Float64()) {
1045           Emit(kIA32PushFloat64, g.NoOutput(), value);
1046         } else if (input.location.GetType() == MachineType::Simd128()) {
1047           Emit(kIA32PushSimd128, g.NoOutput(), value);
1048         } else {
1049           Emit(kIA32Push, g.NoOutput(), value);
1050         }
1051       }
1052     }
1053   }
1054 }
1055 
EmitPrepareResults(ZoneVector<PushParameter> * results,const CallDescriptor * call_descriptor,Node * node)1056 void InstructionSelector::EmitPrepareResults(
1057     ZoneVector<PushParameter>* results, const CallDescriptor* call_descriptor,
1058     Node* node) {
1059   IA32OperandGenerator g(this);
1060 
1061   int reverse_slot = 0;
1062   for (PushParameter output : *results) {
1063     if (!output.location.IsCallerFrameSlot()) continue;
1064     // Skip any alignment holes in nodes.
1065     if (output.node != nullptr) {
1066       DCHECK(!call_descriptor->IsCFunctionCall());
1067       if (output.location.GetType() == MachineType::Float32()) {
1068         MarkAsFloat32(output.node);
1069       } else if (output.location.GetType() == MachineType::Float64()) {
1070         MarkAsFloat64(output.node);
1071       }
1072       Emit(kIA32Peek, g.DefineAsRegister(output.node),
1073            g.UseImmediate(reverse_slot));
1074     }
1075     reverse_slot += output.location.GetSizeInPointers();
1076   }
1077 }
1078 
1079 
IsTailCallAddressImmediate()1080 bool InstructionSelector::IsTailCallAddressImmediate() { return true; }
1081 
GetTempsCountForTailCallFromJSFunction()1082 int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 0; }
1083 
1084 namespace {
1085 
VisitCompareWithMemoryOperand(InstructionSelector * selector,InstructionCode opcode,Node * left,InstructionOperand right,FlagsContinuation * cont)1086 void VisitCompareWithMemoryOperand(InstructionSelector* selector,
1087                                    InstructionCode opcode, Node* left,
1088                                    InstructionOperand right,
1089                                    FlagsContinuation* cont) {
1090   DCHECK_EQ(IrOpcode::kLoad, left->opcode());
1091   IA32OperandGenerator g(selector);
1092   size_t input_count = 0;
1093   InstructionOperand inputs[4];
1094   AddressingMode addressing_mode =
1095       g.GetEffectiveAddressMemoryOperand(left, inputs, &input_count);
1096   opcode |= AddressingModeField::encode(addressing_mode);
1097   inputs[input_count++] = right;
1098 
1099   selector->EmitWithContinuation(opcode, 0, nullptr, input_count, inputs, cont);
1100 }
1101 
1102 // Shared routine for multiple compare operations.
VisitCompare(InstructionSelector * selector,InstructionCode opcode,InstructionOperand left,InstructionOperand right,FlagsContinuation * cont)1103 void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1104                   InstructionOperand left, InstructionOperand right,
1105                   FlagsContinuation* cont) {
1106   selector->EmitWithContinuation(opcode, left, right, cont);
1107 }
1108 
1109 
1110 // Shared routine for multiple compare operations.
VisitCompare(InstructionSelector * selector,InstructionCode opcode,Node * left,Node * right,FlagsContinuation * cont,bool commutative)1111 void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1112                   Node* left, Node* right, FlagsContinuation* cont,
1113                   bool commutative) {
1114   IA32OperandGenerator g(selector);
1115   if (commutative && g.CanBeBetterLeftOperand(right)) {
1116     std::swap(left, right);
1117   }
1118   VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
1119 }
1120 
MachineTypeForNarrow(Node * node,Node * hint_node)1121 MachineType MachineTypeForNarrow(Node* node, Node* hint_node) {
1122   if (hint_node->opcode() == IrOpcode::kLoad) {
1123     MachineType hint = LoadRepresentationOf(hint_node->op());
1124     if (node->opcode() == IrOpcode::kInt32Constant ||
1125         node->opcode() == IrOpcode::kInt64Constant) {
1126       int64_t constant = node->opcode() == IrOpcode::kInt32Constant
1127                              ? OpParameter<int32_t>(node->op())
1128                              : OpParameter<int64_t>(node->op());
1129       if (hint == MachineType::Int8()) {
1130         if (constant >= std::numeric_limits<int8_t>::min() &&
1131             constant <= std::numeric_limits<int8_t>::max()) {
1132           return hint;
1133         }
1134       } else if (hint == MachineType::Uint8()) {
1135         if (constant >= std::numeric_limits<uint8_t>::min() &&
1136             constant <= std::numeric_limits<uint8_t>::max()) {
1137           return hint;
1138         }
1139       } else if (hint == MachineType::Int16()) {
1140         if (constant >= std::numeric_limits<int16_t>::min() &&
1141             constant <= std::numeric_limits<int16_t>::max()) {
1142           return hint;
1143         }
1144       } else if (hint == MachineType::Uint16()) {
1145         if (constant >= std::numeric_limits<uint16_t>::min() &&
1146             constant <= std::numeric_limits<uint16_t>::max()) {
1147           return hint;
1148         }
1149       } else if (hint == MachineType::Int32()) {
1150         return hint;
1151       } else if (hint == MachineType::Uint32()) {
1152         if (constant >= 0) return hint;
1153       }
1154     }
1155   }
1156   return node->opcode() == IrOpcode::kLoad ? LoadRepresentationOf(node->op())
1157                                            : MachineType::None();
1158 }
1159 
1160 // Tries to match the size of the given opcode to that of the operands, if
1161 // possible.
TryNarrowOpcodeSize(InstructionCode opcode,Node * left,Node * right,FlagsContinuation * cont)1162 InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left,
1163                                     Node* right, FlagsContinuation* cont) {
1164   // TODO(epertoso): we can probably get some size information out of phi nodes.
1165   // If the load representations don't match, both operands will be
1166   // zero/sign-extended to 32bit.
1167   MachineType left_type = MachineTypeForNarrow(left, right);
1168   MachineType right_type = MachineTypeForNarrow(right, left);
1169   if (left_type == right_type) {
1170     switch (left_type.representation()) {
1171       case MachineRepresentation::kBit:
1172       case MachineRepresentation::kWord8: {
1173         if (opcode == kIA32Test) return kIA32Test8;
1174         if (opcode == kIA32Cmp) {
1175           if (left_type.semantic() == MachineSemantic::kUint32) {
1176             cont->OverwriteUnsignedIfSigned();
1177           } else {
1178             CHECK_EQ(MachineSemantic::kInt32, left_type.semantic());
1179           }
1180           return kIA32Cmp8;
1181         }
1182         break;
1183       }
1184       case MachineRepresentation::kWord16:
1185         if (opcode == kIA32Test) return kIA32Test16;
1186         if (opcode == kIA32Cmp) {
1187           if (left_type.semantic() == MachineSemantic::kUint32) {
1188             cont->OverwriteUnsignedIfSigned();
1189           } else {
1190             CHECK_EQ(MachineSemantic::kInt32, left_type.semantic());
1191           }
1192           return kIA32Cmp16;
1193         }
1194         break;
1195       default:
1196         break;
1197     }
1198   }
1199   return opcode;
1200 }
1201 
1202 // Shared routine for multiple float32 compare operations (inputs commuted).
VisitFloat32Compare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1203 void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1204                          FlagsContinuation* cont) {
1205   Node* const left = node->InputAt(0);
1206   Node* const right = node->InputAt(1);
1207   VisitCompare(selector, kSSEFloat32Cmp, right, left, cont, false);
1208 }
1209 
1210 
1211 // Shared routine for multiple float64 compare operations (inputs commuted).
VisitFloat64Compare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1212 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1213                          FlagsContinuation* cont) {
1214   Node* const left = node->InputAt(0);
1215   Node* const right = node->InputAt(1);
1216   VisitCompare(selector, kSSEFloat64Cmp, right, left, cont, false);
1217 }
1218 
1219 // Shared routine for multiple word compare operations.
VisitWordCompare(InstructionSelector * selector,Node * node,InstructionCode opcode,FlagsContinuation * cont)1220 void VisitWordCompare(InstructionSelector* selector, Node* node,
1221                       InstructionCode opcode, FlagsContinuation* cont) {
1222   IA32OperandGenerator g(selector);
1223   Node* left = node->InputAt(0);
1224   Node* right = node->InputAt(1);
1225 
1226   InstructionCode narrowed_opcode =
1227       TryNarrowOpcodeSize(opcode, left, right, cont);
1228 
1229   int effect_level = selector->GetEffectLevel(node);
1230   if (cont->IsBranch()) {
1231     effect_level = selector->GetEffectLevel(
1232         cont->true_block()->PredecessorAt(0)->control_input());
1233   }
1234 
1235   // If one of the two inputs is an immediate, make sure it's on the right, or
1236   // if one of the two inputs is a memory operand, make sure it's on the left.
1237   if ((!g.CanBeImmediate(right) && g.CanBeImmediate(left)) ||
1238       (g.CanBeMemoryOperand(narrowed_opcode, node, right, effect_level) &&
1239        !g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level))) {
1240     if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1241     std::swap(left, right);
1242   }
1243 
1244   // Match immediates on right side of comparison.
1245   if (g.CanBeImmediate(right)) {
1246     if (g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level)) {
1247       return VisitCompareWithMemoryOperand(selector, narrowed_opcode, left,
1248                                            g.UseImmediate(right), cont);
1249     }
1250     return VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right),
1251                         cont);
1252   }
1253 
1254   // Match memory operands on left side of comparison.
1255   if (g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level)) {
1256     bool needs_byte_register =
1257         narrowed_opcode == kIA32Test8 || narrowed_opcode == kIA32Cmp8;
1258     return VisitCompareWithMemoryOperand(
1259         selector, narrowed_opcode, left,
1260         needs_byte_register ? g.UseByteRegister(right) : g.UseRegister(right),
1261         cont);
1262   }
1263 
1264   return VisitCompare(selector, opcode, left, right, cont,
1265                       node->op()->HasProperty(Operator::kCommutative));
1266 }
1267 
VisitWordCompare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1268 void VisitWordCompare(InstructionSelector* selector, Node* node,
1269                       FlagsContinuation* cont) {
1270   StackCheckMatcher<Int32BinopMatcher, IrOpcode::kUint32LessThan> m(
1271       selector->isolate(), node);
1272   if (m.Matched()) {
1273     // Compare(Load(js_stack_limit), LoadStackPointer)
1274     if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1275     InstructionCode opcode = cont->Encode(kIA32StackCheck);
1276     CHECK(cont->IsBranch());
1277     selector->EmitWithContinuation(opcode, cont);
1278     return;
1279   }
1280   WasmStackCheckMatcher<Int32BinopMatcher, IrOpcode::kUint32LessThan> wasm_m(
1281       node);
1282   if (wasm_m.Matched()) {
1283     // This is a wasm stack check. By structure, we know that we can use the
1284     // stack pointer directly, as wasm code does not modify the stack at points
1285     // where stack checks are performed.
1286     Node* left = node->InputAt(0);
1287     LocationOperand esp(InstructionOperand::EXPLICIT, LocationOperand::REGISTER,
1288                         InstructionSequence::DefaultRepresentation(),
1289                         RegisterCode::kRegCode_esp);
1290     return VisitCompareWithMemoryOperand(selector, kIA32Cmp, left, esp, cont);
1291   }
1292   VisitWordCompare(selector, node, kIA32Cmp, cont);
1293 }
1294 
VisitAtomicExchange(InstructionSelector * selector,Node * node,ArchOpcode opcode,MachineRepresentation rep)1295 void VisitAtomicExchange(InstructionSelector* selector, Node* node,
1296                          ArchOpcode opcode, MachineRepresentation rep) {
1297   IA32OperandGenerator g(selector);
1298   Node* base = node->InputAt(0);
1299   Node* index = node->InputAt(1);
1300   Node* value = node->InputAt(2);
1301 
1302   AddressingMode addressing_mode;
1303   InstructionOperand value_operand = (rep == MachineRepresentation::kWord8)
1304                                          ? g.UseFixed(value, edx)
1305                                          : g.UseUniqueRegister(value);
1306   InstructionOperand inputs[] = {
1307       value_operand, g.UseUniqueRegister(base),
1308       g.GetEffectiveIndexOperand(index, &addressing_mode)};
1309   InstructionOperand outputs[] = {
1310       (rep == MachineRepresentation::kWord8)
1311           // Using DefineSameAsFirst requires the register to be unallocated.
1312           ? g.DefineAsFixed(node, edx)
1313           : g.DefineSameAsFirst(node)};
1314   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
1315   selector->Emit(code, 1, outputs, arraysize(inputs), inputs);
1316 }
1317 
VisitAtomicBinOp(InstructionSelector * selector,Node * node,ArchOpcode opcode,MachineRepresentation rep)1318 void VisitAtomicBinOp(InstructionSelector* selector, Node* node,
1319                       ArchOpcode opcode, MachineRepresentation rep) {
1320   AddressingMode addressing_mode;
1321   IA32OperandGenerator g(selector);
1322   Node* base = node->InputAt(0);
1323   Node* index = node->InputAt(1);
1324   Node* value = node->InputAt(2);
1325   InstructionOperand inputs[] = {
1326       g.UseUniqueRegister(value), g.UseUniqueRegister(base),
1327       g.GetEffectiveIndexOperand(index, &addressing_mode)};
1328   InstructionOperand outputs[] = {g.DefineAsFixed(node, eax)};
1329   InstructionOperand temp[] = {(rep == MachineRepresentation::kWord8)
1330                                    ? g.UseByteRegister(node)
1331                                    : g.TempRegister()};
1332   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
1333   selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
1334                  arraysize(temp), temp);
1335 }
1336 
VisitPairAtomicBinOp(InstructionSelector * selector,Node * node,ArchOpcode opcode)1337 void VisitPairAtomicBinOp(InstructionSelector* selector, Node* node,
1338                           ArchOpcode opcode) {
1339   IA32OperandGenerator g(selector);
1340   Node* base = node->InputAt(0);
1341   Node* index = node->InputAt(1);
1342   Node* value = node->InputAt(2);
1343   // For Word64 operations, the value input is split into the a high node,
1344   // and a low node in the int64-lowering phase.
1345   Node* value_high = node->InputAt(3);
1346 
1347   // Wasm lives in 32-bit address space, so we do not need to worry about
1348   // base/index lowering. This will need to be fixed for Wasm64.
1349   AddressingMode addressing_mode;
1350   InstructionOperand inputs[] = {
1351       g.UseFixed(value, ebx), g.UseFixed(value_high, ecx),
1352       g.UseUniqueRegister(base),
1353       g.GetEffectiveIndexOperand(index, &addressing_mode)};
1354   InstructionOperand outputs[] = {
1355       g.DefineAsFixed(NodeProperties::FindProjection(node, 0), eax),
1356       g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)};
1357   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
1358   selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs);
1359 }
1360 
VisitNarrowAtomicBinOp(InstructionSelector * selector,Node * node,ArchOpcode opcode,MachineType type)1361 void VisitNarrowAtomicBinOp(InstructionSelector* selector, Node* node,
1362                             ArchOpcode opcode, MachineType type) {
1363   IA32OperandGenerator g(selector);
1364   Node* base = node->InputAt(0);
1365   Node* index = node->InputAt(1);
1366   Node* value = node->InputAt(2);
1367 
1368   // Wasm lives in 32-bit address space, so we do not need to worry about
1369   // base/index lowering. This will need to be fixed for Wasm64.
1370   AddressingMode addressing_mode;
1371   InstructionOperand inputs[] = {
1372       g.UseUniqueRegister(value), g.UseUniqueRegister(base),
1373       g.GetEffectiveIndexOperand(index, &addressing_mode)};
1374   InstructionOperand outputs[] = {
1375       g.DefineAsFixed(NodeProperties::FindProjection(node, 0), eax),
1376       g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)};
1377   InstructionOperand temp[] = {(type == MachineType::Uint8())
1378                                    ? g.UseByteRegister(node)
1379                                    : g.TempRegister()};
1380   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
1381   selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
1382                  arraysize(temp), temp);
1383 }
1384 
1385 }  // namespace
1386 
1387 // Shared routine for word comparison with zero.
VisitWordCompareZero(Node * user,Node * value,FlagsContinuation * cont)1388 void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
1389                                                FlagsContinuation* cont) {
1390   // Try to combine with comparisons against 0 by simply inverting the branch.
1391   while (value->opcode() == IrOpcode::kWord32Equal && CanCover(user, value)) {
1392     Int32BinopMatcher m(value);
1393     if (!m.right().Is(0)) break;
1394 
1395     user = value;
1396     value = m.left().node();
1397     cont->Negate();
1398   }
1399 
1400   if (CanCover(user, value)) {
1401     switch (value->opcode()) {
1402       case IrOpcode::kWord32Equal:
1403         cont->OverwriteAndNegateIfEqual(kEqual);
1404         return VisitWordCompare(this, value, cont);
1405       case IrOpcode::kInt32LessThan:
1406         cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1407         return VisitWordCompare(this, value, cont);
1408       case IrOpcode::kInt32LessThanOrEqual:
1409         cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1410         return VisitWordCompare(this, value, cont);
1411       case IrOpcode::kUint32LessThan:
1412         cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1413         return VisitWordCompare(this, value, cont);
1414       case IrOpcode::kUint32LessThanOrEqual:
1415         cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1416         return VisitWordCompare(this, value, cont);
1417       case IrOpcode::kFloat32Equal:
1418         cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
1419         return VisitFloat32Compare(this, value, cont);
1420       case IrOpcode::kFloat32LessThan:
1421         cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
1422         return VisitFloat32Compare(this, value, cont);
1423       case IrOpcode::kFloat32LessThanOrEqual:
1424         cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
1425         return VisitFloat32Compare(this, value, cont);
1426       case IrOpcode::kFloat64Equal:
1427         cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
1428         return VisitFloat64Compare(this, value, cont);
1429       case IrOpcode::kFloat64LessThan:
1430         cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
1431         return VisitFloat64Compare(this, value, cont);
1432       case IrOpcode::kFloat64LessThanOrEqual:
1433         cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
1434         return VisitFloat64Compare(this, value, cont);
1435       case IrOpcode::kProjection:
1436         // Check if this is the overflow output projection of an
1437         // <Operation>WithOverflow node.
1438         if (ProjectionIndexOf(value->op()) == 1u) {
1439           // We cannot combine the <Operation>WithOverflow with this branch
1440           // unless the 0th projection (the use of the actual value of the
1441           // <Operation> is either nullptr, which means there's no use of the
1442           // actual value, or was already defined, which means it is scheduled
1443           // *AFTER* this branch).
1444           Node* const node = value->InputAt(0);
1445           Node* const result = NodeProperties::FindProjection(node, 0);
1446           if (result == nullptr || IsDefined(result)) {
1447             switch (node->opcode()) {
1448               case IrOpcode::kInt32AddWithOverflow:
1449                 cont->OverwriteAndNegateIfEqual(kOverflow);
1450                 return VisitBinop(this, node, kIA32Add, cont);
1451               case IrOpcode::kInt32SubWithOverflow:
1452                 cont->OverwriteAndNegateIfEqual(kOverflow);
1453                 return VisitBinop(this, node, kIA32Sub, cont);
1454               case IrOpcode::kInt32MulWithOverflow:
1455                 cont->OverwriteAndNegateIfEqual(kOverflow);
1456                 return VisitBinop(this, node, kIA32Imul, cont);
1457               default:
1458                 break;
1459             }
1460           }
1461         }
1462         break;
1463       case IrOpcode::kInt32Sub:
1464         return VisitWordCompare(this, value, cont);
1465       case IrOpcode::kWord32And:
1466         return VisitWordCompare(this, value, kIA32Test, cont);
1467       default:
1468         break;
1469     }
1470   }
1471 
1472   // Continuation could not be combined with a compare, emit compare against 0.
1473   IA32OperandGenerator g(this);
1474   VisitCompare(this, kIA32Cmp, g.Use(value), g.TempImmediate(0), cont);
1475 }
1476 
VisitSwitch(Node * node,const SwitchInfo & sw)1477 void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1478   IA32OperandGenerator g(this);
1479   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1480 
1481   // Emit either ArchTableSwitch or ArchLookupSwitch.
1482   if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
1483     static const size_t kMaxTableSwitchValueRange = 2 << 16;
1484     size_t table_space_cost = 4 + sw.value_range();
1485     size_t table_time_cost = 3;
1486     size_t lookup_space_cost = 3 + 2 * sw.case_count();
1487     size_t lookup_time_cost = sw.case_count();
1488     if (sw.case_count() > 4 &&
1489         table_space_cost + 3 * table_time_cost <=
1490             lookup_space_cost + 3 * lookup_time_cost &&
1491         sw.min_value() > std::numeric_limits<int32_t>::min() &&
1492         sw.value_range() <= kMaxTableSwitchValueRange) {
1493       InstructionOperand index_operand = value_operand;
1494       if (sw.min_value()) {
1495         index_operand = g.TempRegister();
1496         Emit(kIA32Lea | AddressingModeField::encode(kMode_MRI), index_operand,
1497              value_operand, g.TempImmediate(-sw.min_value()));
1498       }
1499       // Generate a table lookup.
1500       return EmitTableSwitch(sw, index_operand);
1501     }
1502   }
1503 
1504   // Generate a tree of conditional jumps.
1505   return EmitBinarySearchSwitch(sw, value_operand);
1506 }
1507 
1508 
VisitWord32Equal(Node * const node)1509 void InstructionSelector::VisitWord32Equal(Node* const node) {
1510   FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
1511   Int32BinopMatcher m(node);
1512   if (m.right().Is(0)) {
1513     return VisitWordCompareZero(m.node(), m.left().node(), &cont);
1514   }
1515   VisitWordCompare(this, node, &cont);
1516 }
1517 
1518 
VisitInt32LessThan(Node * node)1519 void InstructionSelector::VisitInt32LessThan(Node* node) {
1520   FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
1521   VisitWordCompare(this, node, &cont);
1522 }
1523 
1524 
VisitInt32LessThanOrEqual(Node * node)1525 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
1526   FlagsContinuation cont =
1527       FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
1528   VisitWordCompare(this, node, &cont);
1529 }
1530 
1531 
VisitUint32LessThan(Node * node)1532 void InstructionSelector::VisitUint32LessThan(Node* node) {
1533   FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
1534   VisitWordCompare(this, node, &cont);
1535 }
1536 
1537 
VisitUint32LessThanOrEqual(Node * node)1538 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
1539   FlagsContinuation cont =
1540       FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
1541   VisitWordCompare(this, node, &cont);
1542 }
1543 
1544 
VisitInt32AddWithOverflow(Node * node)1545 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
1546   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1547     FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
1548     return VisitBinop(this, node, kIA32Add, &cont);
1549   }
1550   FlagsContinuation cont;
1551   VisitBinop(this, node, kIA32Add, &cont);
1552 }
1553 
1554 
VisitInt32SubWithOverflow(Node * node)1555 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
1556   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1557     FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
1558     return VisitBinop(this, node, kIA32Sub, &cont);
1559   }
1560   FlagsContinuation cont;
1561   VisitBinop(this, node, kIA32Sub, &cont);
1562 }
1563 
VisitInt32MulWithOverflow(Node * node)1564 void InstructionSelector::VisitInt32MulWithOverflow(Node* node) {
1565   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1566     FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
1567     return VisitBinop(this, node, kIA32Imul, &cont);
1568   }
1569   FlagsContinuation cont;
1570   VisitBinop(this, node, kIA32Imul, &cont);
1571 }
1572 
VisitFloat32Equal(Node * node)1573 void InstructionSelector::VisitFloat32Equal(Node* node) {
1574   FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
1575   VisitFloat32Compare(this, node, &cont);
1576 }
1577 
1578 
VisitFloat32LessThan(Node * node)1579 void InstructionSelector::VisitFloat32LessThan(Node* node) {
1580   FlagsContinuation cont =
1581       FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
1582   VisitFloat32Compare(this, node, &cont);
1583 }
1584 
1585 
VisitFloat32LessThanOrEqual(Node * node)1586 void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
1587   FlagsContinuation cont =
1588       FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
1589   VisitFloat32Compare(this, node, &cont);
1590 }
1591 
1592 
VisitFloat64Equal(Node * node)1593 void InstructionSelector::VisitFloat64Equal(Node* node) {
1594   FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
1595   VisitFloat64Compare(this, node, &cont);
1596 }
1597 
1598 
VisitFloat64LessThan(Node * node)1599 void InstructionSelector::VisitFloat64LessThan(Node* node) {
1600   FlagsContinuation cont =
1601       FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
1602   VisitFloat64Compare(this, node, &cont);
1603 }
1604 
1605 
VisitFloat64LessThanOrEqual(Node * node)1606 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
1607   FlagsContinuation cont =
1608       FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
1609   VisitFloat64Compare(this, node, &cont);
1610 }
1611 
1612 
1613 
VisitFloat64InsertLowWord32(Node * node)1614 void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1615   IA32OperandGenerator g(this);
1616   Node* left = node->InputAt(0);
1617   Node* right = node->InputAt(1);
1618   Float64Matcher mleft(left);
1619   if (mleft.HasValue() && (bit_cast<uint64_t>(mleft.Value()) >> 32) == 0u) {
1620     Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right));
1621     return;
1622   }
1623   Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node),
1624        g.UseRegister(left), g.Use(right));
1625 }
1626 
1627 
VisitFloat64InsertHighWord32(Node * node)1628 void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1629   IA32OperandGenerator g(this);
1630   Node* left = node->InputAt(0);
1631   Node* right = node->InputAt(1);
1632   Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node),
1633        g.UseRegister(left), g.Use(right));
1634 }
1635 
VisitFloat64SilenceNaN(Node * node)1636 void InstructionSelector::VisitFloat64SilenceNaN(Node* node) {
1637   IA32OperandGenerator g(this);
1638   Emit(kSSEFloat64SilenceNaN, g.DefineSameAsFirst(node),
1639        g.UseRegister(node->InputAt(0)));
1640 }
1641 
VisitWord32AtomicLoad(Node * node)1642 void InstructionSelector::VisitWord32AtomicLoad(Node* node) {
1643   LoadRepresentation load_rep = LoadRepresentationOf(node->op());
1644   DCHECK(load_rep.representation() == MachineRepresentation::kWord8 ||
1645          load_rep.representation() == MachineRepresentation::kWord16 ||
1646          load_rep.representation() == MachineRepresentation::kWord32);
1647   USE(load_rep);
1648   VisitLoad(node);
1649 }
1650 
VisitWord32AtomicStore(Node * node)1651 void InstructionSelector::VisitWord32AtomicStore(Node* node) {
1652   IA32OperandGenerator g(this);
1653   MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
1654   ArchOpcode opcode = kArchNop;
1655   switch (rep) {
1656     case MachineRepresentation::kWord8:
1657       opcode = kWord32AtomicExchangeInt8;
1658       break;
1659     case MachineRepresentation::kWord16:
1660       opcode = kWord32AtomicExchangeInt16;
1661       break;
1662     case MachineRepresentation::kWord32:
1663       opcode = kWord32AtomicExchangeWord32;
1664       break;
1665     default:
1666       UNREACHABLE();
1667       break;
1668   }
1669   VisitAtomicExchange(this, node, opcode, rep);
1670 }
1671 
VisitWord32AtomicExchange(Node * node)1672 void InstructionSelector::VisitWord32AtomicExchange(Node* node) {
1673   IA32OperandGenerator g(this);
1674   MachineType type = AtomicOpType(node->op());
1675   ArchOpcode opcode = kArchNop;
1676   if (type == MachineType::Int8()) {
1677     opcode = kWord32AtomicExchangeInt8;
1678   } else if (type == MachineType::Uint8()) {
1679     opcode = kWord32AtomicExchangeUint8;
1680   } else if (type == MachineType::Int16()) {
1681     opcode = kWord32AtomicExchangeInt16;
1682   } else if (type == MachineType::Uint16()) {
1683     opcode = kWord32AtomicExchangeUint16;
1684   } else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
1685     opcode = kWord32AtomicExchangeWord32;
1686   } else {
1687     UNREACHABLE();
1688     return;
1689   }
1690   VisitAtomicExchange(this, node, opcode, type.representation());
1691 }
1692 
VisitWord32AtomicCompareExchange(Node * node)1693 void InstructionSelector::VisitWord32AtomicCompareExchange(Node* node) {
1694   IA32OperandGenerator g(this);
1695   Node* base = node->InputAt(0);
1696   Node* index = node->InputAt(1);
1697   Node* old_value = node->InputAt(2);
1698   Node* new_value = node->InputAt(3);
1699 
1700   MachineType type = AtomicOpType(node->op());
1701   ArchOpcode opcode = kArchNop;
1702   if (type == MachineType::Int8()) {
1703     opcode = kWord32AtomicCompareExchangeInt8;
1704   } else if (type == MachineType::Uint8()) {
1705     opcode = kWord32AtomicCompareExchangeUint8;
1706   } else if (type == MachineType::Int16()) {
1707     opcode = kWord32AtomicCompareExchangeInt16;
1708   } else if (type == MachineType::Uint16()) {
1709     opcode = kWord32AtomicCompareExchangeUint16;
1710   } else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
1711     opcode = kWord32AtomicCompareExchangeWord32;
1712   } else {
1713     UNREACHABLE();
1714     return;
1715   }
1716   AddressingMode addressing_mode;
1717   InstructionOperand new_val_operand =
1718       (type.representation() == MachineRepresentation::kWord8)
1719           ? g.UseByteRegister(new_value)
1720           : g.UseUniqueRegister(new_value);
1721   InstructionOperand inputs[] = {
1722       g.UseFixed(old_value, eax), new_val_operand, g.UseUniqueRegister(base),
1723       g.GetEffectiveIndexOperand(index, &addressing_mode)};
1724   InstructionOperand outputs[] = {g.DefineAsFixed(node, eax)};
1725   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
1726   Emit(code, 1, outputs, arraysize(inputs), inputs);
1727 }
1728 
VisitWord32AtomicBinaryOperation(Node * node,ArchOpcode int8_op,ArchOpcode uint8_op,ArchOpcode int16_op,ArchOpcode uint16_op,ArchOpcode word32_op)1729 void InstructionSelector::VisitWord32AtomicBinaryOperation(
1730     Node* node, ArchOpcode int8_op, ArchOpcode uint8_op, ArchOpcode int16_op,
1731     ArchOpcode uint16_op, ArchOpcode word32_op) {
1732   MachineType type = AtomicOpType(node->op());
1733   ArchOpcode opcode = kArchNop;
1734   if (type == MachineType::Int8()) {
1735     opcode = int8_op;
1736   } else if (type == MachineType::Uint8()) {
1737     opcode = uint8_op;
1738   } else if (type == MachineType::Int16()) {
1739     opcode = int16_op;
1740   } else if (type == MachineType::Uint16()) {
1741     opcode = uint16_op;
1742   } else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
1743     opcode = word32_op;
1744   } else {
1745     UNREACHABLE();
1746     return;
1747   }
1748   VisitAtomicBinOp(this, node, opcode, type.representation());
1749 }
1750 
1751 #define VISIT_ATOMIC_BINOP(op)                                   \
1752   void InstructionSelector::VisitWord32Atomic##op(Node* node) {  \
1753     VisitWord32AtomicBinaryOperation(                            \
1754         node, kWord32Atomic##op##Int8, kWord32Atomic##op##Uint8, \
1755         kWord32Atomic##op##Int16, kWord32Atomic##op##Uint16,     \
1756         kWord32Atomic##op##Word32);                              \
1757   }
1758 VISIT_ATOMIC_BINOP(Add)
VISIT_ATOMIC_BINOP(Sub)1759 VISIT_ATOMIC_BINOP(Sub)
1760 VISIT_ATOMIC_BINOP(And)
1761 VISIT_ATOMIC_BINOP(Or)
1762 VISIT_ATOMIC_BINOP(Xor)
1763 #undef VISIT_ATOMIC_BINOP
1764 
1765 void InstructionSelector::VisitWord32AtomicPairLoad(Node* node) {
1766   IA32OperandGenerator g(this);
1767   AddressingMode mode;
1768   Node* base = node->InputAt(0);
1769   Node* index = node->InputAt(1);
1770   InstructionOperand inputs[] = {g.UseUniqueRegister(base),
1771                                  g.GetEffectiveIndexOperand(index, &mode)};
1772   InstructionOperand temps[] = {g.TempDoubleRegister()};
1773   InstructionOperand outputs[] = {
1774       g.DefineAsRegister(NodeProperties::FindProjection(node, 0)),
1775       g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
1776   InstructionCode code =
1777       kIA32Word32AtomicPairLoad | AddressingModeField::encode(mode);
1778   Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
1779        arraysize(temps), temps);
1780 }
1781 
VisitWord32AtomicPairStore(Node * node)1782 void InstructionSelector::VisitWord32AtomicPairStore(Node* node) {
1783   IA32OperandGenerator g(this);
1784   Node* base = node->InputAt(0);
1785   Node* index = node->InputAt(1);
1786   Node* value = node->InputAt(2);
1787   Node* value_high = node->InputAt(3);
1788 
1789   AddressingMode addressing_mode;
1790   InstructionOperand inputs[] = {
1791       g.UseFixed(value, ebx), g.UseFixed(value_high, ecx),
1792       g.UseUniqueRegister(base),
1793       g.GetEffectiveIndexOperand(index, &addressing_mode)};
1794   // Allocating temp registers here as stores are performed using an atomic
1795   // exchange, the output of which is stored in edx:eax, which should be saved
1796   // and restored at the end of the instruction.
1797   InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
1798   InstructionCode code =
1799       kIA32Word32AtomicPairStore | AddressingModeField::encode(addressing_mode);
1800   Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
1801 }
1802 
VisitWord32AtomicPairAdd(Node * node)1803 void InstructionSelector::VisitWord32AtomicPairAdd(Node* node) {
1804   VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairAdd);
1805 }
1806 
VisitWord32AtomicPairSub(Node * node)1807 void InstructionSelector::VisitWord32AtomicPairSub(Node* node) {
1808   VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairSub);
1809 }
1810 
VisitWord32AtomicPairAnd(Node * node)1811 void InstructionSelector::VisitWord32AtomicPairAnd(Node* node) {
1812   VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairAnd);
1813 }
1814 
VisitWord32AtomicPairOr(Node * node)1815 void InstructionSelector::VisitWord32AtomicPairOr(Node* node) {
1816   VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairOr);
1817 }
1818 
VisitWord32AtomicPairXor(Node * node)1819 void InstructionSelector::VisitWord32AtomicPairXor(Node* node) {
1820   VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairXor);
1821 }
1822 
VisitWord32AtomicPairExchange(Node * node)1823 void InstructionSelector::VisitWord32AtomicPairExchange(Node* node) {
1824   VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairExchange);
1825 }
1826 
VisitWord32AtomicPairCompareExchange(Node * node)1827 void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
1828   IA32OperandGenerator g(this);
1829   Node* index = node->InputAt(1);
1830   AddressingMode addressing_mode;
1831   InstructionOperand inputs[] = {
1832       // High, Low values of old value
1833       g.UseFixed(node->InputAt(2), eax), g.UseFixed(node->InputAt(3), edx),
1834       // High, Low values of new value
1835       g.UseFixed(node->InputAt(4), ebx), g.UseFixed(node->InputAt(5), ecx),
1836       // InputAt(0) => base
1837       g.UseUniqueRegister(node->InputAt(0)),
1838       g.GetEffectiveIndexOperand(index, &addressing_mode)};
1839   InstructionOperand outputs[] = {
1840       g.DefineAsFixed(NodeProperties::FindProjection(node, 0), eax),
1841       g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)};
1842   InstructionCode code = kIA32Word32AtomicPairCompareExchange |
1843                          AddressingModeField::encode(addressing_mode);
1844   Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs);
1845 }
1846 
VisitWord64AtomicNarrowBinop(Node * node,ArchOpcode uint8_op,ArchOpcode uint16_op,ArchOpcode uint32_op)1847 void InstructionSelector::VisitWord64AtomicNarrowBinop(Node* node,
1848                                                        ArchOpcode uint8_op,
1849                                                        ArchOpcode uint16_op,
1850                                                        ArchOpcode uint32_op) {
1851   MachineType type = AtomicOpType(node->op());
1852   DCHECK(type != MachineType::Uint64());
1853   ArchOpcode opcode = kArchNop;
1854   if (type == MachineType::Uint32()) {
1855     opcode = uint32_op;
1856   } else if (type == MachineType::Uint16()) {
1857     opcode = uint16_op;
1858   } else if (type == MachineType::Uint8()) {
1859     opcode = uint8_op;
1860   } else {
1861     UNREACHABLE();
1862     return;
1863   }
1864   VisitNarrowAtomicBinOp(this, node, opcode, type);
1865 }
1866 
1867 #define VISIT_ATOMIC_BINOP(op)                                             \
1868   void InstructionSelector::VisitWord64AtomicNarrow##op(Node* node) {      \
1869     VisitWord64AtomicNarrowBinop(node, kIA32Word64AtomicNarrow##op##Uint8, \
1870                                  kIA32Word64AtomicNarrow##op##Uint16,      \
1871                                  kIA32Word64AtomicNarrow##op##Uint32);     \
1872   }
1873 VISIT_ATOMIC_BINOP(Add)
VISIT_ATOMIC_BINOP(Sub)1874 VISIT_ATOMIC_BINOP(Sub)
1875 VISIT_ATOMIC_BINOP(And)
1876 VISIT_ATOMIC_BINOP(Or)
1877 VISIT_ATOMIC_BINOP(Xor)
1878 #undef VISIT_ATOMIC_BINOP
1879 
1880 void InstructionSelector::VisitWord64AtomicNarrowExchange(Node* node) {
1881   MachineType type = AtomicOpType(node->op());
1882   DCHECK(type != MachineType::Uint64());
1883   ArchOpcode opcode = kArchNop;
1884   if (type == MachineType::Uint32()) {
1885     opcode = kIA32Word64AtomicNarrowExchangeUint32;
1886   } else if (type == MachineType::Uint16()) {
1887     opcode = kIA32Word64AtomicNarrowExchangeUint16;
1888   } else if (type == MachineType::Uint8()) {
1889     opcode = kIA32Word64AtomicNarrowExchangeUint8;
1890   } else {
1891     UNREACHABLE();
1892     return;
1893   }
1894   IA32OperandGenerator g(this);
1895   Node* base = node->InputAt(0);
1896   Node* index = node->InputAt(1);
1897   Node* value = node->InputAt(2);
1898   AddressingMode addressing_mode;
1899   InstructionOperand value_operand =
1900       (type.representation() == MachineRepresentation::kWord8)
1901           ? g.UseFixed(value, edx)
1902           : g.UseUniqueRegister(value);
1903   InstructionOperand inputs[] = {
1904       value_operand, g.UseUniqueRegister(base),
1905       g.GetEffectiveIndexOperand(index, &addressing_mode)};
1906   InstructionOperand outputs[2];
1907   if (type.representation() == MachineRepresentation::kWord8) {
1908     // Using DefineSameAsFirst requires the register to be unallocated.
1909     outputs[0] = g.DefineAsFixed(NodeProperties::FindProjection(node, 0), edx);
1910   } else {
1911     outputs[0] = g.DefineSameAsFirst(NodeProperties::FindProjection(node, 0));
1912   }
1913   outputs[1] = g.DefineAsRegister(NodeProperties::FindProjection(node, 1));
1914   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
1915   Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs);
1916 }
1917 
VisitWord64AtomicNarrowCompareExchange(Node * node)1918 void InstructionSelector::VisitWord64AtomicNarrowCompareExchange(Node* node) {
1919   MachineType type = AtomicOpType(node->op());
1920   DCHECK(type != MachineType::Uint64());
1921   ArchOpcode opcode = kArchNop;
1922   if (type == MachineType::Uint32()) {
1923     opcode = kIA32Word64AtomicNarrowCompareExchangeUint32;
1924   } else if (type == MachineType::Uint16()) {
1925     opcode = kIA32Word64AtomicNarrowCompareExchangeUint16;
1926   } else if (type == MachineType::Uint8()) {
1927     opcode = kIA32Word64AtomicNarrowCompareExchangeUint8;
1928   } else {
1929     UNREACHABLE();
1930     return;
1931   }
1932   IA32OperandGenerator g(this);
1933   Node* base = node->InputAt(0);
1934   Node* index = node->InputAt(1);
1935   Node* old_value = node->InputAt(2);
1936   Node* new_value = node->InputAt(3);
1937   AddressingMode addressing_mode;
1938   InstructionOperand new_value_operand =
1939       (type.representation() == MachineRepresentation::kWord8)
1940           ? g.UseByteRegister(new_value)
1941           : g.UseUniqueRegister(new_value);
1942   InstructionOperand inputs[] = {
1943       g.UseFixed(old_value, eax), new_value_operand, g.UseUniqueRegister(base),
1944       g.GetEffectiveIndexOperand(index, &addressing_mode)};
1945   InstructionOperand outputs[] = {
1946       g.DefineAsFixed(NodeProperties::FindProjection(node, 0), eax),
1947       g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
1948   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
1949   Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs);
1950 }
1951 
1952 #define SIMD_INT_TYPES(V) \
1953   V(I32x4)                \
1954   V(I16x8)                \
1955   V(I8x16)
1956 
1957 #define SIMD_BINOP_LIST(V) \
1958   V(F32x4Add)              \
1959   V(F32x4AddHoriz)         \
1960   V(F32x4Sub)              \
1961   V(F32x4Mul)              \
1962   V(F32x4Min)              \
1963   V(F32x4Max)              \
1964   V(F32x4Eq)               \
1965   V(F32x4Ne)               \
1966   V(F32x4Lt)               \
1967   V(F32x4Le)               \
1968   V(I32x4Add)              \
1969   V(I32x4AddHoriz)         \
1970   V(I32x4Sub)              \
1971   V(I32x4Mul)              \
1972   V(I32x4MinS)             \
1973   V(I32x4MaxS)             \
1974   V(I32x4Eq)               \
1975   V(I32x4Ne)               \
1976   V(I32x4GtS)              \
1977   V(I32x4GeS)              \
1978   V(I32x4MinU)             \
1979   V(I32x4MaxU)             \
1980   V(I32x4GtU)              \
1981   V(I32x4GeU)              \
1982   V(I16x8SConvertI32x4)    \
1983   V(I16x8Add)              \
1984   V(I16x8AddSaturateS)     \
1985   V(I16x8AddHoriz)         \
1986   V(I16x8Sub)              \
1987   V(I16x8SubSaturateS)     \
1988   V(I16x8Mul)              \
1989   V(I16x8MinS)             \
1990   V(I16x8MaxS)             \
1991   V(I16x8Eq)               \
1992   V(I16x8Ne)               \
1993   V(I16x8GtS)              \
1994   V(I16x8GeS)              \
1995   V(I16x8AddSaturateU)     \
1996   V(I16x8SubSaturateU)     \
1997   V(I16x8MinU)             \
1998   V(I16x8MaxU)             \
1999   V(I16x8GtU)              \
2000   V(I16x8GeU)              \
2001   V(I8x16SConvertI16x8)    \
2002   V(I8x16Add)              \
2003   V(I8x16AddSaturateS)     \
2004   V(I8x16Sub)              \
2005   V(I8x16SubSaturateS)     \
2006   V(I8x16MinS)             \
2007   V(I8x16MaxS)             \
2008   V(I8x16Eq)               \
2009   V(I8x16Ne)               \
2010   V(I8x16GtS)              \
2011   V(I8x16GeS)              \
2012   V(I8x16AddSaturateU)     \
2013   V(I8x16SubSaturateU)     \
2014   V(I8x16MinU)             \
2015   V(I8x16MaxU)             \
2016   V(I8x16GtU)              \
2017   V(I8x16GeU)              \
2018   V(S128And)               \
2019   V(S128Or)                \
2020   V(S128Xor)
2021 
2022 #define SIMD_UNOP_LIST(V)   \
2023   V(F32x4SConvertI32x4)     \
2024   V(F32x4RecipApprox)       \
2025   V(F32x4RecipSqrtApprox)   \
2026   V(I32x4SConvertI16x8Low)  \
2027   V(I32x4SConvertI16x8High) \
2028   V(I32x4Neg)               \
2029   V(I32x4UConvertI16x8Low)  \
2030   V(I32x4UConvertI16x8High) \
2031   V(I16x8SConvertI8x16Low)  \
2032   V(I16x8SConvertI8x16High) \
2033   V(I16x8Neg)               \
2034   V(I16x8UConvertI8x16Low)  \
2035   V(I16x8UConvertI8x16High) \
2036   V(I8x16Neg)
2037 
2038 #define SIMD_UNOP_PREFIX_LIST(V) \
2039   V(F32x4Abs)                    \
2040   V(F32x4Neg)                    \
2041   V(S128Not)
2042 
2043 #define SIMD_ANYTRUE_LIST(V) \
2044   V(S1x4AnyTrue)             \
2045   V(S1x8AnyTrue)             \
2046   V(S1x16AnyTrue)
2047 
2048 #define SIMD_ALLTRUE_LIST(V) \
2049   V(S1x4AllTrue)             \
2050   V(S1x8AllTrue)             \
2051   V(S1x16AllTrue)
2052 
2053 #define SIMD_SHIFT_OPCODES(V) \
2054   V(I32x4Shl)                 \
2055   V(I32x4ShrS)                \
2056   V(I32x4ShrU)                \
2057   V(I16x8Shl)                 \
2058   V(I16x8ShrS)                \
2059   V(I16x8ShrU)                \
2060   V(I8x16Shl)
2061 
2062 #define SIMD_I8X16_RIGHT_SHIFT_OPCODES(V) \
2063   V(I8x16ShrS)                            \
2064   V(I8x16ShrU)
2065 
VisitF32x4Splat(Node * node)2066 void InstructionSelector::VisitF32x4Splat(Node* node) {
2067   VisitRRSimd(this, node, kAVXF32x4Splat, kSSEF32x4Splat);
2068 }
2069 
VisitF32x4ExtractLane(Node * node)2070 void InstructionSelector::VisitF32x4ExtractLane(Node* node) {
2071   VisitRRISimd(this, node, kAVXF32x4ExtractLane, kSSEF32x4ExtractLane);
2072 }
2073 
VisitF32x4UConvertI32x4(Node * node)2074 void InstructionSelector::VisitF32x4UConvertI32x4(Node* node) {
2075   VisitRRSimd(this, node, kAVXF32x4UConvertI32x4, kSSEF32x4UConvertI32x4);
2076 }
2077 
VisitI32x4SConvertF32x4(Node * node)2078 void InstructionSelector::VisitI32x4SConvertF32x4(Node* node) {
2079   VisitRRSimd(this, node, kAVXI32x4SConvertF32x4, kSSEI32x4SConvertF32x4);
2080 }
2081 
VisitI32x4UConvertF32x4(Node * node)2082 void InstructionSelector::VisitI32x4UConvertF32x4(Node* node) {
2083   IA32OperandGenerator g(this);
2084   InstructionOperand temps[] = {g.TempSimd128Register()};
2085   InstructionCode opcode =
2086       IsSupported(AVX) ? kAVXI32x4UConvertF32x4 : kSSEI32x4UConvertF32x4;
2087   Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
2088        arraysize(temps), temps);
2089 }
2090 
VisitI8x16Mul(Node * node)2091 void InstructionSelector::VisitI8x16Mul(Node* node) {
2092   IA32OperandGenerator g(this);
2093   InstructionOperand operand0 = g.UseUniqueRegister(node->InputAt(0));
2094   InstructionOperand operand1 = g.UseUniqueRegister(node->InputAt(1));
2095   InstructionOperand temps[] = {g.TempSimd128Register()};
2096   if (IsSupported(AVX)) {
2097     Emit(kAVXI8x16Mul, g.DefineAsRegister(node), operand0, operand1,
2098          arraysize(temps), temps);
2099   } else {
2100     Emit(kSSEI8x16Mul, g.DefineSameAsFirst(node), operand0, operand1,
2101          arraysize(temps), temps);
2102   }
2103 }
2104 
VisitS128Zero(Node * node)2105 void InstructionSelector::VisitS128Zero(Node* node) {
2106   IA32OperandGenerator g(this);
2107   Emit(kIA32S128Zero, g.DefineAsRegister(node));
2108 }
2109 
VisitS128Select(Node * node)2110 void InstructionSelector::VisitS128Select(Node* node) {
2111   IA32OperandGenerator g(this);
2112   InstructionOperand operand2 = g.UseRegister(node->InputAt(2));
2113   if (IsSupported(AVX)) {
2114     Emit(kAVXS128Select, g.DefineAsRegister(node), g.Use(node->InputAt(0)),
2115          g.Use(node->InputAt(1)), operand2);
2116   } else {
2117     Emit(kSSES128Select, g.DefineSameAsFirst(node),
2118          g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)),
2119          operand2);
2120   }
2121 }
2122 
2123 #define VISIT_SIMD_SPLAT(Type)                               \
2124   void InstructionSelector::Visit##Type##Splat(Node* node) { \
2125     VisitRO(this, node, kIA32##Type##Splat);                 \
2126   }
2127 SIMD_INT_TYPES(VISIT_SIMD_SPLAT)
2128 #undef VISIT_SIMD_SPLAT
2129 
2130 #define VISIT_SIMD_EXTRACT_LANE(Type)                              \
2131   void InstructionSelector::Visit##Type##ExtractLane(Node* node) { \
2132     VisitRRISimd(this, node, kIA32##Type##ExtractLane);            \
2133   }
SIMD_INT_TYPES(VISIT_SIMD_EXTRACT_LANE)2134 SIMD_INT_TYPES(VISIT_SIMD_EXTRACT_LANE)
2135 #undef VISIT_SIMD_EXTRACT_LANE
2136 
2137 #define VISIT_SIMD_REPLACE_LANE(Type)                                    \
2138   void InstructionSelector::Visit##Type##ReplaceLane(Node* node) {       \
2139     IA32OperandGenerator g(this);                                        \
2140     InstructionOperand operand0 = g.UseRegister(node->InputAt(0));       \
2141     InstructionOperand operand1 =                                        \
2142         g.UseImmediate(OpParameter<int32_t>(node->op()));                \
2143     InstructionOperand operand2 = g.Use(node->InputAt(1));               \
2144     if (IsSupported(AVX)) {                                              \
2145       Emit(kAVX##Type##ReplaceLane, g.DefineAsRegister(node), operand0,  \
2146            operand1, operand2);                                          \
2147     } else {                                                             \
2148       Emit(kSSE##Type##ReplaceLane, g.DefineSameAsFirst(node), operand0, \
2149            operand1, operand2);                                          \
2150     }                                                                    \
2151   }
2152 SIMD_INT_TYPES(VISIT_SIMD_REPLACE_LANE)
2153 VISIT_SIMD_REPLACE_LANE(F32x4)
2154 #undef VISIT_SIMD_REPLACE_LANE
2155 #undef SIMD_INT_TYPES
2156 
2157 #define VISIT_SIMD_SHIFT(Opcode)                          \
2158   void InstructionSelector::Visit##Opcode(Node* node) {   \
2159     VisitRRISimd(this, node, kAVX##Opcode, kSSE##Opcode); \
2160   }
2161 SIMD_SHIFT_OPCODES(VISIT_SIMD_SHIFT)
2162 #undef VISIT_SIMD_SHIFT
2163 #undef SIMD_SHIFT_OPCODES
2164 
2165 #define VISIT_SIMD_I8X16_RIGHT_SHIFT(Op)            \
2166   void InstructionSelector::Visit##Op(Node* node) { \
2167     VisitRRISimd(this, node, kIA32##Op);            \
2168   }
2169 
2170 SIMD_I8X16_RIGHT_SHIFT_OPCODES(VISIT_SIMD_I8X16_RIGHT_SHIFT)
2171 #undef SIMD_I8X16_RIGHT_SHIFT_OPCODES
2172 #undef VISIT_SIMD_I8X16_RIGHT_SHIFT
2173 
2174 #define VISIT_SIMD_UNOP(Opcode)                                             \
2175   void InstructionSelector::Visit##Opcode(Node* node) {                     \
2176     IA32OperandGenerator g(this);                                           \
2177     Emit(kIA32##Opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0))); \
2178   }
2179 SIMD_UNOP_LIST(VISIT_SIMD_UNOP)
2180 #undef VISIT_SIMD_UNOP
2181 #undef SIMD_UNOP_LIST
2182 
2183 #define VISIT_SIMD_UNOP_PREFIX(Opcode)                                       \
2184   void InstructionSelector::Visit##Opcode(Node* node) {                      \
2185     IA32OperandGenerator g(this);                                            \
2186     InstructionCode opcode = IsSupported(AVX) ? kAVX##Opcode : kSSE##Opcode; \
2187     Emit(opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0)));         \
2188   }
2189 SIMD_UNOP_PREFIX_LIST(VISIT_SIMD_UNOP_PREFIX)
2190 #undef VISIT_SIMD_UNOP_PREFIX
2191 #undef SIMD_UNOP_PREFIX_LIST
2192 
2193 #define VISIT_SIMD_ANYTRUE(Opcode)                                  \
2194   void InstructionSelector::Visit##Opcode(Node* node) {             \
2195     IA32OperandGenerator g(this);                                   \
2196     InstructionOperand temps[] = {g.TempRegister()};                \
2197     Emit(kIA32##Opcode, g.DefineAsRegister(node),                   \
2198          g.UseRegister(node->InputAt(0)), arraysize(temps), temps); \
2199   }
2200 SIMD_ANYTRUE_LIST(VISIT_SIMD_ANYTRUE)
2201 #undef VISIT_SIMD_ANYTRUE
2202 #undef SIMD_ANYTRUE_LIST
2203 
2204 #define VISIT_SIMD_ALLTRUE(Opcode)                                         \
2205   void InstructionSelector::Visit##Opcode(Node* node) {                    \
2206     IA32OperandGenerator g(this);                                          \
2207     InstructionOperand temps[] = {g.TempRegister()};                       \
2208     Emit(kIA32##Opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0)), \
2209          arraysize(temps), temps);                                         \
2210   }
2211 SIMD_ALLTRUE_LIST(VISIT_SIMD_ALLTRUE)
2212 #undef VISIT_SIMD_ALLTRUE
2213 #undef SIMD_ALLTRUE_LIST
2214 
2215 #define VISIT_SIMD_BINOP(Opcode)                           \
2216   void InstructionSelector::Visit##Opcode(Node* node) {    \
2217     VisitRROFloat(this, node, kAVX##Opcode, kSSE##Opcode); \
2218   }
2219 SIMD_BINOP_LIST(VISIT_SIMD_BINOP)
2220 #undef VISIT_SIMD_BINOP
2221 #undef SIMD_BINOP_LIST
2222 
2223 void VisitPack(InstructionSelector* selector, Node* node, ArchOpcode avx_opcode,
2224                ArchOpcode sse_opcode) {
2225   IA32OperandGenerator g(selector);
2226   InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
2227   InstructionOperand operand1 = g.Use(node->InputAt(1));
2228   if (selector->IsSupported(AVX)) {
2229     selector->Emit(avx_opcode, g.DefineSameAsFirst(node), operand0, operand1);
2230   } else {
2231     selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1);
2232   }
2233 }
2234 
VisitI16x8UConvertI32x4(Node * node)2235 void InstructionSelector::VisitI16x8UConvertI32x4(Node* node) {
2236   VisitPack(this, node, kAVXI16x8UConvertI32x4, kSSEI16x8UConvertI32x4);
2237 }
2238 
VisitI8x16UConvertI16x8(Node * node)2239 void InstructionSelector::VisitI8x16UConvertI16x8(Node* node) {
2240   VisitPack(this, node, kAVXI8x16UConvertI16x8, kSSEI8x16UConvertI16x8);
2241 }
2242 
VisitInt32AbsWithOverflow(Node * node)2243 void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
2244   UNREACHABLE();
2245 }
2246 
VisitInt64AbsWithOverflow(Node * node)2247 void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
2248   UNREACHABLE();
2249 }
2250 
2251 namespace {
2252 
2253 // Packs a 4 lane shuffle into a single imm8 suitable for use by pshufd,
2254 // pshuflw, and pshufhw.
PackShuffle4(uint8_t * shuffle)2255 uint8_t PackShuffle4(uint8_t* shuffle) {
2256   return (shuffle[0] & 3) | ((shuffle[1] & 3) << 2) | ((shuffle[2] & 3) << 4) |
2257          ((shuffle[3] & 3) << 6);
2258 }
2259 
2260 // Gets an 8 bit lane mask suitable for 16x8 pblendw.
PackBlend8(const uint8_t * shuffle16x8)2261 uint8_t PackBlend8(const uint8_t* shuffle16x8) {
2262   int8_t result = 0;
2263   for (int i = 0; i < 8; ++i) {
2264     result |= (shuffle16x8[i] >= 8 ? 1 : 0) << i;
2265   }
2266   return result;
2267 }
2268 
2269 // Gets an 8 bit lane mask suitable for 32x4 pblendw.
PackBlend4(const uint8_t * shuffle32x4)2270 uint8_t PackBlend4(const uint8_t* shuffle32x4) {
2271   int8_t result = 0;
2272   for (int i = 0; i < 4; ++i) {
2273     result |= (shuffle32x4[i] >= 4 ? 0x3 : 0) << (i * 2);
2274   }
2275   return result;
2276 }
2277 
2278 // Returns true if shuffle can be decomposed into two 16x4 half shuffles
2279 // followed by a 16x8 blend.
2280 // E.g. [3 2 1 0 15 14 13 12].
TryMatch16x8HalfShuffle(uint8_t * shuffle16x8,uint8_t * blend_mask)2281 bool TryMatch16x8HalfShuffle(uint8_t* shuffle16x8, uint8_t* blend_mask) {
2282   *blend_mask = 0;
2283   for (int i = 0; i < 8; i++) {
2284     if ((shuffle16x8[i] & 0x4) != (i & 0x4)) return false;
2285     *blend_mask |= (shuffle16x8[i] > 7 ? 1 : 0) << i;
2286   }
2287   return true;
2288 }
2289 
2290 struct ShuffleEntry {
2291   uint8_t shuffle[kSimd128Size];
2292   ArchOpcode opcode;
2293   ArchOpcode avx_opcode;
2294   bool src0_needs_reg;
2295   bool src1_needs_reg;
2296 };
2297 
2298 // Shuffles that map to architecture-specific instruction sequences. These are
2299 // matched very early, so we shouldn't include shuffles that match better in
2300 // later tests, like 32x4 and 16x8 shuffles. In general, these patterns should
2301 // map to either a single instruction, or be finer grained, such as zip/unzip or
2302 // transpose patterns.
2303 static const ShuffleEntry arch_shuffles[] = {
2304     {{0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23},
2305      kIA32S64x2UnpackLow,
2306      kIA32S64x2UnpackLow,
2307      true,
2308      false},
2309     {{8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31},
2310      kIA32S64x2UnpackHigh,
2311      kIA32S64x2UnpackHigh,
2312      true,
2313      false},
2314     {{0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23},
2315      kIA32S32x4UnpackLow,
2316      kIA32S32x4UnpackLow,
2317      true,
2318      false},
2319     {{8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31},
2320      kIA32S32x4UnpackHigh,
2321      kIA32S32x4UnpackHigh,
2322      true,
2323      false},
2324     {{0, 1, 16, 17, 2, 3, 18, 19, 4, 5, 20, 21, 6, 7, 22, 23},
2325      kIA32S16x8UnpackLow,
2326      kIA32S16x8UnpackLow,
2327      true,
2328      false},
2329     {{8, 9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31},
2330      kIA32S16x8UnpackHigh,
2331      kIA32S16x8UnpackHigh,
2332      true,
2333      false},
2334     {{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23},
2335      kIA32S8x16UnpackLow,
2336      kIA32S8x16UnpackLow,
2337      true,
2338      false},
2339     {{8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31},
2340      kIA32S8x16UnpackHigh,
2341      kIA32S8x16UnpackHigh,
2342      true,
2343      false},
2344 
2345     {{0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29},
2346      kSSES16x8UnzipLow,
2347      kAVXS16x8UnzipLow,
2348      true,
2349      false},
2350     {{2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31},
2351      kSSES16x8UnzipHigh,
2352      kAVXS16x8UnzipHigh,
2353      true,
2354      true},
2355     {{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30},
2356      kSSES8x16UnzipLow,
2357      kAVXS8x16UnzipLow,
2358      true,
2359      true},
2360     {{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31},
2361      kSSES8x16UnzipHigh,
2362      kAVXS8x16UnzipHigh,
2363      true,
2364      true},
2365 
2366     {{0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30},
2367      kSSES8x16TransposeLow,
2368      kAVXS8x16TransposeLow,
2369      true,
2370      true},
2371     {{1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31},
2372      kSSES8x16TransposeHigh,
2373      kAVXS8x16TransposeHigh,
2374      true,
2375      true},
2376     {{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8},
2377      kSSES8x8Reverse,
2378      kAVXS8x8Reverse,
2379      false,
2380      false},
2381     {{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12},
2382      kSSES8x4Reverse,
2383      kAVXS8x4Reverse,
2384      false,
2385      false},
2386     {{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14},
2387      kSSES8x2Reverse,
2388      kAVXS8x2Reverse,
2389      true,
2390      true}};
2391 
TryMatchArchShuffle(const uint8_t * shuffle,const ShuffleEntry * table,size_t num_entries,bool is_swizzle,const ShuffleEntry ** arch_shuffle)2392 bool TryMatchArchShuffle(const uint8_t* shuffle, const ShuffleEntry* table,
2393                          size_t num_entries, bool is_swizzle,
2394                          const ShuffleEntry** arch_shuffle) {
2395   uint8_t mask = is_swizzle ? kSimd128Size - 1 : 2 * kSimd128Size - 1;
2396   for (size_t i = 0; i < num_entries; ++i) {
2397     const ShuffleEntry& entry = table[i];
2398     int j = 0;
2399     for (; j < kSimd128Size; ++j) {
2400       if ((entry.shuffle[j] & mask) != (shuffle[j] & mask)) {
2401         break;
2402       }
2403     }
2404     if (j == kSimd128Size) {
2405       *arch_shuffle = &entry;
2406       return true;
2407     }
2408   }
2409   return false;
2410 }
2411 
2412 }  // namespace
2413 
VisitS8x16Shuffle(Node * node)2414 void InstructionSelector::VisitS8x16Shuffle(Node* node) {
2415   uint8_t shuffle[kSimd128Size];
2416   bool is_swizzle;
2417   CanonicalizeShuffle(node, shuffle, &is_swizzle);
2418 
2419   int imm_count = 0;
2420   static const int kMaxImms = 6;
2421   uint32_t imms[kMaxImms];
2422   int temp_count = 0;
2423   static const int kMaxTemps = 2;
2424   InstructionOperand temps[kMaxTemps];
2425 
2426   IA32OperandGenerator g(this);
2427   bool use_avx = CpuFeatures::IsSupported(AVX);
2428   // AVX and swizzles don't generally need DefineSameAsFirst to avoid a move.
2429   bool no_same_as_first = use_avx || is_swizzle;
2430   // We generally need UseRegister for input0, Use for input1.
2431   bool src0_needs_reg = true;
2432   bool src1_needs_reg = false;
2433   ArchOpcode opcode = kIA32S8x16Shuffle;  // general shuffle is the default
2434 
2435   uint8_t offset;
2436   uint8_t shuffle32x4[4];
2437   uint8_t shuffle16x8[8];
2438   int index;
2439   const ShuffleEntry* arch_shuffle;
2440   if (TryMatchConcat(shuffle, &offset)) {
2441     // Swap inputs from the normal order for (v)palignr.
2442     SwapShuffleInputs(node);
2443     is_swizzle = false;  // It's simpler to just handle the general case.
2444     no_same_as_first = use_avx;  // SSE requires same-as-first.
2445     opcode = kIA32S8x16Alignr;
2446     // palignr takes a single imm8 offset.
2447     imms[imm_count++] = offset;
2448   } else if (TryMatchArchShuffle(shuffle, arch_shuffles,
2449                                  arraysize(arch_shuffles), is_swizzle,
2450                                  &arch_shuffle)) {
2451     opcode = use_avx ? arch_shuffle->avx_opcode : arch_shuffle->opcode;
2452     src0_needs_reg = !use_avx || arch_shuffle->src0_needs_reg;
2453     // SSE can't take advantage of both operands in registers and needs
2454     // same-as-first.
2455     src1_needs_reg = use_avx && arch_shuffle->src1_needs_reg;
2456     no_same_as_first = use_avx;
2457   } else if (TryMatch32x4Shuffle(shuffle, shuffle32x4)) {
2458     uint8_t shuffle_mask = PackShuffle4(shuffle32x4);
2459     if (is_swizzle) {
2460       if (TryMatchIdentity(shuffle)) {
2461         // Bypass normal shuffle code generation in this case.
2462         EmitIdentity(node);
2463         return;
2464       } else {
2465         // pshufd takes a single imm8 shuffle mask.
2466         opcode = kIA32S32x4Swizzle;
2467         no_same_as_first = true;
2468         src0_needs_reg = false;
2469         imms[imm_count++] = shuffle_mask;
2470       }
2471     } else {
2472       // 2 operand shuffle
2473       // A blend is more efficient than a general 32x4 shuffle; try it first.
2474       if (TryMatchBlend(shuffle)) {
2475         opcode = kIA32S16x8Blend;
2476         uint8_t blend_mask = PackBlend4(shuffle32x4);
2477         imms[imm_count++] = blend_mask;
2478       } else {
2479         opcode = kIA32S32x4Shuffle;
2480         no_same_as_first = true;
2481         src0_needs_reg = false;
2482         imms[imm_count++] = shuffle_mask;
2483         int8_t blend_mask = PackBlend4(shuffle32x4);
2484         imms[imm_count++] = blend_mask;
2485       }
2486     }
2487   } else if (TryMatch16x8Shuffle(shuffle, shuffle16x8)) {
2488     uint8_t blend_mask;
2489     if (TryMatchBlend(shuffle)) {
2490       opcode = kIA32S16x8Blend;
2491       blend_mask = PackBlend8(shuffle16x8);
2492       imms[imm_count++] = blend_mask;
2493     } else if (TryMatchDup<8>(shuffle, &index)) {
2494       opcode = kIA32S16x8Dup;
2495       src0_needs_reg = false;
2496       imms[imm_count++] = index;
2497     } else if (TryMatch16x8HalfShuffle(shuffle16x8, &blend_mask)) {
2498       opcode = is_swizzle ? kIA32S16x8HalfShuffle1 : kIA32S16x8HalfShuffle2;
2499       // Half-shuffles don't need DefineSameAsFirst or UseRegister(src0).
2500       no_same_as_first = true;
2501       src0_needs_reg = false;
2502       uint8_t mask_lo = PackShuffle4(shuffle16x8);
2503       uint8_t mask_hi = PackShuffle4(shuffle16x8 + 4);
2504       imms[imm_count++] = mask_lo;
2505       imms[imm_count++] = mask_hi;
2506       if (!is_swizzle) imms[imm_count++] = blend_mask;
2507     }
2508   } else if (TryMatchDup<16>(shuffle, &index)) {
2509     opcode = kIA32S8x16Dup;
2510     no_same_as_first = use_avx;
2511     src0_needs_reg = true;
2512     imms[imm_count++] = index;
2513   }
2514   if (opcode == kIA32S8x16Shuffle) {
2515     // Use same-as-first for general swizzle, but not shuffle.
2516     no_same_as_first = !is_swizzle;
2517     src0_needs_reg = !no_same_as_first;
2518     imms[imm_count++] = Pack4Lanes(shuffle);
2519     imms[imm_count++] = Pack4Lanes(shuffle + 4);
2520     imms[imm_count++] = Pack4Lanes(shuffle + 8);
2521     imms[imm_count++] = Pack4Lanes(shuffle + 12);
2522     temps[temp_count++] = g.TempRegister();
2523   }
2524 
2525   // Use DefineAsRegister(node) and Use(src0) if we can without forcing an extra
2526   // move instruction in the CodeGenerator.
2527   Node* input0 = node->InputAt(0);
2528   InstructionOperand dst =
2529       no_same_as_first ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node);
2530   InstructionOperand src0 =
2531       src0_needs_reg ? g.UseRegister(input0) : g.Use(input0);
2532 
2533   int input_count = 0;
2534   InstructionOperand inputs[2 + kMaxImms + kMaxTemps];
2535   inputs[input_count++] = src0;
2536   if (!is_swizzle) {
2537     Node* input1 = node->InputAt(1);
2538     inputs[input_count++] =
2539         src1_needs_reg ? g.UseRegister(input1) : g.Use(input1);
2540   }
2541   for (int i = 0; i < imm_count; ++i) {
2542     inputs[input_count++] = g.UseImmediate(imms[i]);
2543   }
2544   Emit(opcode, 1, &dst, input_count, inputs, temp_count, temps);
2545 }
2546 
2547 // static
2548 MachineOperatorBuilder::Flags
SupportedMachineOperatorFlags()2549 InstructionSelector::SupportedMachineOperatorFlags() {
2550   MachineOperatorBuilder::Flags flags =
2551       MachineOperatorBuilder::kWord32ShiftIsSafe |
2552       MachineOperatorBuilder::kWord32Ctz |
2553       MachineOperatorBuilder::kSpeculationFence;
2554   if (CpuFeatures::IsSupported(POPCNT)) {
2555     flags |= MachineOperatorBuilder::kWord32Popcnt;
2556   }
2557   if (CpuFeatures::IsSupported(SSE4_1)) {
2558     flags |= MachineOperatorBuilder::kFloat32RoundDown |
2559              MachineOperatorBuilder::kFloat64RoundDown |
2560              MachineOperatorBuilder::kFloat32RoundUp |
2561              MachineOperatorBuilder::kFloat64RoundUp |
2562              MachineOperatorBuilder::kFloat32RoundTruncate |
2563              MachineOperatorBuilder::kFloat64RoundTruncate |
2564              MachineOperatorBuilder::kFloat32RoundTiesEven |
2565              MachineOperatorBuilder::kFloat64RoundTiesEven;
2566   }
2567   return flags;
2568 }
2569 
2570 // static
2571 MachineOperatorBuilder::AlignmentRequirements
AlignmentRequirements()2572 InstructionSelector::AlignmentRequirements() {
2573   return MachineOperatorBuilder::AlignmentRequirements::
2574       FullUnalignedAccessSupport();
2575 }
2576 
2577 }  // namespace compiler
2578 }  // namespace internal
2579 }  // namespace v8
2580