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.
5 #include "src/compiler/instruction-selector-impl.h"
6 #include "src/compiler/node-matchers.h"
7 #include "src/compiler/node-properties.h"
13 // Adds IA32-specific methods for generating operands.
14 class IA32OperandGenerator FINAL : public OperandGenerator {
16 explicit IA32OperandGenerator(InstructionSelector* selector)
17 : OperandGenerator(selector) {}
19 InstructionOperand UseByteRegister(Node* node) {
20 // TODO(dcarney): relax constraint.
21 return UseFixed(node, edx);
24 bool CanBeImmediate(Node* node) {
25 switch (node->opcode()) {
26 case IrOpcode::kInt32Constant:
27 case IrOpcode::kNumberConstant:
28 case IrOpcode::kExternalConstant:
30 case IrOpcode::kHeapConstant: {
31 // Constants in new space cannot be used as immediates in V8 because
32 // the GC does not scan code objects when collecting the new generation.
33 Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node);
34 Isolate* isolate = value.handle()->GetIsolate();
35 return !isolate->heap()->InNewSpace(*value.handle());
42 AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base,
43 Node* displacement_node,
44 InstructionOperand inputs[],
45 size_t* input_count) {
46 AddressingMode mode = kMode_MRI;
47 int32_t displacement = (displacement_node == NULL)
49 : OpParameter<int32_t>(displacement_node);
51 if (base->opcode() == IrOpcode::kInt32Constant) {
52 displacement += OpParameter<int32_t>(base);
57 inputs[(*input_count)++] = UseRegister(base);
59 DCHECK(scale >= 0 && scale <= 3);
60 inputs[(*input_count)++] = UseRegister(index);
61 if (displacement != 0) {
62 inputs[(*input_count)++] = TempImmediate(displacement);
63 static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
64 kMode_MR4I, kMode_MR8I};
65 mode = kMRnI_modes[scale];
67 static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2,
68 kMode_MR4, kMode_MR8};
69 mode = kMRn_modes[scale];
72 if (displacement == 0) {
75 inputs[(*input_count)++] = TempImmediate(displacement);
80 DCHECK(scale >= 0 && scale <= 3);
82 inputs[(*input_count)++] = UseRegister(index);
83 if (displacement != 0) {
84 inputs[(*input_count)++] = TempImmediate(displacement);
85 static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I,
86 kMode_M4I, kMode_M8I};
87 mode = kMnI_modes[scale];
89 static const AddressingMode kMn_modes[] = {kMode_MR, kMode_M2,
91 mode = kMn_modes[scale];
94 inputs[(*input_count)++] = TempImmediate(displacement);
101 AddressingMode GetEffectiveAddressMemoryOperand(Node* node,
102 InstructionOperand inputs[],
103 size_t* input_count) {
104 BaseWithIndexAndDisplacement32Matcher m(node, true);
106 if ((m.displacement() == NULL || CanBeImmediate(m.displacement()))) {
107 return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(),
108 m.displacement(), inputs, input_count);
110 inputs[(*input_count)++] = UseRegister(node->InputAt(0));
111 inputs[(*input_count)++] = UseRegister(node->InputAt(1));
116 bool CanBeBetterLeftOperand(Node* node) const {
117 return !selector()->IsLive(node);
122 static void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
124 IA32OperandGenerator g(selector);
125 selector->Emit(opcode, g.DefineAsRegister(node),
126 g.UseRegister(node->InputAt(0)));
130 void InstructionSelector::VisitLoad(Node* node) {
131 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
132 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
135 // TODO(titzer): signed/unsigned small loads
143 case kRepBit: // Fall through.
145 opcode = typ == kTypeInt32 ? kIA32Movsxbl : kIA32Movzxbl;
148 opcode = typ == kTypeInt32 ? kIA32Movsxwl : kIA32Movzxwl;
150 case kRepTagged: // Fall through.
159 IA32OperandGenerator g(this);
160 InstructionOperand outputs[1];
161 outputs[0] = g.DefineAsRegister(node);
162 InstructionOperand inputs[3];
163 size_t input_count = 0;
164 AddressingMode mode =
165 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
166 InstructionCode code = opcode | AddressingModeField::encode(mode);
167 Emit(code, 1, outputs, input_count, inputs);
171 void InstructionSelector::VisitStore(Node* node) {
172 IA32OperandGenerator g(this);
173 Node* base = node->InputAt(0);
174 Node* index = node->InputAt(1);
175 Node* value = node->InputAt(2);
177 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
178 MachineType rep = RepresentationOf(store_rep.machine_type());
179 if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
180 DCHECK_EQ(kRepTagged, rep);
181 // TODO(dcarney): refactor RecordWrite function to take temp registers
182 // and pass them here instead of using fixed regs
183 // TODO(dcarney): handle immediate indices.
184 InstructionOperand temps[] = {g.TempRegister(ecx), g.TempRegister(edx)};
185 Emit(kIA32StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, ebx),
186 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps),
190 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
200 case kRepBit: // Fall through.
207 case kRepTagged: // Fall through.
216 InstructionOperand val;
217 if (g.CanBeImmediate(value)) {
218 val = g.UseImmediate(value);
219 } else if (rep == kRepWord8 || rep == kRepBit) {
220 val = g.UseByteRegister(value);
222 val = g.UseRegister(value);
225 InstructionOperand inputs[4];
226 size_t input_count = 0;
227 AddressingMode mode =
228 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
229 InstructionCode code = opcode | AddressingModeField::encode(mode);
230 inputs[input_count++] = val;
231 Emit(code, 0, static_cast<InstructionOperand*>(NULL), input_count, inputs);
235 void InstructionSelector::VisitCheckedLoad(Node* node) {
236 MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
237 MachineType typ = TypeOf(OpParameter<MachineType>(node));
238 IA32OperandGenerator g(this);
239 Node* const buffer = node->InputAt(0);
240 Node* const offset = node->InputAt(1);
241 Node* const length = node->InputAt(2);
245 opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
248 opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
251 opcode = kCheckedLoadWord32;
254 opcode = kCheckedLoadFloat32;
257 opcode = kCheckedLoadFloat64;
263 InstructionOperand offset_operand = g.UseRegister(offset);
264 InstructionOperand length_operand =
265 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
266 if (g.CanBeImmediate(buffer)) {
267 Emit(opcode | AddressingModeField::encode(kMode_MRI),
268 g.DefineAsRegister(node), offset_operand, length_operand,
269 offset_operand, g.UseImmediate(buffer));
271 Emit(opcode | AddressingModeField::encode(kMode_MR1),
272 g.DefineAsRegister(node), offset_operand, length_operand,
273 g.UseRegister(buffer), offset_operand);
278 void InstructionSelector::VisitCheckedStore(Node* node) {
279 MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
280 IA32OperandGenerator g(this);
281 Node* const buffer = node->InputAt(0);
282 Node* const offset = node->InputAt(1);
283 Node* const length = node->InputAt(2);
284 Node* const value = node->InputAt(3);
288 opcode = kCheckedStoreWord8;
291 opcode = kCheckedStoreWord16;
294 opcode = kCheckedStoreWord32;
297 opcode = kCheckedStoreFloat32;
300 opcode = kCheckedStoreFloat64;
306 InstructionOperand value_operand =
307 g.CanBeImmediate(value)
308 ? g.UseImmediate(value)
309 : ((rep == kRepWord8 || rep == kRepBit) ? g.UseByteRegister(value)
310 : g.UseRegister(value));
311 InstructionOperand offset_operand = g.UseRegister(offset);
312 InstructionOperand length_operand =
313 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
314 if (g.CanBeImmediate(buffer)) {
315 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
316 offset_operand, length_operand, value_operand, offset_operand,
317 g.UseImmediate(buffer));
319 Emit(opcode | AddressingModeField::encode(kMode_MR1), g.NoOutput(),
320 offset_operand, length_operand, value_operand, g.UseRegister(buffer),
326 // Shared routine for multiple binary operations.
327 static void VisitBinop(InstructionSelector* selector, Node* node,
328 InstructionCode opcode, FlagsContinuation* cont) {
329 IA32OperandGenerator g(selector);
330 Int32BinopMatcher m(node);
331 Node* left = m.left().node();
332 Node* right = m.right().node();
333 InstructionOperand inputs[4];
334 size_t input_count = 0;
335 InstructionOperand outputs[2];
336 size_t output_count = 0;
338 // TODO(turbofan): match complex addressing modes.
340 // If both inputs refer to the same operand, enforce allocating a register
341 // for both of them to ensure that we don't end up generating code like
344 // mov eax, [ebp-0x10]
345 // add eax, [ebp-0x10]
347 InstructionOperand const input = g.UseRegister(left);
348 inputs[input_count++] = input;
349 inputs[input_count++] = input;
350 } else if (g.CanBeImmediate(right)) {
351 inputs[input_count++] = g.UseRegister(left);
352 inputs[input_count++] = g.UseImmediate(right);
354 if (node->op()->HasProperty(Operator::kCommutative) &&
355 g.CanBeBetterLeftOperand(right)) {
356 std::swap(left, right);
358 inputs[input_count++] = g.UseRegister(left);
359 inputs[input_count++] = g.Use(right);
362 if (cont->IsBranch()) {
363 inputs[input_count++] = g.Label(cont->true_block());
364 inputs[input_count++] = g.Label(cont->false_block());
367 outputs[output_count++] = g.DefineSameAsFirst(node);
369 // TODO(turbofan): Use byte register here.
370 outputs[output_count++] = g.DefineAsRegister(cont->result());
373 DCHECK_NE(0u, input_count);
374 DCHECK_NE(0u, output_count);
375 DCHECK_GE(arraysize(inputs), input_count);
376 DCHECK_GE(arraysize(outputs), output_count);
378 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
379 outputs, input_count, inputs);
380 if (cont->IsBranch()) instr->MarkAsControl();
384 // Shared routine for multiple binary operations.
385 static void VisitBinop(InstructionSelector* selector, Node* node,
386 InstructionCode opcode) {
387 FlagsContinuation cont;
388 VisitBinop(selector, node, opcode, &cont);
392 void InstructionSelector::VisitWord32And(Node* node) {
393 VisitBinop(this, node, kIA32And);
397 void InstructionSelector::VisitWord32Or(Node* node) {
398 VisitBinop(this, node, kIA32Or);
402 void InstructionSelector::VisitWord32Xor(Node* node) {
403 IA32OperandGenerator g(this);
404 Int32BinopMatcher m(node);
405 if (m.right().Is(-1)) {
406 Emit(kIA32Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()));
408 VisitBinop(this, node, kIA32Xor);
413 // Shared routine for multiple shift operations.
414 static inline void VisitShift(InstructionSelector* selector, Node* node,
416 IA32OperandGenerator g(selector);
417 Node* left = node->InputAt(0);
418 Node* right = node->InputAt(1);
420 if (g.CanBeImmediate(right)) {
421 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
422 g.UseImmediate(right));
424 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
425 g.UseFixed(right, ecx));
432 void VisitMulHigh(InstructionSelector* selector, Node* node,
434 IA32OperandGenerator g(selector);
435 selector->Emit(opcode, g.DefineAsFixed(node, edx),
436 g.UseFixed(node->InputAt(0), eax),
437 g.UseUniqueRegister(node->InputAt(1)));
441 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
442 IA32OperandGenerator g(selector);
443 InstructionOperand temps[] = {g.TempRegister(edx)};
444 selector->Emit(opcode, g.DefineAsFixed(node, eax),
445 g.UseFixed(node->InputAt(0), eax),
446 g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
450 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
451 IA32OperandGenerator g(selector);
452 selector->Emit(opcode, g.DefineAsFixed(node, edx),
453 g.UseFixed(node->InputAt(0), eax),
454 g.UseUnique(node->InputAt(1)));
457 void EmitLea(InstructionSelector* selector, Node* result, Node* index,
458 int scale, Node* base, Node* displacement) {
459 IA32OperandGenerator g(selector);
460 InstructionOperand inputs[4];
461 size_t input_count = 0;
462 AddressingMode mode = g.GenerateMemoryOperandInputs(
463 index, scale, base, displacement, inputs, &input_count);
465 DCHECK_NE(0, static_cast<int>(input_count));
466 DCHECK_GE(arraysize(inputs), input_count);
468 InstructionOperand outputs[1];
469 outputs[0] = g.DefineAsRegister(result);
471 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
473 selector->Emit(opcode, 1, outputs, input_count, inputs);
479 void InstructionSelector::VisitWord32Shl(Node* node) {
480 Int32ScaleMatcher m(node, true);
482 Node* index = node->InputAt(0);
483 Node* base = m.power_of_two_plus_one() ? index : NULL;
484 EmitLea(this, node, index, m.scale(), base, NULL);
487 VisitShift(this, node, kIA32Shl);
491 void InstructionSelector::VisitWord32Shr(Node* node) {
492 VisitShift(this, node, kIA32Shr);
496 void InstructionSelector::VisitWord32Sar(Node* node) {
497 VisitShift(this, node, kIA32Sar);
501 void InstructionSelector::VisitWord32Ror(Node* node) {
502 VisitShift(this, node, kIA32Ror);
506 void InstructionSelector::VisitInt32Add(Node* node) {
507 IA32OperandGenerator g(this);
509 // Try to match the Add to a lea pattern
510 BaseWithIndexAndDisplacement32Matcher m(node);
512 (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) {
513 InstructionOperand inputs[4];
514 size_t input_count = 0;
515 AddressingMode mode = g.GenerateMemoryOperandInputs(
516 m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count);
518 DCHECK_NE(0, static_cast<int>(input_count));
519 DCHECK_GE(arraysize(inputs), input_count);
521 InstructionOperand outputs[1];
522 outputs[0] = g.DefineAsRegister(node);
524 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
525 Emit(opcode, 1, outputs, input_count, inputs);
529 // No lea pattern match, use add
530 VisitBinop(this, node, kIA32Add);
534 void InstructionSelector::VisitInt32Sub(Node* node) {
535 IA32OperandGenerator g(this);
536 Int32BinopMatcher m(node);
537 if (m.left().Is(0)) {
538 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node()));
540 VisitBinop(this, node, kIA32Sub);
545 void InstructionSelector::VisitInt32Mul(Node* node) {
546 Int32ScaleMatcher m(node, true);
548 Node* index = node->InputAt(0);
549 Node* base = m.power_of_two_plus_one() ? index : NULL;
550 EmitLea(this, node, index, m.scale(), base, NULL);
553 IA32OperandGenerator g(this);
554 Node* left = node->InputAt(0);
555 Node* right = node->InputAt(1);
556 if (g.CanBeImmediate(right)) {
557 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left),
558 g.UseImmediate(right));
560 if (g.CanBeBetterLeftOperand(right)) {
561 std::swap(left, right);
563 Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
569 void InstructionSelector::VisitInt32MulHigh(Node* node) {
570 VisitMulHigh(this, node, kIA32ImulHigh);
574 void InstructionSelector::VisitUint32MulHigh(Node* node) {
575 VisitMulHigh(this, node, kIA32UmulHigh);
579 void InstructionSelector::VisitInt32Div(Node* node) {
580 VisitDiv(this, node, kIA32Idiv);
584 void InstructionSelector::VisitUint32Div(Node* node) {
585 VisitDiv(this, node, kIA32Udiv);
589 void InstructionSelector::VisitInt32Mod(Node* node) {
590 VisitMod(this, node, kIA32Idiv);
594 void InstructionSelector::VisitUint32Mod(Node* node) {
595 VisitMod(this, node, kIA32Udiv);
599 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
600 IA32OperandGenerator g(this);
601 Emit(kSSECvtss2sd, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
605 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
606 IA32OperandGenerator g(this);
607 Emit(kSSEInt32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
611 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
612 IA32OperandGenerator g(this);
613 Emit(kSSEUint32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
617 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
618 IA32OperandGenerator g(this);
619 Emit(kSSEFloat64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
623 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
624 IA32OperandGenerator g(this);
625 Emit(kSSEFloat64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
629 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
630 IA32OperandGenerator g(this);
631 Emit(kSSECvtsd2ss, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
635 void InstructionSelector::VisitFloat64Add(Node* node) {
636 IA32OperandGenerator g(this);
637 if (IsSupported(AVX)) {
638 Emit(kAVXFloat64Add, g.DefineAsRegister(node),
639 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
641 Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
642 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
647 void InstructionSelector::VisitFloat64Sub(Node* node) {
648 IA32OperandGenerator g(this);
649 if (IsSupported(AVX)) {
650 Emit(kAVXFloat64Sub, g.DefineAsRegister(node),
651 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
653 Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
654 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
659 void InstructionSelector::VisitFloat64Mul(Node* node) {
660 IA32OperandGenerator g(this);
661 if (IsSupported(AVX)) {
662 Emit(kAVXFloat64Mul, g.DefineAsRegister(node),
663 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
665 Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
666 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
671 void InstructionSelector::VisitFloat64Div(Node* node) {
672 IA32OperandGenerator g(this);
673 if (IsSupported(AVX)) {
674 Emit(kAVXFloat64Div, g.DefineAsRegister(node),
675 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
677 Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
678 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
683 void InstructionSelector::VisitFloat64Mod(Node* node) {
684 IA32OperandGenerator g(this);
685 InstructionOperand temps[] = {g.TempRegister(eax)};
686 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node),
687 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1,
692 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
693 IA32OperandGenerator g(this);
694 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
698 void InstructionSelector::VisitFloat64Floor(Node* node) {
699 DCHECK(CpuFeatures::IsSupported(SSE4_1));
700 VisitRRFloat64(this, kSSEFloat64Floor, node);
704 void InstructionSelector::VisitFloat64Ceil(Node* node) {
705 DCHECK(CpuFeatures::IsSupported(SSE4_1));
706 VisitRRFloat64(this, kSSEFloat64Ceil, node);
710 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
711 DCHECK(CpuFeatures::IsSupported(SSE4_1));
712 VisitRRFloat64(this, kSSEFloat64RoundTruncate, node);
716 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
721 void InstructionSelector::VisitCall(Node* node) {
722 IA32OperandGenerator g(this);
723 const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
725 FrameStateDescriptor* frame_state_descriptor = NULL;
727 if (descriptor->NeedsFrameState()) {
728 frame_state_descriptor =
729 GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
732 CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
734 // Compute InstructionOperands for inputs and outputs.
735 InitializeCallBuffer(node, &buffer, true, true);
737 // Push any stack arguments.
738 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
740 // TODO(titzer): handle pushing double parameters.
741 InstructionOperand value =
742 g.CanBeImmediate(*i) ? g.UseImmediate(*i) : IsSupported(ATOM)
745 Emit(kIA32Push, g.NoOutput(), value);
748 // Select the appropriate opcode based on the call type.
749 InstructionCode opcode;
750 switch (descriptor->kind()) {
751 case CallDescriptor::kCallCodeObject: {
752 opcode = kArchCallCodeObject;
755 case CallDescriptor::kCallJSFunction:
756 opcode = kArchCallJSFunction;
762 opcode |= MiscField::encode(descriptor->flags());
764 // Emit the call instruction.
765 InstructionOperand* first_output =
766 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
767 Instruction* call_instr =
768 Emit(opcode, buffer.outputs.size(), first_output,
769 buffer.instruction_args.size(), &buffer.instruction_args.front());
770 call_instr->MarkAsCall();
776 // Shared routine for multiple compare operations.
777 void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
778 InstructionOperand left, InstructionOperand right,
779 FlagsContinuation* cont) {
780 IA32OperandGenerator g(selector);
781 if (cont->IsBranch()) {
782 selector->Emit(cont->Encode(opcode), g.NoOutput(), left, right,
783 g.Label(cont->true_block()),
784 g.Label(cont->false_block()))->MarkAsControl();
786 DCHECK(cont->IsSet());
787 // TODO(titzer): Needs byte register.
788 selector->Emit(cont->Encode(opcode), g.DefineAsRegister(cont->result()),
794 // Shared routine for multiple compare operations.
795 void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
796 Node* left, Node* right, FlagsContinuation* cont,
798 IA32OperandGenerator g(selector);
799 if (commutative && g.CanBeBetterLeftOperand(right)) {
800 std::swap(left, right);
802 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
806 // Shared routine for multiple float64 compare operations (inputs commuted).
807 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
808 FlagsContinuation* cont) {
809 Node* const left = node->InputAt(0);
810 Node* const right = node->InputAt(1);
811 VisitCompare(selector, kSSEFloat64Cmp, right, left, cont, false);
815 // Shared routine for multiple word compare operations.
816 void VisitWordCompare(InstructionSelector* selector, Node* node,
817 InstructionCode opcode, FlagsContinuation* cont) {
818 IA32OperandGenerator g(selector);
819 Node* const left = node->InputAt(0);
820 Node* const right = node->InputAt(1);
822 // Match immediates on left or right side of comparison.
823 if (g.CanBeImmediate(right)) {
824 VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont);
825 } else if (g.CanBeImmediate(left)) {
826 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
827 VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont);
829 VisitCompare(selector, opcode, left, right, cont,
830 node->op()->HasProperty(Operator::kCommutative));
835 void VisitWordCompare(InstructionSelector* selector, Node* node,
836 FlagsContinuation* cont) {
837 VisitWordCompare(selector, node, kIA32Cmp, cont);
841 // Shared routine for word comparison with zero.
842 void VisitWordCompareZero(InstructionSelector* selector, Node* user,
843 Node* value, FlagsContinuation* cont) {
844 // Try to combine the branch with a comparison.
845 while (selector->CanCover(user, value)) {
846 switch (value->opcode()) {
847 case IrOpcode::kWord32Equal: {
848 // Try to combine with comparisons against 0 by simply inverting the
850 Int32BinopMatcher m(value);
851 if (m.right().Is(0)) {
853 value = m.left().node();
857 cont->OverwriteAndNegateIfEqual(kEqual);
858 return VisitWordCompare(selector, value, cont);
860 case IrOpcode::kInt32LessThan:
861 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
862 return VisitWordCompare(selector, value, cont);
863 case IrOpcode::kInt32LessThanOrEqual:
864 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
865 return VisitWordCompare(selector, value, cont);
866 case IrOpcode::kUint32LessThan:
867 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
868 return VisitWordCompare(selector, value, cont);
869 case IrOpcode::kUint32LessThanOrEqual:
870 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
871 return VisitWordCompare(selector, value, cont);
872 case IrOpcode::kFloat64Equal:
873 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
874 return VisitFloat64Compare(selector, value, cont);
875 case IrOpcode::kFloat64LessThan:
876 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
877 return VisitFloat64Compare(selector, value, cont);
878 case IrOpcode::kFloat64LessThanOrEqual:
879 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
880 return VisitFloat64Compare(selector, value, cont);
881 case IrOpcode::kProjection:
882 // Check if this is the overflow output projection of an
883 // <Operation>WithOverflow node.
884 if (ProjectionIndexOf(value->op()) == 1u) {
885 // We cannot combine the <Operation>WithOverflow with this branch
886 // unless the 0th projection (the use of the actual value of the
887 // <Operation> is either NULL, which means there's no use of the
888 // actual value, or was already defined, which means it is scheduled
889 // *AFTER* this branch).
890 Node* const node = value->InputAt(0);
891 Node* const result = NodeProperties::FindProjection(node, 0);
892 if (result == NULL || selector->IsDefined(result)) {
893 switch (node->opcode()) {
894 case IrOpcode::kInt32AddWithOverflow:
895 cont->OverwriteAndNegateIfEqual(kOverflow);
896 return VisitBinop(selector, node, kIA32Add, cont);
897 case IrOpcode::kInt32SubWithOverflow:
898 cont->OverwriteAndNegateIfEqual(kOverflow);
899 return VisitBinop(selector, node, kIA32Sub, cont);
906 case IrOpcode::kInt32Sub:
907 return VisitWordCompare(selector, value, cont);
908 case IrOpcode::kWord32And:
909 return VisitWordCompare(selector, value, kIA32Test, cont);
916 // Continuation could not be combined with a compare, emit compare against 0.
917 IA32OperandGenerator g(selector);
918 VisitCompare(selector, kIA32Cmp, g.Use(value), g.TempImmediate(0), cont);
924 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
925 BasicBlock* fbranch) {
926 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
927 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
931 void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
932 BasicBlock** case_branches,
933 int32_t* case_values, size_t case_count,
934 int32_t min_value, int32_t max_value) {
935 IA32OperandGenerator g(this);
936 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
937 InstructionOperand default_operand = g.Label(default_branch);
939 // Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value}
940 // is 2^31-1, so don't assume that it's non-zero below.
942 1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
944 // Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
946 size_t table_space_cost = 4 + value_range;
947 size_t table_time_cost = 3;
948 size_t lookup_space_cost = 3 + 2 * case_count;
949 size_t lookup_time_cost = case_count;
950 if (case_count > 4 &&
951 table_space_cost + 3 * table_time_cost <=
952 lookup_space_cost + 3 * lookup_time_cost &&
953 min_value > std::numeric_limits<int32_t>::min()) {
954 InstructionOperand index_operand = value_operand;
956 index_operand = g.TempRegister();
957 Emit(kIA32Lea | AddressingModeField::encode(kMode_MRI), index_operand,
958 value_operand, g.TempImmediate(-min_value));
960 size_t input_count = 2 + value_range;
961 auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
962 inputs[0] = index_operand;
963 std::fill(&inputs[1], &inputs[input_count], default_operand);
964 for (size_t index = 0; index < case_count; ++index) {
965 size_t value = case_values[index] - min_value;
966 BasicBlock* branch = case_branches[index];
967 DCHECK_LE(0u, value);
968 DCHECK_LT(value + 2, input_count);
969 inputs[value + 2] = g.Label(branch);
971 Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
976 // Generate a sequence of conditional jumps.
977 size_t input_count = 2 + case_count * 2;
978 auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
979 inputs[0] = value_operand;
980 inputs[1] = default_operand;
981 for (size_t index = 0; index < case_count; ++index) {
982 int32_t value = case_values[index];
983 BasicBlock* branch = case_branches[index];
984 inputs[index * 2 + 2 + 0] = g.TempImmediate(value);
985 inputs[index * 2 + 2 + 1] = g.Label(branch);
987 Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
992 void InstructionSelector::VisitWord32Equal(Node* const node) {
993 FlagsContinuation cont(kEqual, node);
994 Int32BinopMatcher m(node);
995 if (m.right().Is(0)) {
996 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
998 VisitWordCompare(this, node, &cont);
1002 void InstructionSelector::VisitInt32LessThan(Node* node) {
1003 FlagsContinuation cont(kSignedLessThan, node);
1004 VisitWordCompare(this, node, &cont);
1008 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
1009 FlagsContinuation cont(kSignedLessThanOrEqual, node);
1010 VisitWordCompare(this, node, &cont);
1014 void InstructionSelector::VisitUint32LessThan(Node* node) {
1015 FlagsContinuation cont(kUnsignedLessThan, node);
1016 VisitWordCompare(this, node, &cont);
1020 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
1021 FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
1022 VisitWordCompare(this, node, &cont);
1026 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
1027 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1028 FlagsContinuation cont(kOverflow, ovf);
1029 return VisitBinop(this, node, kIA32Add, &cont);
1031 FlagsContinuation cont;
1032 VisitBinop(this, node, kIA32Add, &cont);
1036 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
1037 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1038 FlagsContinuation cont(kOverflow, ovf);
1039 return VisitBinop(this, node, kIA32Sub, &cont);
1041 FlagsContinuation cont;
1042 VisitBinop(this, node, kIA32Sub, &cont);
1046 void InstructionSelector::VisitFloat64Equal(Node* node) {
1047 FlagsContinuation cont(kUnorderedEqual, node);
1048 VisitFloat64Compare(this, node, &cont);
1052 void InstructionSelector::VisitFloat64LessThan(Node* node) {
1053 FlagsContinuation cont(kUnsignedGreaterThan, node);
1054 VisitFloat64Compare(this, node, &cont);
1058 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
1059 FlagsContinuation cont(kUnsignedGreaterThanOrEqual, node);
1060 VisitFloat64Compare(this, node, &cont);
1065 MachineOperatorBuilder::Flags
1066 InstructionSelector::SupportedMachineOperatorFlags() {
1067 if (CpuFeatures::IsSupported(SSE4_1)) {
1068 return MachineOperatorBuilder::kFloat64Floor |
1069 MachineOperatorBuilder::kFloat64Ceil |
1070 MachineOperatorBuilder::kFloat64RoundTruncate |
1071 MachineOperatorBuilder::kWord32ShiftIsSafe;
1073 return MachineOperatorBuilder::Flag::kNoFlags;
1076 } // namespace compiler
1077 } // namespace internal