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"
17 kInt16Imm_4ByteAligned,
24 // Adds PPC-specific methods for generating operands.
25 class PPCOperandGenerator FINAL : public OperandGenerator {
27 explicit PPCOperandGenerator(InstructionSelector* selector)
28 : OperandGenerator(selector) {}
30 InstructionOperand UseOperand(Node* node, ImmediateMode mode) {
31 if (CanBeImmediate(node, mode)) {
32 return UseImmediate(node);
34 return UseRegister(node);
37 bool CanBeImmediate(Node* node, ImmediateMode mode) {
39 if (node->opcode() == IrOpcode::kInt32Constant)
40 value = OpParameter<int32_t>(node);
41 else if (node->opcode() == IrOpcode::kInt64Constant)
42 value = OpParameter<int64_t>(node);
45 return CanBeImmediate(value, mode);
48 bool CanBeImmediate(int64_t value, ImmediateMode mode) {
51 return is_int16(value);
52 case kInt16Imm_Unsigned:
53 return is_uint16(value);
54 case kInt16Imm_Negate:
55 return is_int16(-value);
56 case kInt16Imm_4ByteAligned:
57 return is_int16(value) && !(value & 3);
59 return 0 <= value && value < 32;
61 return 0 <= value && value < 64;
70 static void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
72 PPCOperandGenerator g(selector);
73 selector->Emit(opcode, g.DefineAsRegister(node),
74 g.UseRegister(node->InputAt(0)));
78 static void VisitRRR(InstructionSelector* selector, Node* node,
80 PPCOperandGenerator g(selector);
81 selector->Emit(opcode, g.DefineAsRegister(node),
82 g.UseRegister(node->InputAt(0)),
83 g.UseRegister(node->InputAt(1)));
87 static void VisitRRRFloat64(InstructionSelector* selector, Node* node,
89 PPCOperandGenerator g(selector);
90 selector->Emit(opcode, g.DefineAsRegister(node),
91 g.UseRegister(node->InputAt(0)),
92 g.UseRegister(node->InputAt(1)));
96 static void VisitRRO(InstructionSelector* selector, Node* node,
97 ArchOpcode opcode, ImmediateMode operand_mode) {
98 PPCOperandGenerator g(selector);
99 selector->Emit(opcode, g.DefineAsRegister(node),
100 g.UseRegister(node->InputAt(0)),
101 g.UseOperand(node->InputAt(1), operand_mode));
105 // Shared routine for multiple binary operations.
106 template <typename Matcher>
107 static void VisitBinop(InstructionSelector* selector, Node* node,
108 InstructionCode opcode, ImmediateMode operand_mode,
109 FlagsContinuation* cont) {
110 PPCOperandGenerator g(selector);
112 InstructionOperand inputs[4];
113 size_t input_count = 0;
114 InstructionOperand outputs[2];
115 size_t output_count = 0;
117 inputs[input_count++] = g.UseRegister(m.left().node());
118 inputs[input_count++] = g.UseOperand(m.right().node(), operand_mode);
120 if (cont->IsBranch()) {
121 inputs[input_count++] = g.Label(cont->true_block());
122 inputs[input_count++] = g.Label(cont->false_block());
125 outputs[output_count++] = g.DefineAsRegister(node);
127 outputs[output_count++] = g.DefineAsRegister(cont->result());
130 DCHECK_NE(0u, input_count);
131 DCHECK_NE(0u, output_count);
132 DCHECK_GE(arraysize(inputs), input_count);
133 DCHECK_GE(arraysize(outputs), output_count);
135 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
136 outputs, input_count, inputs);
137 if (cont->IsBranch()) instr->MarkAsControl();
141 // Shared routine for multiple binary operations.
142 template <typename Matcher>
143 static void VisitBinop(InstructionSelector* selector, Node* node,
144 ArchOpcode opcode, ImmediateMode operand_mode) {
145 FlagsContinuation cont;
146 VisitBinop<Matcher>(selector, node, opcode, operand_mode, &cont);
150 void InstructionSelector::VisitLoad(Node* node) {
151 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
152 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
153 PPCOperandGenerator g(this);
154 Node* base = node->InputAt(0);
155 Node* offset = node->InputAt(1);
158 ImmediateMode mode = kInt16Imm;
161 opcode = kPPC_LoadFloat32;
164 opcode = kPPC_LoadFloat64;
166 case kRepBit: // Fall through.
168 opcode = (typ == kTypeInt32) ? kPPC_LoadWordS8 : kPPC_LoadWordU8;
171 opcode = (typ == kTypeInt32) ? kPPC_LoadWordS16 : kPPC_LoadWordU16;
173 #if !V8_TARGET_ARCH_PPC64
174 case kRepTagged: // Fall through.
177 opcode = kPPC_LoadWordS32;
178 #if V8_TARGET_ARCH_PPC64
179 // TODO(mbrandy): this applies to signed loads only (lwa)
180 mode = kInt16Imm_4ByteAligned;
183 #if V8_TARGET_ARCH_PPC64
184 case kRepTagged: // Fall through.
186 opcode = kPPC_LoadWord64;
187 mode = kInt16Imm_4ByteAligned;
194 if (g.CanBeImmediate(offset, mode)) {
195 Emit(opcode | AddressingModeField::encode(kMode_MRI),
196 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(offset));
197 } else if (g.CanBeImmediate(base, mode)) {
198 Emit(opcode | AddressingModeField::encode(kMode_MRI),
199 g.DefineAsRegister(node), g.UseRegister(offset), g.UseImmediate(base));
201 Emit(opcode | AddressingModeField::encode(kMode_MRR),
202 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(offset));
207 void InstructionSelector::VisitStore(Node* node) {
208 PPCOperandGenerator g(this);
209 Node* base = node->InputAt(0);
210 Node* offset = node->InputAt(1);
211 Node* value = node->InputAt(2);
213 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
214 MachineType rep = RepresentationOf(store_rep.machine_type());
215 if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
216 DCHECK(rep == kRepTagged);
217 // TODO(dcarney): refactor RecordWrite function to take temp registers
218 // and pass them here instead of using fixed regs
219 // TODO(dcarney): handle immediate indices.
220 InstructionOperand temps[] = {g.TempRegister(r8), g.TempRegister(r9)};
221 Emit(kPPC_StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, r7),
222 g.UseFixed(offset, r8), g.UseFixed(value, r9), arraysize(temps),
226 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
228 ImmediateMode mode = kInt16Imm;
231 opcode = kPPC_StoreFloat32;
234 opcode = kPPC_StoreFloat64;
236 case kRepBit: // Fall through.
238 opcode = kPPC_StoreWord8;
241 opcode = kPPC_StoreWord16;
243 #if !V8_TARGET_ARCH_PPC64
244 case kRepTagged: // Fall through.
247 opcode = kPPC_StoreWord32;
249 #if V8_TARGET_ARCH_PPC64
250 case kRepTagged: // Fall through.
252 opcode = kPPC_StoreWord64;
253 mode = kInt16Imm_4ByteAligned;
260 if (g.CanBeImmediate(offset, mode)) {
261 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
262 g.UseRegister(base), g.UseImmediate(offset), g.UseRegister(value));
263 } else if (g.CanBeImmediate(base, mode)) {
264 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
265 g.UseRegister(offset), g.UseImmediate(base), g.UseRegister(value));
267 Emit(opcode | AddressingModeField::encode(kMode_MRR), g.NoOutput(),
268 g.UseRegister(base), g.UseRegister(offset), g.UseRegister(value));
273 void InstructionSelector::VisitCheckedLoad(Node* node) {
274 MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
275 MachineType typ = TypeOf(OpParameter<MachineType>(node));
276 PPCOperandGenerator g(this);
277 Node* const base = node->InputAt(0);
278 Node* const offset = node->InputAt(1);
279 Node* const length = node->InputAt(2);
283 opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
286 opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
289 opcode = kCheckedLoadWord32;
292 opcode = kCheckedLoadFloat32;
295 opcode = kCheckedLoadFloat64;
301 AddressingMode addressingMode = kMode_MRR;
302 Emit(opcode | AddressingModeField::encode(addressingMode),
303 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(offset),
304 g.UseOperand(length, kInt16Imm_Unsigned));
308 void InstructionSelector::VisitCheckedStore(Node* node) {
309 MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
310 PPCOperandGenerator g(this);
311 Node* const base = node->InputAt(0);
312 Node* const offset = node->InputAt(1);
313 Node* const length = node->InputAt(2);
314 Node* const value = node->InputAt(3);
318 opcode = kCheckedStoreWord8;
321 opcode = kCheckedStoreWord16;
324 opcode = kCheckedStoreWord32;
327 opcode = kCheckedStoreFloat32;
330 opcode = kCheckedStoreFloat64;
336 AddressingMode addressingMode = kMode_MRR;
337 Emit(opcode | AddressingModeField::encode(addressingMode), g.NoOutput(),
338 g.UseRegister(base), g.UseRegister(offset),
339 g.UseOperand(length, kInt16Imm_Unsigned), g.UseRegister(value));
343 template <typename Matcher>
344 static void VisitLogical(InstructionSelector* selector, Node* node, Matcher* m,
345 ArchOpcode opcode, bool left_can_cover,
346 bool right_can_cover, ImmediateMode imm_mode) {
347 PPCOperandGenerator g(selector);
349 // Map instruction to equivalent operation with inverted right input.
350 ArchOpcode inv_opcode = opcode;
353 inv_opcode = kPPC_AndComplement32;
356 inv_opcode = kPPC_AndComplement64;
359 inv_opcode = kPPC_OrComplement32;
362 inv_opcode = kPPC_OrComplement64;
368 // Select Logical(y, ~x) for Logical(Xor(x, -1), y).
369 if ((m->left().IsWord32Xor() || m->left().IsWord64Xor()) && left_can_cover) {
370 Matcher mleft(m->left().node());
371 if (mleft.right().Is(-1)) {
372 selector->Emit(inv_opcode, g.DefineAsRegister(node),
373 g.UseRegister(m->right().node()),
374 g.UseRegister(mleft.left().node()));
379 // Select Logical(x, ~y) for Logical(x, Xor(y, -1)).
380 if ((m->right().IsWord32Xor() || m->right().IsWord64Xor()) &&
382 Matcher mright(m->right().node());
383 if (mright.right().Is(-1)) {
384 // TODO(all): support shifted operand on right.
385 selector->Emit(inv_opcode, g.DefineAsRegister(node),
386 g.UseRegister(m->left().node()),
387 g.UseRegister(mright.left().node()));
392 VisitBinop<Matcher>(selector, node, opcode, imm_mode);
396 static inline bool IsContiguousMask32(uint32_t value, int* mb, int* me) {
397 int mask_width = base::bits::CountPopulation32(value);
398 int mask_msb = base::bits::CountLeadingZeros32(value);
399 int mask_lsb = base::bits::CountTrailingZeros32(value);
400 if ((mask_width == 0) || (mask_msb + mask_width + mask_lsb != 32))
402 *mb = mask_lsb + mask_width - 1;
408 #if V8_TARGET_ARCH_PPC64
409 static inline bool IsContiguousMask64(uint64_t value, int* mb, int* me) {
410 int mask_width = base::bits::CountPopulation64(value);
411 int mask_msb = base::bits::CountLeadingZeros64(value);
412 int mask_lsb = base::bits::CountTrailingZeros64(value);
413 if ((mask_width == 0) || (mask_msb + mask_width + mask_lsb != 64))
415 *mb = mask_lsb + mask_width - 1;
422 // TODO(mbrandy): Absorb rotate-right into rlwinm?
423 void InstructionSelector::VisitWord32And(Node* node) {
424 PPCOperandGenerator g(this);
425 Int32BinopMatcher m(node);
428 if (m.right().HasValue() && IsContiguousMask32(m.right().Value(), &mb, &me)) {
430 Node* left = m.left().node();
431 if ((m.left().IsWord32Shr() || m.left().IsWord32Shl()) &&
432 CanCover(node, left)) {
433 // Try to absorb left/right shift into rlwinm
434 Int32BinopMatcher mleft(m.left().node());
435 if (mleft.right().IsInRange(0, 31)) {
436 left = mleft.left().node();
437 sh = mleft.right().Value();
438 if (m.left().IsWord32Shr()) {
439 // Adjust the mask such that it doesn't include any rotated bits.
440 if (mb > 31 - sh) mb = 31 - sh;
441 sh = (32 - sh) & 0x1f;
443 // Adjust the mask such that it doesn't include any rotated bits.
444 if (me < sh) me = sh;
449 Emit(kPPC_RotLeftAndMask32, g.DefineAsRegister(node), g.UseRegister(left),
450 g.TempImmediate(sh), g.TempImmediate(mb), g.TempImmediate(me));
454 VisitLogical<Int32BinopMatcher>(
455 this, node, &m, kPPC_And32, CanCover(node, m.left().node()),
456 CanCover(node, m.right().node()), kInt16Imm_Unsigned);
460 #if V8_TARGET_ARCH_PPC64
461 // TODO(mbrandy): Absorb rotate-right into rldic?
462 void InstructionSelector::VisitWord64And(Node* node) {
463 PPCOperandGenerator g(this);
464 Int64BinopMatcher m(node);
467 if (m.right().HasValue() && IsContiguousMask64(m.right().Value(), &mb, &me)) {
469 Node* left = m.left().node();
470 if ((m.left().IsWord64Shr() || m.left().IsWord64Shl()) &&
471 CanCover(node, left)) {
472 // Try to absorb left/right shift into rldic
473 Int64BinopMatcher mleft(m.left().node());
474 if (mleft.right().IsInRange(0, 63)) {
475 left = mleft.left().node();
476 sh = mleft.right().Value();
477 if (m.left().IsWord64Shr()) {
478 // Adjust the mask such that it doesn't include any rotated bits.
479 if (mb > 63 - sh) mb = 63 - sh;
480 sh = (64 - sh) & 0x3f;
482 // Adjust the mask such that it doesn't include any rotated bits.
483 if (me < sh) me = sh;
493 opcode = kPPC_RotLeftAndClearLeft64;
495 } else if (mb == 63) {
497 opcode = kPPC_RotLeftAndClearRight64;
499 } else if (sh && me <= sh && m.left().IsWord64Shl()) {
501 opcode = kPPC_RotLeftAndClear64;
505 Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left),
506 g.TempImmediate(sh), g.TempImmediate(mask));
511 VisitLogical<Int64BinopMatcher>(
512 this, node, &m, kPPC_And64, CanCover(node, m.left().node()),
513 CanCover(node, m.right().node()), kInt16Imm_Unsigned);
518 void InstructionSelector::VisitWord32Or(Node* node) {
519 Int32BinopMatcher m(node);
520 VisitLogical<Int32BinopMatcher>(
521 this, node, &m, kPPC_Or32, CanCover(node, m.left().node()),
522 CanCover(node, m.right().node()), kInt16Imm_Unsigned);
526 #if V8_TARGET_ARCH_PPC64
527 void InstructionSelector::VisitWord64Or(Node* node) {
528 Int64BinopMatcher m(node);
529 VisitLogical<Int64BinopMatcher>(
530 this, node, &m, kPPC_Or64, CanCover(node, m.left().node()),
531 CanCover(node, m.right().node()), kInt16Imm_Unsigned);
536 void InstructionSelector::VisitWord32Xor(Node* node) {
537 PPCOperandGenerator g(this);
538 Int32BinopMatcher m(node);
539 if (m.right().Is(-1)) {
540 Emit(kPPC_Not32, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
542 VisitBinop<Int32BinopMatcher>(this, node, kPPC_Xor32, kInt16Imm_Unsigned);
547 #if V8_TARGET_ARCH_PPC64
548 void InstructionSelector::VisitWord64Xor(Node* node) {
549 PPCOperandGenerator g(this);
550 Int64BinopMatcher m(node);
551 if (m.right().Is(-1)) {
552 Emit(kPPC_Not64, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
554 VisitBinop<Int64BinopMatcher>(this, node, kPPC_Xor64, kInt16Imm_Unsigned);
560 void InstructionSelector::VisitWord32Shl(Node* node) {
561 PPCOperandGenerator g(this);
562 Int32BinopMatcher m(node);
563 if (m.left().IsWord32And() && m.right().IsInRange(0, 31)) {
564 // Try to absorb logical-and into rlwinm
565 Int32BinopMatcher mleft(m.left().node());
566 int sh = m.right().Value();
569 if (mleft.right().HasValue() &&
570 IsContiguousMask32(mleft.right().Value() << sh, &mb, &me)) {
571 // Adjust the mask such that it doesn't include any rotated bits.
572 if (me < sh) me = sh;
574 Emit(kPPC_RotLeftAndMask32, g.DefineAsRegister(node),
575 g.UseRegister(mleft.left().node()), g.TempImmediate(sh),
576 g.TempImmediate(mb), g.TempImmediate(me));
581 VisitRRO(this, node, kPPC_ShiftLeft32, kShift32Imm);
585 #if V8_TARGET_ARCH_PPC64
586 void InstructionSelector::VisitWord64Shl(Node* node) {
587 PPCOperandGenerator g(this);
588 Int64BinopMatcher m(node);
589 // TODO(mbrandy): eliminate left sign extension if right >= 32
590 if (m.left().IsWord64And() && m.right().IsInRange(0, 63)) {
591 // Try to absorb logical-and into rldic
592 Int64BinopMatcher mleft(m.left().node());
593 int sh = m.right().Value();
596 if (mleft.right().HasValue() &&
597 IsContiguousMask64(mleft.right().Value() << sh, &mb, &me)) {
598 // Adjust the mask such that it doesn't include any rotated bits.
599 if (me < sh) me = sh;
606 opcode = kPPC_RotLeftAndClearLeft64;
608 } else if (mb == 63) {
610 opcode = kPPC_RotLeftAndClearRight64;
612 } else if (sh && me <= sh) {
614 opcode = kPPC_RotLeftAndClear64;
618 Emit(opcode, g.DefineAsRegister(node),
619 g.UseRegister(mleft.left().node()), g.TempImmediate(sh),
620 g.TempImmediate(mask));
626 VisitRRO(this, node, kPPC_ShiftLeft64, kShift64Imm);
631 void InstructionSelector::VisitWord32Shr(Node* node) {
632 PPCOperandGenerator g(this);
633 Int32BinopMatcher m(node);
634 if (m.left().IsWord32And() && m.right().IsInRange(0, 31)) {
635 // Try to absorb logical-and into rlwinm
636 Int32BinopMatcher mleft(m.left().node());
637 int sh = m.right().Value();
640 if (mleft.right().HasValue() &&
641 IsContiguousMask32((uint32_t)(mleft.right().Value()) >> sh, &mb, &me)) {
642 // Adjust the mask such that it doesn't include any rotated bits.
643 if (mb > 31 - sh) mb = 31 - sh;
644 sh = (32 - sh) & 0x1f;
646 Emit(kPPC_RotLeftAndMask32, g.DefineAsRegister(node),
647 g.UseRegister(mleft.left().node()), g.TempImmediate(sh),
648 g.TempImmediate(mb), g.TempImmediate(me));
653 VisitRRO(this, node, kPPC_ShiftRight32, kShift32Imm);
657 #if V8_TARGET_ARCH_PPC64
658 void InstructionSelector::VisitWord64Shr(Node* node) {
659 PPCOperandGenerator g(this);
660 Int64BinopMatcher m(node);
661 if (m.left().IsWord64And() && m.right().IsInRange(0, 63)) {
662 // Try to absorb logical-and into rldic
663 Int64BinopMatcher mleft(m.left().node());
664 int sh = m.right().Value();
667 if (mleft.right().HasValue() &&
668 IsContiguousMask64((uint64_t)(mleft.right().Value()) >> sh, &mb, &me)) {
669 // Adjust the mask such that it doesn't include any rotated bits.
670 if (mb > 63 - sh) mb = 63 - sh;
671 sh = (64 - sh) & 0x3f;
678 opcode = kPPC_RotLeftAndClearLeft64;
680 } else if (mb == 63) {
682 opcode = kPPC_RotLeftAndClearRight64;
686 Emit(opcode, g.DefineAsRegister(node),
687 g.UseRegister(mleft.left().node()), g.TempImmediate(sh),
688 g.TempImmediate(mask));
694 VisitRRO(this, node, kPPC_ShiftRight64, kShift64Imm);
699 void InstructionSelector::VisitWord32Sar(Node* node) {
700 PPCOperandGenerator g(this);
701 Int32BinopMatcher m(node);
702 // Replace with sign extension for (x << K) >> K where K is 16 or 24.
703 if (CanCover(node, m.left().node()) && m.left().IsWord32Shl()) {
704 Int32BinopMatcher mleft(m.left().node());
705 if (mleft.right().Is(16) && m.right().Is(16)) {
706 Emit(kPPC_ExtendSignWord16, g.DefineAsRegister(node),
707 g.UseRegister(mleft.left().node()));
709 } else if (mleft.right().Is(24) && m.right().Is(24)) {
710 Emit(kPPC_ExtendSignWord8, g.DefineAsRegister(node),
711 g.UseRegister(mleft.left().node()));
715 VisitRRO(this, node, kPPC_ShiftRightAlg32, kShift32Imm);
719 #if V8_TARGET_ARCH_PPC64
720 void InstructionSelector::VisitWord64Sar(Node* node) {
721 VisitRRO(this, node, kPPC_ShiftRightAlg64, kShift64Imm);
726 // TODO(mbrandy): Absorb logical-and into rlwinm?
727 void InstructionSelector::VisitWord32Ror(Node* node) {
728 VisitRRO(this, node, kPPC_RotRight32, kShift32Imm);
732 #if V8_TARGET_ARCH_PPC64
733 // TODO(mbrandy): Absorb logical-and into rldic?
734 void InstructionSelector::VisitWord64Ror(Node* node) {
735 VisitRRO(this, node, kPPC_RotRight64, kShift64Imm);
740 void InstructionSelector::VisitInt32Add(Node* node) {
741 VisitBinop<Int32BinopMatcher>(this, node, kPPC_Add32, kInt16Imm);
745 #if V8_TARGET_ARCH_PPC64
746 void InstructionSelector::VisitInt64Add(Node* node) {
747 VisitBinop<Int64BinopMatcher>(this, node, kPPC_Add64, kInt16Imm);
752 void InstructionSelector::VisitInt32Sub(Node* node) {
753 PPCOperandGenerator g(this);
754 Int32BinopMatcher m(node);
755 if (m.left().Is(0)) {
756 Emit(kPPC_Neg32, g.DefineAsRegister(node), g.UseRegister(m.right().node()));
758 VisitBinop<Int32BinopMatcher>(this, node, kPPC_Sub32, kInt16Imm_Negate);
763 #if V8_TARGET_ARCH_PPC64
764 void InstructionSelector::VisitInt64Sub(Node* node) {
765 PPCOperandGenerator g(this);
766 Int64BinopMatcher m(node);
767 if (m.left().Is(0)) {
768 Emit(kPPC_Neg64, g.DefineAsRegister(node), g.UseRegister(m.right().node()));
770 VisitBinop<Int64BinopMatcher>(this, node, kPPC_Sub64, kInt16Imm_Negate);
776 void InstructionSelector::VisitInt32Mul(Node* node) {
777 VisitRRR(this, node, kPPC_Mul32);
781 #if V8_TARGET_ARCH_PPC64
782 void InstructionSelector::VisitInt64Mul(Node* node) {
783 VisitRRR(this, node, kPPC_Mul64);
788 void InstructionSelector::VisitInt32MulHigh(Node* node) {
789 PPCOperandGenerator g(this);
790 Emit(kPPC_MulHigh32, g.DefineAsRegister(node),
791 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
795 void InstructionSelector::VisitUint32MulHigh(Node* node) {
796 PPCOperandGenerator g(this);
797 Emit(kPPC_MulHighU32, g.DefineAsRegister(node),
798 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
802 void InstructionSelector::VisitInt32Div(Node* node) {
803 VisitRRR(this, node, kPPC_Div32);
807 #if V8_TARGET_ARCH_PPC64
808 void InstructionSelector::VisitInt64Div(Node* node) {
809 VisitRRR(this, node, kPPC_Div64);
814 void InstructionSelector::VisitUint32Div(Node* node) {
815 VisitRRR(this, node, kPPC_DivU32);
819 #if V8_TARGET_ARCH_PPC64
820 void InstructionSelector::VisitUint64Div(Node* node) {
821 VisitRRR(this, node, kPPC_DivU64);
826 void InstructionSelector::VisitInt32Mod(Node* node) {
827 VisitRRR(this, node, kPPC_Mod32);
831 #if V8_TARGET_ARCH_PPC64
832 void InstructionSelector::VisitInt64Mod(Node* node) {
833 VisitRRR(this, node, kPPC_Mod64);
838 void InstructionSelector::VisitUint32Mod(Node* node) {
839 VisitRRR(this, node, kPPC_ModU32);
843 #if V8_TARGET_ARCH_PPC64
844 void InstructionSelector::VisitUint64Mod(Node* node) {
845 VisitRRR(this, node, kPPC_ModU64);
850 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
851 PPCOperandGenerator g(this);
852 Emit(kPPC_Float32ToFloat64, g.DefineAsRegister(node),
853 g.UseRegister(node->InputAt(0)));
857 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
858 PPCOperandGenerator g(this);
859 Emit(kPPC_Int32ToFloat64, g.DefineAsRegister(node),
860 g.UseRegister(node->InputAt(0)));
864 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
865 PPCOperandGenerator g(this);
866 Emit(kPPC_Uint32ToFloat64, g.DefineAsRegister(node),
867 g.UseRegister(node->InputAt(0)));
871 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
872 PPCOperandGenerator g(this);
873 Emit(kPPC_Float64ToInt32, g.DefineAsRegister(node),
874 g.UseRegister(node->InputAt(0)));
878 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
879 PPCOperandGenerator g(this);
880 Emit(kPPC_Float64ToUint32, g.DefineAsRegister(node),
881 g.UseRegister(node->InputAt(0)));
885 #if V8_TARGET_ARCH_PPC64
886 void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
887 // TODO(mbrandy): inspect input to see if nop is appropriate.
888 PPCOperandGenerator g(this);
889 Emit(kPPC_ExtendSignWord32, g.DefineAsRegister(node),
890 g.UseRegister(node->InputAt(0)));
894 void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
895 // TODO(mbrandy): inspect input to see if nop is appropriate.
896 PPCOperandGenerator g(this);
897 Emit(kPPC_Uint32ToUint64, g.DefineAsRegister(node),
898 g.UseRegister(node->InputAt(0)));
903 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
904 PPCOperandGenerator g(this);
905 Emit(kPPC_Float64ToFloat32, g.DefineAsRegister(node),
906 g.UseRegister(node->InputAt(0)));
910 #if V8_TARGET_ARCH_PPC64
911 void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
912 PPCOperandGenerator g(this);
913 // TODO(mbrandy): inspect input to see if nop is appropriate.
914 Emit(kPPC_Int64ToInt32, g.DefineAsRegister(node),
915 g.UseRegister(node->InputAt(0)));
920 void InstructionSelector::VisitFloat64Add(Node* node) {
921 // TODO(mbrandy): detect multiply-add
922 VisitRRRFloat64(this, node, kPPC_AddFloat64);
926 void InstructionSelector::VisitFloat64Sub(Node* node) {
927 // TODO(mbrandy): detect multiply-subtract
928 VisitRRRFloat64(this, node, kPPC_SubFloat64);
932 void InstructionSelector::VisitFloat64Mul(Node* node) {
933 // TODO(mbrandy): detect negate
934 VisitRRRFloat64(this, node, kPPC_MulFloat64);
938 void InstructionSelector::VisitFloat64Div(Node* node) {
939 VisitRRRFloat64(this, node, kPPC_DivFloat64);
943 void InstructionSelector::VisitFloat64Mod(Node* node) {
944 PPCOperandGenerator g(this);
945 Emit(kPPC_ModFloat64, g.DefineAsFixed(node, d1),
946 g.UseFixed(node->InputAt(0), d1),
947 g.UseFixed(node->InputAt(1), d2))->MarkAsCall();
951 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
952 VisitRRFloat64(this, kPPC_SqrtFloat64, node);
956 void InstructionSelector::VisitFloat64Floor(Node* node) {
957 VisitRRFloat64(this, kPPC_FloorFloat64, node);
961 void InstructionSelector::VisitFloat64Ceil(Node* node) {
962 VisitRRFloat64(this, kPPC_CeilFloat64, node);
966 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
967 VisitRRFloat64(this, kPPC_TruncateFloat64, node);
971 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
972 VisitRRFloat64(this, kPPC_RoundFloat64, node);
976 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
977 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
978 FlagsContinuation cont(kOverflow, ovf);
979 return VisitBinop<Int32BinopMatcher>(this, node, kPPC_AddWithOverflow32,
982 FlagsContinuation cont;
983 VisitBinop<Int32BinopMatcher>(this, node, kPPC_AddWithOverflow32, kInt16Imm,
988 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
989 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
990 FlagsContinuation cont(kOverflow, ovf);
991 return VisitBinop<Int32BinopMatcher>(this, node, kPPC_SubWithOverflow32,
992 kInt16Imm_Negate, &cont);
994 FlagsContinuation cont;
995 VisitBinop<Int32BinopMatcher>(this, node, kPPC_SubWithOverflow32,
996 kInt16Imm_Negate, &cont);
1000 static bool CompareLogical(FlagsContinuation* cont) {
1001 switch (cont->condition()) {
1002 case kUnsignedLessThan:
1003 case kUnsignedGreaterThanOrEqual:
1004 case kUnsignedLessThanOrEqual:
1005 case kUnsignedGreaterThan:
1015 // Shared routine for multiple compare operations.
1016 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1017 InstructionOperand left, InstructionOperand right,
1018 FlagsContinuation* cont) {
1019 PPCOperandGenerator g(selector);
1020 opcode = cont->Encode(opcode);
1021 if (cont->IsBranch()) {
1022 selector->Emit(opcode, g.NoOutput(), left, right,
1023 g.Label(cont->true_block()),
1024 g.Label(cont->false_block()))->MarkAsControl();
1026 DCHECK(cont->IsSet());
1027 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
1032 // Shared routine for multiple word compare operations.
1033 static void VisitWordCompare(InstructionSelector* selector, Node* node,
1034 InstructionCode opcode, FlagsContinuation* cont,
1035 bool commutative, ImmediateMode immediate_mode) {
1036 PPCOperandGenerator g(selector);
1037 Node* left = node->InputAt(0);
1038 Node* right = node->InputAt(1);
1040 // Match immediates on left or right side of comparison.
1041 if (g.CanBeImmediate(right, immediate_mode)) {
1042 VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
1044 } else if (g.CanBeImmediate(left, immediate_mode)) {
1045 if (!commutative) cont->Commute();
1046 VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
1049 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
1055 static void VisitWord32Compare(InstructionSelector* selector, Node* node,
1056 FlagsContinuation* cont) {
1057 ImmediateMode mode = (CompareLogical(cont) ? kInt16Imm_Unsigned : kInt16Imm);
1058 VisitWordCompare(selector, node, kPPC_Cmp32, cont, false, mode);
1062 #if V8_TARGET_ARCH_PPC64
1063 static void VisitWord64Compare(InstructionSelector* selector, Node* node,
1064 FlagsContinuation* cont) {
1065 ImmediateMode mode = (CompareLogical(cont) ? kInt16Imm_Unsigned : kInt16Imm);
1066 VisitWordCompare(selector, node, kPPC_Cmp64, cont, false, mode);
1071 // Shared routine for multiple float compare operations.
1072 static void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1073 FlagsContinuation* cont) {
1074 PPCOperandGenerator g(selector);
1075 Node* left = node->InputAt(0);
1076 Node* right = node->InputAt(1);
1077 VisitCompare(selector, kPPC_CmpFloat64, g.UseRegister(left),
1078 g.UseRegister(right), cont);
1082 // Shared routine for word comparisons against zero.
1083 static void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1084 Node* value, InstructionCode opcode,
1085 FlagsContinuation* cont) {
1086 while (selector->CanCover(user, value)) {
1087 switch (value->opcode()) {
1088 case IrOpcode::kWord32Equal: {
1089 // Combine with comparisons against 0 by simply inverting the
1091 Int32BinopMatcher m(value);
1092 if (m.right().Is(0)) {
1094 value = m.left().node();
1098 cont->OverwriteAndNegateIfEqual(kEqual);
1099 return VisitWord32Compare(selector, value, cont);
1101 case IrOpcode::kInt32LessThan:
1102 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1103 return VisitWord32Compare(selector, value, cont);
1104 case IrOpcode::kInt32LessThanOrEqual:
1105 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1106 return VisitWord32Compare(selector, value, cont);
1107 case IrOpcode::kUint32LessThan:
1108 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1109 return VisitWord32Compare(selector, value, cont);
1110 case IrOpcode::kUint32LessThanOrEqual:
1111 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1112 return VisitWord32Compare(selector, value, cont);
1113 #if V8_TARGET_ARCH_PPC64
1114 case IrOpcode::kWord64Equal: {
1115 // Combine with comparisons against 0 by simply inverting the
1117 Int64BinopMatcher m(value);
1118 if (m.right().Is(0)) {
1120 value = m.left().node();
1124 cont->OverwriteAndNegateIfEqual(kEqual);
1125 return VisitWord64Compare(selector, value, cont);
1127 case IrOpcode::kInt64LessThan:
1128 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1129 return VisitWord64Compare(selector, value, cont);
1130 case IrOpcode::kInt64LessThanOrEqual:
1131 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1132 return VisitWord64Compare(selector, value, cont);
1133 case IrOpcode::kUint64LessThan:
1134 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1135 return VisitWord64Compare(selector, value, cont);
1137 case IrOpcode::kFloat64Equal:
1138 cont->OverwriteAndNegateIfEqual(kEqual);
1139 return VisitFloat64Compare(selector, value, cont);
1140 case IrOpcode::kFloat64LessThan:
1141 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1142 return VisitFloat64Compare(selector, value, cont);
1143 case IrOpcode::kFloat64LessThanOrEqual:
1144 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1145 return VisitFloat64Compare(selector, value, cont);
1146 case IrOpcode::kProjection:
1147 // Check if this is the overflow output projection of an
1148 // <Operation>WithOverflow node.
1149 if (ProjectionIndexOf(value->op()) == 1u) {
1150 // We cannot combine the <Operation>WithOverflow with this branch
1151 // unless the 0th projection (the use of the actual value of the
1152 // <Operation> is either NULL, which means there's no use of the
1153 // actual value, or was already defined, which means it is scheduled
1154 // *AFTER* this branch).
1155 Node* const node = value->InputAt(0);
1156 Node* const result = NodeProperties::FindProjection(node, 0);
1157 if (result == NULL || selector->IsDefined(result)) {
1158 switch (node->opcode()) {
1159 case IrOpcode::kInt32AddWithOverflow:
1160 cont->OverwriteAndNegateIfEqual(kOverflow);
1161 return VisitBinop<Int32BinopMatcher>(
1162 selector, node, kPPC_AddWithOverflow32, kInt16Imm, cont);
1163 case IrOpcode::kInt32SubWithOverflow:
1164 cont->OverwriteAndNegateIfEqual(kOverflow);
1165 return VisitBinop<Int32BinopMatcher>(selector, node,
1166 kPPC_SubWithOverflow32,
1167 kInt16Imm_Negate, cont);
1174 case IrOpcode::kInt32Sub:
1175 return VisitWord32Compare(selector, value, cont);
1176 case IrOpcode::kWord32And:
1177 // TODO(mbandy): opportunity for rlwinm?
1178 return VisitWordCompare(selector, value, kPPC_Tst32, cont, true,
1179 kInt16Imm_Unsigned);
1180 // TODO(mbrandy): Handle?
1181 // case IrOpcode::kInt32Add:
1182 // case IrOpcode::kWord32Or:
1183 // case IrOpcode::kWord32Xor:
1184 // case IrOpcode::kWord32Sar:
1185 // case IrOpcode::kWord32Shl:
1186 // case IrOpcode::kWord32Shr:
1187 // case IrOpcode::kWord32Ror:
1188 #if V8_TARGET_ARCH_PPC64
1189 case IrOpcode::kInt64Sub:
1190 return VisitWord64Compare(selector, value, cont);
1191 case IrOpcode::kWord64And:
1192 // TODO(mbandy): opportunity for rldic?
1193 return VisitWordCompare(selector, value, kPPC_Tst64, cont, true,
1194 kInt16Imm_Unsigned);
1195 // TODO(mbrandy): Handle?
1196 // case IrOpcode::kInt64Add:
1197 // case IrOpcode::kWord64Or:
1198 // case IrOpcode::kWord64Xor:
1199 // case IrOpcode::kWord64Sar:
1200 // case IrOpcode::kWord64Shl:
1201 // case IrOpcode::kWord64Shr:
1202 // case IrOpcode::kWord64Ror:
1210 // Branch could not be combined with a compare, emit compare against 0.
1211 PPCOperandGenerator g(selector);
1212 VisitCompare(selector, opcode, g.UseRegister(value), g.TempImmediate(0),
1217 static void VisitWord32CompareZero(InstructionSelector* selector, Node* user,
1218 Node* value, FlagsContinuation* cont) {
1219 VisitWordCompareZero(selector, user, value, kPPC_Cmp32, cont);
1223 #if V8_TARGET_ARCH_PPC64
1224 static void VisitWord64CompareZero(InstructionSelector* selector, Node* user,
1225 Node* value, FlagsContinuation* cont) {
1226 VisitWordCompareZero(selector, user, value, kPPC_Cmp64, cont);
1231 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1232 BasicBlock* fbranch) {
1233 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1234 VisitWord32CompareZero(this, branch, branch->InputAt(0), &cont);
1238 void InstructionSelector::VisitWord32Equal(Node* const node) {
1239 FlagsContinuation cont(kEqual, node);
1240 Int32BinopMatcher m(node);
1241 if (m.right().Is(0)) {
1242 return VisitWord32CompareZero(this, m.node(), m.left().node(), &cont);
1244 VisitWord32Compare(this, node, &cont);
1248 void InstructionSelector::VisitInt32LessThan(Node* node) {
1249 FlagsContinuation cont(kSignedLessThan, node);
1250 VisitWord32Compare(this, node, &cont);
1254 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
1255 FlagsContinuation cont(kSignedLessThanOrEqual, node);
1256 VisitWord32Compare(this, node, &cont);
1260 void InstructionSelector::VisitUint32LessThan(Node* node) {
1261 FlagsContinuation cont(kUnsignedLessThan, node);
1262 VisitWord32Compare(this, node, &cont);
1266 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
1267 FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
1268 VisitWord32Compare(this, node, &cont);
1272 #if V8_TARGET_ARCH_PPC64
1273 void InstructionSelector::VisitWord64Equal(Node* const node) {
1274 FlagsContinuation cont(kEqual, node);
1275 Int64BinopMatcher m(node);
1276 if (m.right().Is(0)) {
1277 return VisitWord64CompareZero(this, m.node(), m.left().node(), &cont);
1279 VisitWord64Compare(this, node, &cont);
1283 void InstructionSelector::VisitInt64LessThan(Node* node) {
1284 FlagsContinuation cont(kSignedLessThan, node);
1285 VisitWord64Compare(this, node, &cont);
1289 void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
1290 FlagsContinuation cont(kSignedLessThanOrEqual, node);
1291 VisitWord64Compare(this, node, &cont);
1295 void InstructionSelector::VisitUint64LessThan(Node* node) {
1296 FlagsContinuation cont(kUnsignedLessThan, node);
1297 VisitWord64Compare(this, node, &cont);
1302 void InstructionSelector::VisitFloat64Equal(Node* node) {
1303 FlagsContinuation cont(kEqual, node);
1304 VisitFloat64Compare(this, node, &cont);
1308 void InstructionSelector::VisitFloat64LessThan(Node* node) {
1309 FlagsContinuation cont(kUnsignedLessThan, node);
1310 VisitFloat64Compare(this, node, &cont);
1314 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
1315 FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
1316 VisitFloat64Compare(this, node, &cont);
1320 void InstructionSelector::VisitCall(Node* node) {
1321 PPCOperandGenerator g(this);
1322 const CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node);
1324 FrameStateDescriptor* frame_state_descriptor = NULL;
1325 if (descriptor->NeedsFrameState()) {
1326 frame_state_descriptor =
1327 GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
1330 CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
1332 // Compute InstructionOperands for inputs and outputs.
1333 // TODO(turbofan): on PPC it's probably better to use the code object in a
1334 // register if there are multiple uses of it. Improve constant pool and the
1335 // heuristics in the register allocator for where to emit constants.
1336 InitializeCallBuffer(node, &buffer, true, false);
1338 // Push any stack arguments.
1339 // TODO(mbrandy): reverse order and use push only for first
1340 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
1342 Emit(kPPC_Push, g.NoOutput(), g.UseRegister(*i));
1345 // Select the appropriate opcode based on the call type.
1346 InstructionCode opcode;
1347 switch (descriptor->kind()) {
1348 case CallDescriptor::kCallCodeObject: {
1349 opcode = kArchCallCodeObject;
1352 case CallDescriptor::kCallJSFunction:
1353 opcode = kArchCallJSFunction;
1359 opcode |= MiscField::encode(descriptor->flags());
1361 // Emit the call instruction.
1362 InstructionOperand* first_output =
1363 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
1364 Instruction* call_instr =
1365 Emit(opcode, buffer.outputs.size(), first_output,
1366 buffer.instruction_args.size(), &buffer.instruction_args.front());
1367 call_instr->MarkAsCall();
1372 MachineOperatorBuilder::Flags
1373 InstructionSelector::SupportedMachineOperatorFlags() {
1374 return MachineOperatorBuilder::kFloat64Floor |
1375 MachineOperatorBuilder::kFloat64Ceil |
1376 MachineOperatorBuilder::kFloat64RoundTruncate |
1377 MachineOperatorBuilder::kFloat64RoundTiesAway;
1378 // We omit kWord32ShiftIsSafe as s[rl]w use 0x3f as a mask rather than 0x1f.
1381 } // namespace compiler
1382 } // namespace internal