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