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#include "src/ppc/frames-ppc.h"
10
11namespace v8 {
12namespace internal {
13namespace compiler {
14
15enum ImmediateMode {
16  kInt16Imm,
17  kInt16Imm_Unsigned,
18  kInt16Imm_Negate,
19  kInt16Imm_4ByteAligned,
20  kShift32Imm,
21  kShift64Imm,
22  kNoImmediate
23};
24
25
26// Adds PPC-specific methods for generating operands.
27class PPCOperandGenerator final : public OperandGenerator {
28 public:
29  explicit PPCOperandGenerator(InstructionSelector* selector)
30      : OperandGenerator(selector) {}
31
32  InstructionOperand UseOperand(Node* node, ImmediateMode mode) {
33    if (CanBeImmediate(node, mode)) {
34      return UseImmediate(node);
35    }
36    return UseRegister(node);
37  }
38
39  bool CanBeImmediate(Node* node, ImmediateMode mode) {
40    int64_t value;
41    if (node->opcode() == IrOpcode::kInt32Constant)
42      value = OpParameter<int32_t>(node);
43    else if (node->opcode() == IrOpcode::kInt64Constant)
44      value = OpParameter<int64_t>(node);
45    else
46      return false;
47    return CanBeImmediate(value, mode);
48  }
49
50  bool CanBeImmediate(int64_t value, ImmediateMode mode) {
51    switch (mode) {
52      case kInt16Imm:
53        return is_int16(value);
54      case kInt16Imm_Unsigned:
55        return is_uint16(value);
56      case kInt16Imm_Negate:
57        return is_int16(-value);
58      case kInt16Imm_4ByteAligned:
59        return is_int16(value) && !(value & 3);
60      case kShift32Imm:
61        return 0 <= value && value < 32;
62      case kShift64Imm:
63        return 0 <= value && value < 64;
64      case kNoImmediate:
65        return false;
66    }
67    return false;
68  }
69};
70
71
72namespace {
73
74void VisitRR(InstructionSelector* selector, InstructionCode opcode,
75             Node* node) {
76  PPCOperandGenerator g(selector);
77  selector->Emit(opcode, g.DefineAsRegister(node),
78                 g.UseRegister(node->InputAt(0)));
79}
80
81void VisitRRR(InstructionSelector* selector, InstructionCode opcode,
82              Node* node) {
83  PPCOperandGenerator g(selector);
84  selector->Emit(opcode, g.DefineAsRegister(node),
85                 g.UseRegister(node->InputAt(0)),
86                 g.UseRegister(node->InputAt(1)));
87}
88
89void VisitRRO(InstructionSelector* selector, InstructionCode opcode, Node* node,
90              ImmediateMode operand_mode) {
91  PPCOperandGenerator g(selector);
92  selector->Emit(opcode, g.DefineAsRegister(node),
93                 g.UseRegister(node->InputAt(0)),
94                 g.UseOperand(node->InputAt(1), operand_mode));
95}
96
97
98#if V8_TARGET_ARCH_PPC64
99void VisitTryTruncateDouble(InstructionSelector* selector,
100                            InstructionCode opcode, Node* node) {
101  PPCOperandGenerator g(selector);
102  InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
103  InstructionOperand outputs[2];
104  size_t output_count = 0;
105  outputs[output_count++] = g.DefineAsRegister(node);
106
107  Node* success_output = NodeProperties::FindProjection(node, 1);
108  if (success_output) {
109    outputs[output_count++] = g.DefineAsRegister(success_output);
110  }
111
112  selector->Emit(opcode, output_count, outputs, 1, inputs);
113}
114#endif
115
116
117// Shared routine for multiple binary operations.
118template <typename Matcher>
119void VisitBinop(InstructionSelector* selector, Node* node,
120                InstructionCode opcode, ImmediateMode operand_mode,
121                FlagsContinuation* cont) {
122  PPCOperandGenerator g(selector);
123  Matcher m(node);
124  InstructionOperand inputs[4];
125  size_t input_count = 0;
126  InstructionOperand outputs[2];
127  size_t output_count = 0;
128
129  inputs[input_count++] = g.UseRegister(m.left().node());
130  inputs[input_count++] = g.UseOperand(m.right().node(), operand_mode);
131
132  if (cont->IsBranch()) {
133    inputs[input_count++] = g.Label(cont->true_block());
134    inputs[input_count++] = g.Label(cont->false_block());
135  }
136
137  if (cont->IsDeoptimize()) {
138    // If we can deoptimize as a result of the binop, we need to make sure that
139    // the deopt inputs are not overwritten by the binop result. One way
140    // to achieve that is to declare the output register as same-as-first.
141    outputs[output_count++] = g.DefineSameAsFirst(node);
142  } else {
143    outputs[output_count++] = g.DefineAsRegister(node);
144  }
145  if (cont->IsSet()) {
146    outputs[output_count++] = g.DefineAsRegister(cont->result());
147  }
148
149  DCHECK_NE(0u, input_count);
150  DCHECK_NE(0u, output_count);
151  DCHECK_GE(arraysize(inputs), input_count);
152  DCHECK_GE(arraysize(outputs), output_count);
153
154  opcode = cont->Encode(opcode);
155  if (cont->IsDeoptimize()) {
156    selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
157                             cont->reason(), cont->frame_state());
158  } else {
159    selector->Emit(opcode, output_count, outputs, input_count, inputs);
160  }
161}
162
163
164// Shared routine for multiple binary operations.
165template <typename Matcher>
166void VisitBinop(InstructionSelector* selector, Node* node,
167                InstructionCode opcode, ImmediateMode operand_mode) {
168  FlagsContinuation cont;
169  VisitBinop<Matcher>(selector, node, opcode, operand_mode, &cont);
170}
171
172}  // namespace
173
174
175void InstructionSelector::VisitLoad(Node* node) {
176  LoadRepresentation load_rep = LoadRepresentationOf(node->op());
177  PPCOperandGenerator g(this);
178  Node* base = node->InputAt(0);
179  Node* offset = node->InputAt(1);
180  ArchOpcode opcode = kArchNop;
181  ImmediateMode mode = kInt16Imm;
182  switch (load_rep.representation()) {
183    case MachineRepresentation::kFloat32:
184      opcode = kPPC_LoadFloat32;
185      break;
186    case MachineRepresentation::kFloat64:
187      opcode = kPPC_LoadDouble;
188      break;
189    case MachineRepresentation::kBit:  // Fall through.
190    case MachineRepresentation::kWord8:
191      opcode = load_rep.IsSigned() ? kPPC_LoadWordS8 : kPPC_LoadWordU8;
192      break;
193    case MachineRepresentation::kWord16:
194      opcode = load_rep.IsSigned() ? kPPC_LoadWordS16 : kPPC_LoadWordU16;
195      break;
196#if !V8_TARGET_ARCH_PPC64
197    case MachineRepresentation::kTaggedSigned:   // Fall through.
198    case MachineRepresentation::kTaggedPointer:  // Fall through.
199    case MachineRepresentation::kTagged:  // Fall through.
200#endif
201    case MachineRepresentation::kWord32:
202      opcode = kPPC_LoadWordU32;
203      break;
204#if V8_TARGET_ARCH_PPC64
205    case MachineRepresentation::kTaggedSigned:   // Fall through.
206    case MachineRepresentation::kTaggedPointer:  // Fall through.
207    case MachineRepresentation::kTagged:  // Fall through.
208    case MachineRepresentation::kWord64:
209      opcode = kPPC_LoadWord64;
210      mode = kInt16Imm_4ByteAligned;
211      break;
212#else
213    case MachineRepresentation::kWord64:  // Fall through.
214#endif
215    case MachineRepresentation::kSimd128:  // Fall through.
216    case MachineRepresentation::kNone:
217      UNREACHABLE();
218      return;
219  }
220  if (g.CanBeImmediate(offset, mode)) {
221    Emit(opcode | AddressingModeField::encode(kMode_MRI),
222         g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(offset));
223  } else if (g.CanBeImmediate(base, mode)) {
224    Emit(opcode | AddressingModeField::encode(kMode_MRI),
225         g.DefineAsRegister(node), g.UseRegister(offset), g.UseImmediate(base));
226  } else {
227    Emit(opcode | AddressingModeField::encode(kMode_MRR),
228         g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(offset));
229  }
230}
231
232void InstructionSelector::VisitProtectedLoad(Node* node) {
233  // TODO(eholk)
234  UNIMPLEMENTED();
235}
236
237void InstructionSelector::VisitStore(Node* node) {
238  PPCOperandGenerator g(this);
239  Node* base = node->InputAt(0);
240  Node* offset = node->InputAt(1);
241  Node* value = node->InputAt(2);
242
243  StoreRepresentation store_rep = StoreRepresentationOf(node->op());
244  WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
245  MachineRepresentation rep = store_rep.representation();
246
247  if (write_barrier_kind != kNoWriteBarrier) {
248    DCHECK(CanBeTaggedPointer(rep));
249    AddressingMode addressing_mode;
250    InstructionOperand inputs[3];
251    size_t input_count = 0;
252    inputs[input_count++] = g.UseUniqueRegister(base);
253    // OutOfLineRecordWrite uses the offset in an 'add' instruction as well as
254    // for the store itself, so we must check compatibility with both.
255    if (g.CanBeImmediate(offset, kInt16Imm)
256#if V8_TARGET_ARCH_PPC64
257        && g.CanBeImmediate(offset, kInt16Imm_4ByteAligned)
258#endif
259            ) {
260      inputs[input_count++] = g.UseImmediate(offset);
261      addressing_mode = kMode_MRI;
262    } else {
263      inputs[input_count++] = g.UseUniqueRegister(offset);
264      addressing_mode = kMode_MRR;
265    }
266    inputs[input_count++] = g.UseUniqueRegister(value);
267    RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
268    switch (write_barrier_kind) {
269      case kNoWriteBarrier:
270        UNREACHABLE();
271        break;
272      case kMapWriteBarrier:
273        record_write_mode = RecordWriteMode::kValueIsMap;
274        break;
275      case kPointerWriteBarrier:
276        record_write_mode = RecordWriteMode::kValueIsPointer;
277        break;
278      case kFullWriteBarrier:
279        record_write_mode = RecordWriteMode::kValueIsAny;
280        break;
281    }
282    InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
283    size_t const temp_count = arraysize(temps);
284    InstructionCode code = kArchStoreWithWriteBarrier;
285    code |= AddressingModeField::encode(addressing_mode);
286    code |= MiscField::encode(static_cast<int>(record_write_mode));
287    Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
288  } else {
289    ArchOpcode opcode = kArchNop;
290    ImmediateMode mode = kInt16Imm;
291    switch (rep) {
292      case MachineRepresentation::kFloat32:
293        opcode = kPPC_StoreFloat32;
294        break;
295      case MachineRepresentation::kFloat64:
296        opcode = kPPC_StoreDouble;
297        break;
298      case MachineRepresentation::kBit:  // Fall through.
299      case MachineRepresentation::kWord8:
300        opcode = kPPC_StoreWord8;
301        break;
302      case MachineRepresentation::kWord16:
303        opcode = kPPC_StoreWord16;
304        break;
305#if !V8_TARGET_ARCH_PPC64
306      case MachineRepresentation::kTaggedSigned:   // Fall through.
307      case MachineRepresentation::kTaggedPointer:  // Fall through.
308      case MachineRepresentation::kTagged:  // Fall through.
309#endif
310      case MachineRepresentation::kWord32:
311        opcode = kPPC_StoreWord32;
312        break;
313#if V8_TARGET_ARCH_PPC64
314      case MachineRepresentation::kTaggedSigned:   // Fall through.
315      case MachineRepresentation::kTaggedPointer:  // Fall through.
316      case MachineRepresentation::kTagged:  // Fall through.
317      case MachineRepresentation::kWord64:
318        opcode = kPPC_StoreWord64;
319        mode = kInt16Imm_4ByteAligned;
320        break;
321#else
322      case MachineRepresentation::kWord64:  // Fall through.
323#endif
324      case MachineRepresentation::kSimd128:  // Fall through.
325      case MachineRepresentation::kNone:
326        UNREACHABLE();
327        return;
328    }
329    if (g.CanBeImmediate(offset, mode)) {
330      Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
331           g.UseRegister(base), g.UseImmediate(offset), g.UseRegister(value));
332    } else if (g.CanBeImmediate(base, mode)) {
333      Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
334           g.UseRegister(offset), g.UseImmediate(base), g.UseRegister(value));
335    } else {
336      Emit(opcode | AddressingModeField::encode(kMode_MRR), g.NoOutput(),
337           g.UseRegister(base), g.UseRegister(offset), g.UseRegister(value));
338    }
339  }
340}
341
342// Architecture supports unaligned access, therefore VisitLoad is used instead
343void InstructionSelector::VisitUnalignedLoad(Node* node) { UNREACHABLE(); }
344
345// Architecture supports unaligned access, therefore VisitStore is used instead
346void InstructionSelector::VisitUnalignedStore(Node* node) { UNREACHABLE(); }
347
348void InstructionSelector::VisitCheckedLoad(Node* node) {
349  CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
350  PPCOperandGenerator g(this);
351  Node* const base = node->InputAt(0);
352  Node* const offset = node->InputAt(1);
353  Node* const length = node->InputAt(2);
354  ArchOpcode opcode = kArchNop;
355  switch (load_rep.representation()) {
356    case MachineRepresentation::kWord8:
357      opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
358      break;
359    case MachineRepresentation::kWord16:
360      opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
361      break;
362    case MachineRepresentation::kWord32:
363      opcode = kCheckedLoadWord32;
364      break;
365#if V8_TARGET_ARCH_PPC64
366    case MachineRepresentation::kWord64:
367      opcode = kCheckedLoadWord64;
368      break;
369#endif
370    case MachineRepresentation::kFloat32:
371      opcode = kCheckedLoadFloat32;
372      break;
373    case MachineRepresentation::kFloat64:
374      opcode = kCheckedLoadFloat64;
375      break;
376    case MachineRepresentation::kBit:     // Fall through.
377    case MachineRepresentation::kTaggedSigned:   // Fall through.
378    case MachineRepresentation::kTaggedPointer:  // Fall through.
379    case MachineRepresentation::kTagged:  // Fall through.
380#if !V8_TARGET_ARCH_PPC64
381    case MachineRepresentation::kWord64:  // Fall through.
382#endif
383    case MachineRepresentation::kSimd128:  // Fall through.
384    case MachineRepresentation::kNone:
385      UNREACHABLE();
386      return;
387  }
388  AddressingMode addressingMode = kMode_MRR;
389  Emit(opcode | AddressingModeField::encode(addressingMode),
390       g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(offset),
391       g.UseOperand(length, kInt16Imm_Unsigned));
392}
393
394
395void InstructionSelector::VisitCheckedStore(Node* node) {
396  MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
397  PPCOperandGenerator g(this);
398  Node* const base = node->InputAt(0);
399  Node* const offset = node->InputAt(1);
400  Node* const length = node->InputAt(2);
401  Node* const value = node->InputAt(3);
402  ArchOpcode opcode = kArchNop;
403  switch (rep) {
404    case MachineRepresentation::kWord8:
405      opcode = kCheckedStoreWord8;
406      break;
407    case MachineRepresentation::kWord16:
408      opcode = kCheckedStoreWord16;
409      break;
410    case MachineRepresentation::kWord32:
411      opcode = kCheckedStoreWord32;
412      break;
413#if V8_TARGET_ARCH_PPC64
414    case MachineRepresentation::kWord64:
415      opcode = kCheckedStoreWord64;
416      break;
417#endif
418    case MachineRepresentation::kFloat32:
419      opcode = kCheckedStoreFloat32;
420      break;
421    case MachineRepresentation::kFloat64:
422      opcode = kCheckedStoreFloat64;
423      break;
424    case MachineRepresentation::kBit:     // Fall through.
425    case MachineRepresentation::kTaggedSigned:   // Fall through.
426    case MachineRepresentation::kTaggedPointer:  // Fall through.
427    case MachineRepresentation::kTagged:  // Fall through.
428#if !V8_TARGET_ARCH_PPC64
429    case MachineRepresentation::kWord64:  // Fall through.
430#endif
431    case MachineRepresentation::kSimd128:  // Fall through.
432    case MachineRepresentation::kNone:
433      UNREACHABLE();
434      return;
435  }
436  AddressingMode addressingMode = kMode_MRR;
437  Emit(opcode | AddressingModeField::encode(addressingMode), g.NoOutput(),
438       g.UseRegister(base), g.UseRegister(offset),
439       g.UseOperand(length, kInt16Imm_Unsigned), g.UseRegister(value));
440}
441
442
443template <typename Matcher>
444static void VisitLogical(InstructionSelector* selector, Node* node, Matcher* m,
445                         ArchOpcode opcode, bool left_can_cover,
446                         bool right_can_cover, ImmediateMode imm_mode) {
447  PPCOperandGenerator g(selector);
448
449  // Map instruction to equivalent operation with inverted right input.
450  ArchOpcode inv_opcode = opcode;
451  switch (opcode) {
452    case kPPC_And:
453      inv_opcode = kPPC_AndComplement;
454      break;
455    case kPPC_Or:
456      inv_opcode = kPPC_OrComplement;
457      break;
458    default:
459      UNREACHABLE();
460  }
461
462  // Select Logical(y, ~x) for Logical(Xor(x, -1), y).
463  if ((m->left().IsWord32Xor() || m->left().IsWord64Xor()) && left_can_cover) {
464    Matcher mleft(m->left().node());
465    if (mleft.right().Is(-1)) {
466      selector->Emit(inv_opcode, g.DefineAsRegister(node),
467                     g.UseRegister(m->right().node()),
468                     g.UseRegister(mleft.left().node()));
469      return;
470    }
471  }
472
473  // Select Logical(x, ~y) for Logical(x, Xor(y, -1)).
474  if ((m->right().IsWord32Xor() || m->right().IsWord64Xor()) &&
475      right_can_cover) {
476    Matcher mright(m->right().node());
477    if (mright.right().Is(-1)) {
478      // TODO(all): support shifted operand on right.
479      selector->Emit(inv_opcode, g.DefineAsRegister(node),
480                     g.UseRegister(m->left().node()),
481                     g.UseRegister(mright.left().node()));
482      return;
483    }
484  }
485
486  VisitBinop<Matcher>(selector, node, opcode, imm_mode);
487}
488
489
490static inline bool IsContiguousMask32(uint32_t value, int* mb, int* me) {
491  int mask_width = base::bits::CountPopulation32(value);
492  int mask_msb = base::bits::CountLeadingZeros32(value);
493  int mask_lsb = base::bits::CountTrailingZeros32(value);
494  if ((mask_width == 0) || (mask_msb + mask_width + mask_lsb != 32))
495    return false;
496  *mb = mask_lsb + mask_width - 1;
497  *me = mask_lsb;
498  return true;
499}
500
501
502#if V8_TARGET_ARCH_PPC64
503static inline bool IsContiguousMask64(uint64_t value, int* mb, int* me) {
504  int mask_width = base::bits::CountPopulation64(value);
505  int mask_msb = base::bits::CountLeadingZeros64(value);
506  int mask_lsb = base::bits::CountTrailingZeros64(value);
507  if ((mask_width == 0) || (mask_msb + mask_width + mask_lsb != 64))
508    return false;
509  *mb = mask_lsb + mask_width - 1;
510  *me = mask_lsb;
511  return true;
512}
513#endif
514
515
516// TODO(mbrandy): Absorb rotate-right into rlwinm?
517void InstructionSelector::VisitWord32And(Node* node) {
518  PPCOperandGenerator g(this);
519  Int32BinopMatcher m(node);
520  int mb = 0;
521  int me = 0;
522  if (m.right().HasValue() && IsContiguousMask32(m.right().Value(), &mb, &me)) {
523    int sh = 0;
524    Node* left = m.left().node();
525    if ((m.left().IsWord32Shr() || m.left().IsWord32Shl()) &&
526        CanCover(node, left)) {
527      // Try to absorb left/right shift into rlwinm
528      Int32BinopMatcher mleft(m.left().node());
529      if (mleft.right().IsInRange(0, 31)) {
530        left = mleft.left().node();
531        sh = mleft.right().Value();
532        if (m.left().IsWord32Shr()) {
533          // Adjust the mask such that it doesn't include any rotated bits.
534          if (mb > 31 - sh) mb = 31 - sh;
535          sh = (32 - sh) & 0x1f;
536        } else {
537          // Adjust the mask such that it doesn't include any rotated bits.
538          if (me < sh) me = sh;
539        }
540      }
541    }
542    if (mb >= me) {
543      Emit(kPPC_RotLeftAndMask32, g.DefineAsRegister(node), g.UseRegister(left),
544           g.TempImmediate(sh), g.TempImmediate(mb), g.TempImmediate(me));
545      return;
546    }
547  }
548  VisitLogical<Int32BinopMatcher>(
549      this, node, &m, kPPC_And, CanCover(node, m.left().node()),
550      CanCover(node, m.right().node()), kInt16Imm_Unsigned);
551}
552
553
554#if V8_TARGET_ARCH_PPC64
555// TODO(mbrandy): Absorb rotate-right into rldic?
556void InstructionSelector::VisitWord64And(Node* node) {
557  PPCOperandGenerator g(this);
558  Int64BinopMatcher m(node);
559  int mb = 0;
560  int me = 0;
561  if (m.right().HasValue() && IsContiguousMask64(m.right().Value(), &mb, &me)) {
562    int sh = 0;
563    Node* left = m.left().node();
564    if ((m.left().IsWord64Shr() || m.left().IsWord64Shl()) &&
565        CanCover(node, left)) {
566      // Try to absorb left/right shift into rldic
567      Int64BinopMatcher mleft(m.left().node());
568      if (mleft.right().IsInRange(0, 63)) {
569        left = mleft.left().node();
570        sh = mleft.right().Value();
571        if (m.left().IsWord64Shr()) {
572          // Adjust the mask such that it doesn't include any rotated bits.
573          if (mb > 63 - sh) mb = 63 - sh;
574          sh = (64 - sh) & 0x3f;
575        } else {
576          // Adjust the mask such that it doesn't include any rotated bits.
577          if (me < sh) me = sh;
578        }
579      }
580    }
581    if (mb >= me) {
582      bool match = false;
583      ArchOpcode opcode;
584      int mask;
585      if (me == 0) {
586        match = true;
587        opcode = kPPC_RotLeftAndClearLeft64;
588        mask = mb;
589      } else if (mb == 63) {
590        match = true;
591        opcode = kPPC_RotLeftAndClearRight64;
592        mask = me;
593      } else if (sh && me <= sh && m.left().IsWord64Shl()) {
594        match = true;
595        opcode = kPPC_RotLeftAndClear64;
596        mask = mb;
597      }
598      if (match) {
599        Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left),
600             g.TempImmediate(sh), g.TempImmediate(mask));
601        return;
602      }
603    }
604  }
605  VisitLogical<Int64BinopMatcher>(
606      this, node, &m, kPPC_And, CanCover(node, m.left().node()),
607      CanCover(node, m.right().node()), kInt16Imm_Unsigned);
608}
609#endif
610
611
612void InstructionSelector::VisitWord32Or(Node* node) {
613  Int32BinopMatcher m(node);
614  VisitLogical<Int32BinopMatcher>(
615      this, node, &m, kPPC_Or, CanCover(node, m.left().node()),
616      CanCover(node, m.right().node()), kInt16Imm_Unsigned);
617}
618
619
620#if V8_TARGET_ARCH_PPC64
621void InstructionSelector::VisitWord64Or(Node* node) {
622  Int64BinopMatcher m(node);
623  VisitLogical<Int64BinopMatcher>(
624      this, node, &m, kPPC_Or, CanCover(node, m.left().node()),
625      CanCover(node, m.right().node()), kInt16Imm_Unsigned);
626}
627#endif
628
629
630void InstructionSelector::VisitWord32Xor(Node* node) {
631  PPCOperandGenerator g(this);
632  Int32BinopMatcher m(node);
633  if (m.right().Is(-1)) {
634    Emit(kPPC_Not, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
635  } else {
636    VisitBinop<Int32BinopMatcher>(this, node, kPPC_Xor, kInt16Imm_Unsigned);
637  }
638}
639
640
641#if V8_TARGET_ARCH_PPC64
642void InstructionSelector::VisitWord64Xor(Node* node) {
643  PPCOperandGenerator g(this);
644  Int64BinopMatcher m(node);
645  if (m.right().Is(-1)) {
646    Emit(kPPC_Not, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
647  } else {
648    VisitBinop<Int64BinopMatcher>(this, node, kPPC_Xor, kInt16Imm_Unsigned);
649  }
650}
651#endif
652
653
654void InstructionSelector::VisitWord32Shl(Node* node) {
655  PPCOperandGenerator g(this);
656  Int32BinopMatcher m(node);
657  if (m.left().IsWord32And() && m.right().IsInRange(0, 31)) {
658    // Try to absorb logical-and into rlwinm
659    Int32BinopMatcher mleft(m.left().node());
660    int sh = m.right().Value();
661    int mb;
662    int me;
663    if (mleft.right().HasValue() &&
664        IsContiguousMask32(mleft.right().Value() << sh, &mb, &me)) {
665      // Adjust the mask such that it doesn't include any rotated bits.
666      if (me < sh) me = sh;
667      if (mb >= me) {
668        Emit(kPPC_RotLeftAndMask32, g.DefineAsRegister(node),
669             g.UseRegister(mleft.left().node()), g.TempImmediate(sh),
670             g.TempImmediate(mb), g.TempImmediate(me));
671        return;
672      }
673    }
674  }
675  VisitRRO(this, kPPC_ShiftLeft32, node, kShift32Imm);
676}
677
678
679#if V8_TARGET_ARCH_PPC64
680void InstructionSelector::VisitWord64Shl(Node* node) {
681  PPCOperandGenerator g(this);
682  Int64BinopMatcher m(node);
683  // TODO(mbrandy): eliminate left sign extension if right >= 32
684  if (m.left().IsWord64And() && m.right().IsInRange(0, 63)) {
685    // Try to absorb logical-and into rldic
686    Int64BinopMatcher mleft(m.left().node());
687    int sh = m.right().Value();
688    int mb;
689    int me;
690    if (mleft.right().HasValue() &&
691        IsContiguousMask64(mleft.right().Value() << sh, &mb, &me)) {
692      // Adjust the mask such that it doesn't include any rotated bits.
693      if (me < sh) me = sh;
694      if (mb >= me) {
695        bool match = false;
696        ArchOpcode opcode;
697        int mask;
698        if (me == 0) {
699          match = true;
700          opcode = kPPC_RotLeftAndClearLeft64;
701          mask = mb;
702        } else if (mb == 63) {
703          match = true;
704          opcode = kPPC_RotLeftAndClearRight64;
705          mask = me;
706        } else if (sh && me <= sh) {
707          match = true;
708          opcode = kPPC_RotLeftAndClear64;
709          mask = mb;
710        }
711        if (match) {
712          Emit(opcode, g.DefineAsRegister(node),
713               g.UseRegister(mleft.left().node()), g.TempImmediate(sh),
714               g.TempImmediate(mask));
715          return;
716        }
717      }
718    }
719  }
720  VisitRRO(this, kPPC_ShiftLeft64, node, kShift64Imm);
721}
722#endif
723
724
725void InstructionSelector::VisitWord32Shr(Node* node) {
726  PPCOperandGenerator g(this);
727  Int32BinopMatcher m(node);
728  if (m.left().IsWord32And() && m.right().IsInRange(0, 31)) {
729    // Try to absorb logical-and into rlwinm
730    Int32BinopMatcher mleft(m.left().node());
731    int sh = m.right().Value();
732    int mb;
733    int me;
734    if (mleft.right().HasValue() &&
735        IsContiguousMask32((uint32_t)(mleft.right().Value()) >> sh, &mb, &me)) {
736      // Adjust the mask such that it doesn't include any rotated bits.
737      if (mb > 31 - sh) mb = 31 - sh;
738      sh = (32 - sh) & 0x1f;
739      if (mb >= me) {
740        Emit(kPPC_RotLeftAndMask32, g.DefineAsRegister(node),
741             g.UseRegister(mleft.left().node()), g.TempImmediate(sh),
742             g.TempImmediate(mb), g.TempImmediate(me));
743        return;
744      }
745    }
746  }
747  VisitRRO(this, kPPC_ShiftRight32, node, kShift32Imm);
748}
749
750#if V8_TARGET_ARCH_PPC64
751void InstructionSelector::VisitWord64Shr(Node* node) {
752  PPCOperandGenerator g(this);
753  Int64BinopMatcher m(node);
754  if (m.left().IsWord64And() && m.right().IsInRange(0, 63)) {
755    // Try to absorb logical-and into rldic
756    Int64BinopMatcher mleft(m.left().node());
757    int sh = m.right().Value();
758    int mb;
759    int me;
760    if (mleft.right().HasValue() &&
761        IsContiguousMask64((uint64_t)(mleft.right().Value()) >> sh, &mb, &me)) {
762      // Adjust the mask such that it doesn't include any rotated bits.
763      if (mb > 63 - sh) mb = 63 - sh;
764      sh = (64 - sh) & 0x3f;
765      if (mb >= me) {
766        bool match = false;
767        ArchOpcode opcode;
768        int mask;
769        if (me == 0) {
770          match = true;
771          opcode = kPPC_RotLeftAndClearLeft64;
772          mask = mb;
773        } else if (mb == 63) {
774          match = true;
775          opcode = kPPC_RotLeftAndClearRight64;
776          mask = me;
777        }
778        if (match) {
779          Emit(opcode, g.DefineAsRegister(node),
780               g.UseRegister(mleft.left().node()), g.TempImmediate(sh),
781               g.TempImmediate(mask));
782          return;
783        }
784      }
785    }
786  }
787  VisitRRO(this, kPPC_ShiftRight64, node, kShift64Imm);
788}
789#endif
790
791
792void InstructionSelector::VisitWord32Sar(Node* node) {
793  PPCOperandGenerator g(this);
794  Int32BinopMatcher m(node);
795  // Replace with sign extension for (x << K) >> K where K is 16 or 24.
796  if (CanCover(node, m.left().node()) && m.left().IsWord32Shl()) {
797    Int32BinopMatcher mleft(m.left().node());
798    if (mleft.right().Is(16) && m.right().Is(16)) {
799      Emit(kPPC_ExtendSignWord16, g.DefineAsRegister(node),
800           g.UseRegister(mleft.left().node()));
801      return;
802    } else if (mleft.right().Is(24) && m.right().Is(24)) {
803      Emit(kPPC_ExtendSignWord8, g.DefineAsRegister(node),
804           g.UseRegister(mleft.left().node()));
805      return;
806    }
807  }
808  VisitRRO(this, kPPC_ShiftRightAlg32, node, kShift32Imm);
809}
810
811#if !V8_TARGET_ARCH_PPC64
812void VisitPairBinop(InstructionSelector* selector, InstructionCode opcode,
813                    InstructionCode opcode2, Node* node) {
814  PPCOperandGenerator g(selector);
815
816  Node* projection1 = NodeProperties::FindProjection(node, 1);
817  if (projection1) {
818    // We use UseUniqueRegister here to avoid register sharing with the output
819    // registers.
820    InstructionOperand inputs[] = {
821        g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
822        g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
823
824    InstructionOperand outputs[] = {
825        g.DefineAsRegister(node),
826        g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
827
828    selector->Emit(opcode, 2, outputs, 4, inputs);
829  } else {
830    // The high word of the result is not used, so we emit the standard 32 bit
831    // instruction.
832    selector->Emit(opcode2, g.DefineSameAsFirst(node),
833                   g.UseRegister(node->InputAt(0)),
834                   g.UseRegister(node->InputAt(2)));
835  }
836}
837
838void InstructionSelector::VisitInt32PairAdd(Node* node) {
839  VisitPairBinop(this, kPPC_AddPair, kPPC_Add, node);
840}
841
842void InstructionSelector::VisitInt32PairSub(Node* node) {
843  VisitPairBinop(this, kPPC_SubPair, kPPC_Sub, node);
844}
845
846void InstructionSelector::VisitInt32PairMul(Node* node) {
847  PPCOperandGenerator g(this);
848  Node* projection1 = NodeProperties::FindProjection(node, 1);
849  if (projection1) {
850    InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
851                                   g.UseUniqueRegister(node->InputAt(1)),
852                                   g.UseUniqueRegister(node->InputAt(2)),
853                                   g.UseUniqueRegister(node->InputAt(3))};
854
855    InstructionOperand outputs[] = {
856        g.DefineAsRegister(node),
857        g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
858
859    InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
860
861    Emit(kPPC_MulPair, 2, outputs, 4, inputs, 2, temps);
862  } else {
863    // The high word of the result is not used, so we emit the standard 32 bit
864    // instruction.
865    Emit(kPPC_Mul32, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
866         g.UseRegister(node->InputAt(2)));
867  }
868}
869
870namespace {
871// Shared routine for multiple shift operations.
872void VisitPairShift(InstructionSelector* selector, InstructionCode opcode,
873                    Node* node) {
874  PPCOperandGenerator g(selector);
875  // We use g.UseUniqueRegister here to guarantee that there is
876  // no register aliasing of input registers with output registers.
877  Int32Matcher m(node->InputAt(2));
878  InstructionOperand shift_operand;
879  if (m.HasValue()) {
880    shift_operand = g.UseImmediate(m.node());
881  } else {
882    shift_operand = g.UseUniqueRegister(m.node());
883  }
884
885  InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
886                                 g.UseUniqueRegister(node->InputAt(1)),
887                                 shift_operand};
888
889  Node* projection1 = NodeProperties::FindProjection(node, 1);
890
891  InstructionOperand outputs[2];
892  InstructionOperand temps[1];
893  int32_t output_count = 0;
894  int32_t temp_count = 0;
895
896  outputs[output_count++] = g.DefineAsRegister(node);
897  if (projection1) {
898    outputs[output_count++] = g.DefineAsRegister(projection1);
899  } else {
900    temps[temp_count++] = g.TempRegister();
901  }
902
903  selector->Emit(opcode, output_count, outputs, 3, inputs, temp_count, temps);
904}
905}  // namespace
906
907void InstructionSelector::VisitWord32PairShl(Node* node) {
908  VisitPairShift(this, kPPC_ShiftLeftPair, node);
909}
910
911void InstructionSelector::VisitWord32PairShr(Node* node) {
912  VisitPairShift(this, kPPC_ShiftRightPair, node);
913}
914
915void InstructionSelector::VisitWord32PairSar(Node* node) {
916  VisitPairShift(this, kPPC_ShiftRightAlgPair, node);
917}
918#endif
919
920#if V8_TARGET_ARCH_PPC64
921void InstructionSelector::VisitWord64Sar(Node* node) {
922  PPCOperandGenerator g(this);
923  Int64BinopMatcher m(node);
924  if (CanCover(m.node(), m.left().node()) && m.left().IsLoad() &&
925      m.right().Is(32)) {
926    // Just load and sign-extend the interesting 4 bytes instead. This happens,
927    // for example, when we're loading and untagging SMIs.
928    BaseWithIndexAndDisplacement64Matcher mleft(m.left().node(),
929                                                AddressOption::kAllowAll);
930    if (mleft.matches() && mleft.index() == nullptr) {
931      int64_t offset = 0;
932      Node* displacement = mleft.displacement();
933      if (displacement != nullptr) {
934        Int64Matcher mdisplacement(displacement);
935        DCHECK(mdisplacement.HasValue());
936        offset = mdisplacement.Value();
937      }
938      offset = SmiWordOffset(offset);
939      if (g.CanBeImmediate(offset, kInt16Imm_4ByteAligned)) {
940        Emit(kPPC_LoadWordS32 | AddressingModeField::encode(kMode_MRI),
941             g.DefineAsRegister(node), g.UseRegister(mleft.base()),
942             g.TempImmediate(offset));
943        return;
944      }
945    }
946  }
947  VisitRRO(this, kPPC_ShiftRightAlg64, node, kShift64Imm);
948}
949#endif
950
951
952// TODO(mbrandy): Absorb logical-and into rlwinm?
953void InstructionSelector::VisitWord32Ror(Node* node) {
954  VisitRRO(this, kPPC_RotRight32, node, kShift32Imm);
955}
956
957
958#if V8_TARGET_ARCH_PPC64
959// TODO(mbrandy): Absorb logical-and into rldic?
960void InstructionSelector::VisitWord64Ror(Node* node) {
961  VisitRRO(this, kPPC_RotRight64, node, kShift64Imm);
962}
963#endif
964
965
966void InstructionSelector::VisitWord32Clz(Node* node) {
967  PPCOperandGenerator g(this);
968  Emit(kPPC_Cntlz32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
969}
970
971
972#if V8_TARGET_ARCH_PPC64
973void InstructionSelector::VisitWord64Clz(Node* node) {
974  PPCOperandGenerator g(this);
975  Emit(kPPC_Cntlz64, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
976}
977#endif
978
979
980void InstructionSelector::VisitWord32Popcnt(Node* node) {
981  PPCOperandGenerator g(this);
982  Emit(kPPC_Popcnt32, g.DefineAsRegister(node),
983       g.UseRegister(node->InputAt(0)));
984}
985
986
987#if V8_TARGET_ARCH_PPC64
988void InstructionSelector::VisitWord64Popcnt(Node* node) {
989  PPCOperandGenerator g(this);
990  Emit(kPPC_Popcnt64, g.DefineAsRegister(node),
991       g.UseRegister(node->InputAt(0)));
992}
993#endif
994
995
996void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
997
998
999#if V8_TARGET_ARCH_PPC64
1000void InstructionSelector::VisitWord64Ctz(Node* node) { UNREACHABLE(); }
1001#endif
1002
1003
1004void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
1005
1006
1007#if V8_TARGET_ARCH_PPC64
1008void InstructionSelector::VisitWord64ReverseBits(Node* node) { UNREACHABLE(); }
1009#endif
1010
1011void InstructionSelector::VisitWord64ReverseBytes(Node* node) { UNREACHABLE(); }
1012
1013void InstructionSelector::VisitWord32ReverseBytes(Node* node) { UNREACHABLE(); }
1014
1015void InstructionSelector::VisitInt32Add(Node* node) {
1016  VisitBinop<Int32BinopMatcher>(this, node, kPPC_Add, kInt16Imm);
1017}
1018
1019
1020#if V8_TARGET_ARCH_PPC64
1021void InstructionSelector::VisitInt64Add(Node* node) {
1022  VisitBinop<Int64BinopMatcher>(this, node, kPPC_Add, kInt16Imm);
1023}
1024#endif
1025
1026void InstructionSelector::VisitInt32Sub(Node* node) {
1027  PPCOperandGenerator g(this);
1028  Int32BinopMatcher m(node);
1029  if (m.left().Is(0)) {
1030    Emit(kPPC_Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node()));
1031  } else {
1032    VisitBinop<Int32BinopMatcher>(this, node, kPPC_Sub, kInt16Imm_Negate);
1033  }
1034}
1035
1036
1037#if V8_TARGET_ARCH_PPC64
1038void InstructionSelector::VisitInt64Sub(Node* node) {
1039  PPCOperandGenerator g(this);
1040  Int64BinopMatcher m(node);
1041  if (m.left().Is(0)) {
1042    Emit(kPPC_Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node()));
1043  } else {
1044    VisitBinop<Int64BinopMatcher>(this, node, kPPC_Sub, kInt16Imm_Negate);
1045  }
1046}
1047#endif
1048
1049namespace {
1050
1051void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1052                  InstructionOperand left, InstructionOperand right,
1053                  FlagsContinuation* cont);
1054void EmitInt32MulWithOverflow(InstructionSelector* selector, Node* node,
1055                              FlagsContinuation* cont) {
1056  PPCOperandGenerator g(selector);
1057  Int32BinopMatcher m(node);
1058  InstructionOperand result_operand = g.DefineAsRegister(node);
1059  InstructionOperand high32_operand = g.TempRegister();
1060  InstructionOperand temp_operand = g.TempRegister();
1061  {
1062    InstructionOperand outputs[] = {result_operand, high32_operand};
1063    InstructionOperand inputs[] = {g.UseRegister(m.left().node()),
1064                                   g.UseRegister(m.right().node())};
1065    selector->Emit(kPPC_Mul32WithHigh32, 2, outputs, 2, inputs);
1066  }
1067  {
1068    InstructionOperand shift_31 = g.UseImmediate(31);
1069    InstructionOperand outputs[] = {temp_operand};
1070    InstructionOperand inputs[] = {result_operand, shift_31};
1071    selector->Emit(kPPC_ShiftRightAlg32, 1, outputs, 2, inputs);
1072  }
1073
1074  VisitCompare(selector, kPPC_Cmp32, high32_operand, temp_operand, cont);
1075}
1076
1077}  // namespace
1078
1079
1080void InstructionSelector::VisitInt32Mul(Node* node) {
1081  VisitRRR(this, kPPC_Mul32, node);
1082}
1083
1084
1085#if V8_TARGET_ARCH_PPC64
1086void InstructionSelector::VisitInt64Mul(Node* node) {
1087  VisitRRR(this, kPPC_Mul64, node);
1088}
1089#endif
1090
1091
1092void InstructionSelector::VisitInt32MulHigh(Node* node) {
1093  PPCOperandGenerator g(this);
1094  Emit(kPPC_MulHigh32, g.DefineAsRegister(node),
1095       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
1096}
1097
1098
1099void InstructionSelector::VisitUint32MulHigh(Node* node) {
1100  PPCOperandGenerator g(this);
1101  Emit(kPPC_MulHighU32, g.DefineAsRegister(node),
1102       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
1103}
1104
1105
1106void InstructionSelector::VisitInt32Div(Node* node) {
1107  VisitRRR(this, kPPC_Div32, node);
1108}
1109
1110
1111#if V8_TARGET_ARCH_PPC64
1112void InstructionSelector::VisitInt64Div(Node* node) {
1113  VisitRRR(this, kPPC_Div64, node);
1114}
1115#endif
1116
1117
1118void InstructionSelector::VisitUint32Div(Node* node) {
1119  VisitRRR(this, kPPC_DivU32, node);
1120}
1121
1122
1123#if V8_TARGET_ARCH_PPC64
1124void InstructionSelector::VisitUint64Div(Node* node) {
1125  VisitRRR(this, kPPC_DivU64, node);
1126}
1127#endif
1128
1129
1130void InstructionSelector::VisitInt32Mod(Node* node) {
1131  VisitRRR(this, kPPC_Mod32, node);
1132}
1133
1134
1135#if V8_TARGET_ARCH_PPC64
1136void InstructionSelector::VisitInt64Mod(Node* node) {
1137  VisitRRR(this, kPPC_Mod64, node);
1138}
1139#endif
1140
1141
1142void InstructionSelector::VisitUint32Mod(Node* node) {
1143  VisitRRR(this, kPPC_ModU32, node);
1144}
1145
1146
1147#if V8_TARGET_ARCH_PPC64
1148void InstructionSelector::VisitUint64Mod(Node* node) {
1149  VisitRRR(this, kPPC_ModU64, node);
1150}
1151#endif
1152
1153
1154void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
1155  VisitRR(this, kPPC_Float32ToDouble, node);
1156}
1157
1158
1159void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
1160  VisitRR(this, kPPC_Int32ToFloat32, node);
1161}
1162
1163
1164void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
1165  VisitRR(this, kPPC_Uint32ToFloat32, node);
1166}
1167
1168
1169void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
1170  VisitRR(this, kPPC_Int32ToDouble, node);
1171}
1172
1173
1174void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
1175  VisitRR(this, kPPC_Uint32ToDouble, node);
1176}
1177
1178
1179void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
1180  VisitRR(this, kPPC_DoubleToInt32, node);
1181}
1182
1183
1184void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
1185  VisitRR(this, kPPC_DoubleToUint32, node);
1186}
1187
1188void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) {
1189  VisitRR(this, kPPC_DoubleToUint32, node);
1190}
1191
1192#if V8_TARGET_ARCH_PPC64
1193void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
1194  VisitTryTruncateDouble(this, kPPC_DoubleToInt64, node);
1195}
1196
1197
1198void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) {
1199  VisitTryTruncateDouble(this, kPPC_DoubleToInt64, node);
1200}
1201
1202
1203void InstructionSelector::VisitTryTruncateFloat32ToUint64(Node* node) {
1204  VisitTryTruncateDouble(this, kPPC_DoubleToUint64, node);
1205}
1206
1207
1208void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) {
1209  VisitTryTruncateDouble(this, kPPC_DoubleToUint64, node);
1210}
1211
1212
1213void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
1214  // TODO(mbrandy): inspect input to see if nop is appropriate.
1215  VisitRR(this, kPPC_ExtendSignWord32, node);
1216}
1217
1218
1219void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
1220  // TODO(mbrandy): inspect input to see if nop is appropriate.
1221  VisitRR(this, kPPC_Uint32ToUint64, node);
1222}
1223#endif
1224
1225
1226void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
1227  VisitRR(this, kPPC_DoubleToFloat32, node);
1228}
1229
1230void InstructionSelector::VisitTruncateFloat64ToWord32(Node* node) {
1231  VisitRR(this, kArchTruncateDoubleToI, node);
1232}
1233
1234void InstructionSelector::VisitRoundFloat64ToInt32(Node* node) {
1235  VisitRR(this, kPPC_DoubleToInt32, node);
1236}
1237
1238
1239void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
1240  VisitRR(this, kPPC_DoubleToInt32, node);
1241}
1242
1243
1244void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
1245  VisitRR(this, kPPC_DoubleToUint32, node);
1246}
1247
1248
1249#if V8_TARGET_ARCH_PPC64
1250void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
1251  // TODO(mbrandy): inspect input to see if nop is appropriate.
1252  VisitRR(this, kPPC_Int64ToInt32, node);
1253}
1254
1255
1256void InstructionSelector::VisitRoundInt64ToFloat32(Node* node) {
1257  VisitRR(this, kPPC_Int64ToFloat32, node);
1258}
1259
1260
1261void InstructionSelector::VisitRoundInt64ToFloat64(Node* node) {
1262  VisitRR(this, kPPC_Int64ToDouble, node);
1263}
1264
1265
1266void InstructionSelector::VisitRoundUint64ToFloat32(Node* node) {
1267  VisitRR(this, kPPC_Uint64ToFloat32, node);
1268}
1269
1270
1271void InstructionSelector::VisitRoundUint64ToFloat64(Node* node) {
1272  VisitRR(this, kPPC_Uint64ToDouble, node);
1273}
1274#endif
1275
1276
1277void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
1278  VisitRR(this, kPPC_BitcastFloat32ToInt32, node);
1279}
1280
1281
1282#if V8_TARGET_ARCH_PPC64
1283void InstructionSelector::VisitBitcastFloat64ToInt64(Node* node) {
1284  VisitRR(this, kPPC_BitcastDoubleToInt64, node);
1285}
1286#endif
1287
1288
1289void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
1290  VisitRR(this, kPPC_BitcastInt32ToFloat32, node);
1291}
1292
1293
1294#if V8_TARGET_ARCH_PPC64
1295void InstructionSelector::VisitBitcastInt64ToFloat64(Node* node) {
1296  VisitRR(this, kPPC_BitcastInt64ToDouble, node);
1297}
1298#endif
1299
1300
1301void InstructionSelector::VisitFloat32Add(Node* node) {
1302  VisitRRR(this, kPPC_AddDouble | MiscField::encode(1), node);
1303}
1304
1305
1306void InstructionSelector::VisitFloat64Add(Node* node) {
1307  // TODO(mbrandy): detect multiply-add
1308  VisitRRR(this, kPPC_AddDouble, node);
1309}
1310
1311
1312void InstructionSelector::VisitFloat32Sub(Node* node) {
1313  VisitRRR(this, kPPC_SubDouble | MiscField::encode(1), node);
1314}
1315
1316void InstructionSelector::VisitFloat64Sub(Node* node) {
1317  // TODO(mbrandy): detect multiply-subtract
1318  VisitRRR(this, kPPC_SubDouble, node);
1319}
1320
1321void InstructionSelector::VisitFloat32Mul(Node* node) {
1322  VisitRRR(this, kPPC_MulDouble | MiscField::encode(1), node);
1323}
1324
1325
1326void InstructionSelector::VisitFloat64Mul(Node* node) {
1327  // TODO(mbrandy): detect negate
1328  VisitRRR(this, kPPC_MulDouble, node);
1329}
1330
1331
1332void InstructionSelector::VisitFloat32Div(Node* node) {
1333  VisitRRR(this, kPPC_DivDouble | MiscField::encode(1), node);
1334}
1335
1336
1337void InstructionSelector::VisitFloat64Div(Node* node) {
1338  VisitRRR(this, kPPC_DivDouble, node);
1339}
1340
1341
1342void InstructionSelector::VisitFloat64Mod(Node* node) {
1343  PPCOperandGenerator g(this);
1344  Emit(kPPC_ModDouble, g.DefineAsFixed(node, d1),
1345       g.UseFixed(node->InputAt(0), d1),
1346       g.UseFixed(node->InputAt(1), d2))->MarkAsCall();
1347}
1348
1349void InstructionSelector::VisitFloat32Max(Node* node) {
1350  VisitRRR(this, kPPC_MaxDouble | MiscField::encode(1), node);
1351}
1352
1353void InstructionSelector::VisitFloat64Max(Node* node) {
1354  VisitRRR(this, kPPC_MaxDouble, node);
1355}
1356
1357
1358void InstructionSelector::VisitFloat64SilenceNaN(Node* node) {
1359  VisitRR(this, kPPC_Float64SilenceNaN, node);
1360}
1361
1362void InstructionSelector::VisitFloat32Min(Node* node) {
1363  VisitRRR(this, kPPC_MinDouble | MiscField::encode(1), node);
1364}
1365
1366void InstructionSelector::VisitFloat64Min(Node* node) {
1367  VisitRRR(this, kPPC_MinDouble, node);
1368}
1369
1370
1371void InstructionSelector::VisitFloat32Abs(Node* node) {
1372  VisitRR(this, kPPC_AbsDouble | MiscField::encode(1), node);
1373}
1374
1375
1376void InstructionSelector::VisitFloat64Abs(Node* node) {
1377  VisitRR(this, kPPC_AbsDouble, node);
1378}
1379
1380void InstructionSelector::VisitFloat32Sqrt(Node* node) {
1381  VisitRR(this, kPPC_SqrtDouble | MiscField::encode(1), node);
1382}
1383
1384void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
1385                                                  InstructionCode opcode) {
1386  PPCOperandGenerator g(this);
1387  Emit(opcode, g.DefineAsFixed(node, d1), g.UseFixed(node->InputAt(0), d1))
1388       ->MarkAsCall();
1389}
1390
1391void InstructionSelector::VisitFloat64Ieee754Binop(Node* node,
1392                                                  InstructionCode opcode) {
1393  PPCOperandGenerator g(this);
1394  Emit(opcode, g.DefineAsFixed(node, d1),
1395       g.UseFixed(node->InputAt(0), d1),
1396       g.UseFixed(node->InputAt(1), d2))->MarkAsCall();
1397}
1398
1399void InstructionSelector::VisitFloat64Sqrt(Node* node) {
1400  VisitRR(this, kPPC_SqrtDouble, node);
1401}
1402
1403
1404void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1405  VisitRR(this, kPPC_FloorDouble | MiscField::encode(1), node);
1406}
1407
1408
1409void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1410  VisitRR(this, kPPC_FloorDouble, node);
1411}
1412
1413
1414void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1415  VisitRR(this, kPPC_CeilDouble | MiscField::encode(1), node);
1416}
1417
1418
1419void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1420  VisitRR(this, kPPC_CeilDouble, node);
1421}
1422
1423
1424void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1425  VisitRR(this, kPPC_TruncateDouble | MiscField::encode(1), node);
1426}
1427
1428
1429void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
1430  VisitRR(this, kPPC_TruncateDouble, node);
1431}
1432
1433
1434void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
1435  VisitRR(this, kPPC_RoundDouble, node);
1436}
1437
1438
1439void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1440  UNREACHABLE();
1441}
1442
1443
1444void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1445  UNREACHABLE();
1446}
1447
1448void InstructionSelector::VisitFloat32Neg(Node* node) {
1449  VisitRR(this, kPPC_NegDouble, node);
1450}
1451
1452void InstructionSelector::VisitFloat64Neg(Node* node) {
1453  VisitRR(this, kPPC_NegDouble, node);
1454}
1455
1456void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
1457  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1458    FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
1459    return VisitBinop<Int32BinopMatcher>(this, node, kPPC_AddWithOverflow32,
1460                                         kInt16Imm, &cont);
1461  }
1462  FlagsContinuation cont;
1463  VisitBinop<Int32BinopMatcher>(this, node, kPPC_AddWithOverflow32, kInt16Imm,
1464                                &cont);
1465}
1466
1467
1468void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
1469  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1470    FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
1471    return VisitBinop<Int32BinopMatcher>(this, node, kPPC_SubWithOverflow32,
1472                                         kInt16Imm_Negate, &cont);
1473  }
1474  FlagsContinuation cont;
1475  VisitBinop<Int32BinopMatcher>(this, node, kPPC_SubWithOverflow32,
1476                                kInt16Imm_Negate, &cont);
1477}
1478
1479
1480#if V8_TARGET_ARCH_PPC64
1481void InstructionSelector::VisitInt64AddWithOverflow(Node* node) {
1482  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1483    FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
1484    return VisitBinop<Int64BinopMatcher>(this, node, kPPC_Add, kInt16Imm,
1485                                         &cont);
1486  }
1487  FlagsContinuation cont;
1488  VisitBinop<Int64BinopMatcher>(this, node, kPPC_Add, kInt16Imm, &cont);
1489}
1490
1491
1492void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
1493  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1494    FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
1495    return VisitBinop<Int64BinopMatcher>(this, node, kPPC_Sub, kInt16Imm_Negate,
1496                                         &cont);
1497  }
1498  FlagsContinuation cont;
1499  VisitBinop<Int64BinopMatcher>(this, node, kPPC_Sub, kInt16Imm_Negate, &cont);
1500}
1501#endif
1502
1503
1504static bool CompareLogical(FlagsContinuation* cont) {
1505  switch (cont->condition()) {
1506    case kUnsignedLessThan:
1507    case kUnsignedGreaterThanOrEqual:
1508    case kUnsignedLessThanOrEqual:
1509    case kUnsignedGreaterThan:
1510      return true;
1511    default:
1512      return false;
1513  }
1514  UNREACHABLE();
1515  return false;
1516}
1517
1518
1519namespace {
1520
1521// Shared routine for multiple compare operations.
1522void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1523                  InstructionOperand left, InstructionOperand right,
1524                  FlagsContinuation* cont) {
1525  PPCOperandGenerator g(selector);
1526  opcode = cont->Encode(opcode);
1527  if (cont->IsBranch()) {
1528    selector->Emit(opcode, g.NoOutput(), left, right,
1529                   g.Label(cont->true_block()), g.Label(cont->false_block()));
1530  } else if (cont->IsDeoptimize()) {
1531    selector->EmitDeoptimize(opcode, g.NoOutput(), left, right, cont->reason(),
1532                             cont->frame_state());
1533  } else {
1534    DCHECK(cont->IsSet());
1535    selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
1536  }
1537}
1538
1539
1540// Shared routine for multiple word compare operations.
1541void VisitWordCompare(InstructionSelector* selector, Node* node,
1542                      InstructionCode opcode, FlagsContinuation* cont,
1543                      bool commutative, ImmediateMode immediate_mode) {
1544  PPCOperandGenerator g(selector);
1545  Node* left = node->InputAt(0);
1546  Node* right = node->InputAt(1);
1547
1548  // Match immediates on left or right side of comparison.
1549  if (g.CanBeImmediate(right, immediate_mode)) {
1550    VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
1551                 cont);
1552  } else if (g.CanBeImmediate(left, immediate_mode)) {
1553    if (!commutative) cont->Commute();
1554    VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
1555                 cont);
1556  } else {
1557    VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
1558                 cont);
1559  }
1560}
1561
1562
1563void VisitWord32Compare(InstructionSelector* selector, Node* node,
1564                        FlagsContinuation* cont) {
1565  ImmediateMode mode = (CompareLogical(cont) ? kInt16Imm_Unsigned : kInt16Imm);
1566  VisitWordCompare(selector, node, kPPC_Cmp32, cont, false, mode);
1567}
1568
1569
1570#if V8_TARGET_ARCH_PPC64
1571void VisitWord64Compare(InstructionSelector* selector, Node* node,
1572                        FlagsContinuation* cont) {
1573  ImmediateMode mode = (CompareLogical(cont) ? kInt16Imm_Unsigned : kInt16Imm);
1574  VisitWordCompare(selector, node, kPPC_Cmp64, cont, false, mode);
1575}
1576#endif
1577
1578
1579// Shared routine for multiple float32 compare operations.
1580void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1581                         FlagsContinuation* cont) {
1582  PPCOperandGenerator g(selector);
1583  Node* left = node->InputAt(0);
1584  Node* right = node->InputAt(1);
1585  VisitCompare(selector, kPPC_CmpDouble, g.UseRegister(left),
1586               g.UseRegister(right), cont);
1587}
1588
1589
1590// Shared routine for multiple float64 compare operations.
1591void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1592                         FlagsContinuation* cont) {
1593  PPCOperandGenerator g(selector);
1594  Node* left = node->InputAt(0);
1595  Node* right = node->InputAt(1);
1596  VisitCompare(selector, kPPC_CmpDouble, g.UseRegister(left),
1597               g.UseRegister(right), cont);
1598}
1599
1600
1601// Shared routine for word comparisons against zero.
1602void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1603                          Node* value, InstructionCode opcode,
1604                          FlagsContinuation* cont) {
1605  // Try to combine with comparisons against 0 by simply inverting the branch.
1606  while (value->opcode() == IrOpcode::kWord32Equal &&
1607         selector->CanCover(user, value)) {
1608    Int32BinopMatcher m(value);
1609    if (!m.right().Is(0)) break;
1610
1611    user = value;
1612    value = m.left().node();
1613    cont->Negate();
1614  }
1615
1616  if (selector->CanCover(user, value)) {
1617    switch (value->opcode()) {
1618      case IrOpcode::kWord32Equal:
1619        cont->OverwriteAndNegateIfEqual(kEqual);
1620        return VisitWord32Compare(selector, value, cont);
1621      case IrOpcode::kInt32LessThan:
1622        cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1623        return VisitWord32Compare(selector, value, cont);
1624      case IrOpcode::kInt32LessThanOrEqual:
1625        cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1626        return VisitWord32Compare(selector, value, cont);
1627      case IrOpcode::kUint32LessThan:
1628        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1629        return VisitWord32Compare(selector, value, cont);
1630      case IrOpcode::kUint32LessThanOrEqual:
1631        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1632        return VisitWord32Compare(selector, value, cont);
1633#if V8_TARGET_ARCH_PPC64
1634      case IrOpcode::kWord64Equal:
1635        cont->OverwriteAndNegateIfEqual(kEqual);
1636        return VisitWord64Compare(selector, value, cont);
1637      case IrOpcode::kInt64LessThan:
1638        cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1639        return VisitWord64Compare(selector, value, cont);
1640      case IrOpcode::kInt64LessThanOrEqual:
1641        cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1642        return VisitWord64Compare(selector, value, cont);
1643      case IrOpcode::kUint64LessThan:
1644        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1645        return VisitWord64Compare(selector, value, cont);
1646      case IrOpcode::kUint64LessThanOrEqual:
1647        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1648        return VisitWord64Compare(selector, value, cont);
1649#endif
1650      case IrOpcode::kFloat32Equal:
1651        cont->OverwriteAndNegateIfEqual(kEqual);
1652        return VisitFloat32Compare(selector, value, cont);
1653      case IrOpcode::kFloat32LessThan:
1654        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1655        return VisitFloat32Compare(selector, value, cont);
1656      case IrOpcode::kFloat32LessThanOrEqual:
1657        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1658        return VisitFloat32Compare(selector, value, cont);
1659      case IrOpcode::kFloat64Equal:
1660        cont->OverwriteAndNegateIfEqual(kEqual);
1661        return VisitFloat64Compare(selector, value, cont);
1662      case IrOpcode::kFloat64LessThan:
1663        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1664        return VisitFloat64Compare(selector, value, cont);
1665      case IrOpcode::kFloat64LessThanOrEqual:
1666        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1667        return VisitFloat64Compare(selector, value, cont);
1668      case IrOpcode::kProjection:
1669        // Check if this is the overflow output projection of an
1670        // <Operation>WithOverflow node.
1671        if (ProjectionIndexOf(value->op()) == 1u) {
1672          // We cannot combine the <Operation>WithOverflow with this branch
1673          // unless the 0th projection (the use of the actual value of the
1674          // <Operation> is either nullptr, which means there's no use of the
1675          // actual value, or was already defined, which means it is scheduled
1676          // *AFTER* this branch).
1677          Node* const node = value->InputAt(0);
1678          Node* const result = NodeProperties::FindProjection(node, 0);
1679          if (result == nullptr || selector->IsDefined(result)) {
1680            switch (node->opcode()) {
1681              case IrOpcode::kInt32AddWithOverflow:
1682                cont->OverwriteAndNegateIfEqual(kOverflow);
1683                return VisitBinop<Int32BinopMatcher>(
1684                    selector, node, kPPC_AddWithOverflow32, kInt16Imm, cont);
1685              case IrOpcode::kInt32SubWithOverflow:
1686                cont->OverwriteAndNegateIfEqual(kOverflow);
1687                return VisitBinop<Int32BinopMatcher>(selector, node,
1688                                                     kPPC_SubWithOverflow32,
1689                                                     kInt16Imm_Negate, cont);
1690              case IrOpcode::kInt32MulWithOverflow:
1691                cont->OverwriteAndNegateIfEqual(kNotEqual);
1692                return EmitInt32MulWithOverflow(selector, node, cont);
1693#if V8_TARGET_ARCH_PPC64
1694              case IrOpcode::kInt64AddWithOverflow:
1695                cont->OverwriteAndNegateIfEqual(kOverflow);
1696                return VisitBinop<Int64BinopMatcher>(selector, node, kPPC_Add,
1697                                                     kInt16Imm, cont);
1698              case IrOpcode::kInt64SubWithOverflow:
1699                cont->OverwriteAndNegateIfEqual(kOverflow);
1700                return VisitBinop<Int64BinopMatcher>(selector, node, kPPC_Sub,
1701                                                     kInt16Imm_Negate, cont);
1702#endif
1703              default:
1704                break;
1705            }
1706          }
1707        }
1708        break;
1709      case IrOpcode::kInt32Sub:
1710        return VisitWord32Compare(selector, value, cont);
1711      case IrOpcode::kWord32And:
1712        // TODO(mbandy): opportunity for rlwinm?
1713        return VisitWordCompare(selector, value, kPPC_Tst32, cont, true,
1714                                kInt16Imm_Unsigned);
1715// TODO(mbrandy): Handle?
1716// case IrOpcode::kInt32Add:
1717// case IrOpcode::kWord32Or:
1718// case IrOpcode::kWord32Xor:
1719// case IrOpcode::kWord32Sar:
1720// case IrOpcode::kWord32Shl:
1721// case IrOpcode::kWord32Shr:
1722// case IrOpcode::kWord32Ror:
1723#if V8_TARGET_ARCH_PPC64
1724      case IrOpcode::kInt64Sub:
1725        return VisitWord64Compare(selector, value, cont);
1726      case IrOpcode::kWord64And:
1727        // TODO(mbandy): opportunity for rldic?
1728        return VisitWordCompare(selector, value, kPPC_Tst64, cont, true,
1729                                kInt16Imm_Unsigned);
1730// TODO(mbrandy): Handle?
1731// case IrOpcode::kInt64Add:
1732// case IrOpcode::kWord64Or:
1733// case IrOpcode::kWord64Xor:
1734// case IrOpcode::kWord64Sar:
1735// case IrOpcode::kWord64Shl:
1736// case IrOpcode::kWord64Shr:
1737// case IrOpcode::kWord64Ror:
1738#endif
1739      default:
1740        break;
1741    }
1742  }
1743
1744  // Branch could not be combined with a compare, emit compare against 0.
1745  PPCOperandGenerator g(selector);
1746  VisitCompare(selector, opcode, g.UseRegister(value), g.TempImmediate(0),
1747               cont);
1748}
1749
1750
1751void VisitWord32CompareZero(InstructionSelector* selector, Node* user,
1752                            Node* value, FlagsContinuation* cont) {
1753  VisitWordCompareZero(selector, user, value, kPPC_Cmp32, cont);
1754}
1755
1756
1757#if V8_TARGET_ARCH_PPC64
1758void VisitWord64CompareZero(InstructionSelector* selector, Node* user,
1759                            Node* value, FlagsContinuation* cont) {
1760  VisitWordCompareZero(selector, user, value, kPPC_Cmp64, cont);
1761}
1762#endif
1763
1764}  // namespace
1765
1766
1767void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1768                                      BasicBlock* fbranch) {
1769  FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1770  VisitWord32CompareZero(this, branch, branch->InputAt(0), &cont);
1771}
1772
1773void InstructionSelector::VisitDeoptimizeIf(Node* node) {
1774  FlagsContinuation cont = FlagsContinuation::ForDeoptimize(
1775      kNotEqual, DeoptimizeReasonOf(node->op()), node->InputAt(1));
1776  VisitWord32CompareZero(this, node, node->InputAt(0), &cont);
1777}
1778
1779void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
1780  FlagsContinuation cont = FlagsContinuation::ForDeoptimize(
1781      kEqual, DeoptimizeReasonOf(node->op()), node->InputAt(1));
1782  VisitWord32CompareZero(this, node, node->InputAt(0), &cont);
1783}
1784
1785void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1786  PPCOperandGenerator g(this);
1787  InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1788
1789  // Emit either ArchTableSwitch or ArchLookupSwitch.
1790  size_t table_space_cost = 4 + sw.value_range;
1791  size_t table_time_cost = 3;
1792  size_t lookup_space_cost = 3 + 2 * sw.case_count;
1793  size_t lookup_time_cost = sw.case_count;
1794  if (sw.case_count > 0 &&
1795      table_space_cost + 3 * table_time_cost <=
1796          lookup_space_cost + 3 * lookup_time_cost &&
1797      sw.min_value > std::numeric_limits<int32_t>::min()) {
1798    InstructionOperand index_operand = value_operand;
1799    if (sw.min_value) {
1800      index_operand = g.TempRegister();
1801      Emit(kPPC_Sub, index_operand, value_operand,
1802           g.TempImmediate(sw.min_value));
1803    }
1804    // Generate a table lookup.
1805    return EmitTableSwitch(sw, index_operand);
1806  }
1807
1808  // Generate a sequence of conditional jumps.
1809  return EmitLookupSwitch(sw, value_operand);
1810}
1811
1812
1813void InstructionSelector::VisitWord32Equal(Node* const node) {
1814  FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
1815  Int32BinopMatcher m(node);
1816  if (m.right().Is(0)) {
1817    return VisitWord32CompareZero(this, m.node(), m.left().node(), &cont);
1818  }
1819  VisitWord32Compare(this, node, &cont);
1820}
1821
1822
1823void InstructionSelector::VisitInt32LessThan(Node* node) {
1824  FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
1825  VisitWord32Compare(this, node, &cont);
1826}
1827
1828
1829void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
1830  FlagsContinuation cont =
1831      FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
1832  VisitWord32Compare(this, node, &cont);
1833}
1834
1835
1836void InstructionSelector::VisitUint32LessThan(Node* node) {
1837  FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
1838  VisitWord32Compare(this, node, &cont);
1839}
1840
1841
1842void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
1843  FlagsContinuation cont =
1844      FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
1845  VisitWord32Compare(this, node, &cont);
1846}
1847
1848
1849#if V8_TARGET_ARCH_PPC64
1850void InstructionSelector::VisitWord64Equal(Node* const node) {
1851  FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
1852  Int64BinopMatcher m(node);
1853  if (m.right().Is(0)) {
1854    return VisitWord64CompareZero(this, m.node(), m.left().node(), &cont);
1855  }
1856  VisitWord64Compare(this, node, &cont);
1857}
1858
1859
1860void InstructionSelector::VisitInt64LessThan(Node* node) {
1861  FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
1862  VisitWord64Compare(this, node, &cont);
1863}
1864
1865
1866void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
1867  FlagsContinuation cont =
1868      FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
1869  VisitWord64Compare(this, node, &cont);
1870}
1871
1872
1873void InstructionSelector::VisitUint64LessThan(Node* node) {
1874  FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
1875  VisitWord64Compare(this, node, &cont);
1876}
1877
1878
1879void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) {
1880  FlagsContinuation cont =
1881      FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
1882  VisitWord64Compare(this, node, &cont);
1883}
1884#endif
1885
1886void InstructionSelector::VisitInt32MulWithOverflow(Node* node) {
1887  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1888    FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf);
1889    return EmitInt32MulWithOverflow(this, node, &cont);
1890  }
1891  FlagsContinuation cont;
1892  EmitInt32MulWithOverflow(this, node, &cont);
1893}
1894
1895
1896void InstructionSelector::VisitFloat32Equal(Node* node) {
1897  FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
1898  VisitFloat32Compare(this, node, &cont);
1899}
1900
1901
1902void InstructionSelector::VisitFloat32LessThan(Node* node) {
1903  FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
1904  VisitFloat32Compare(this, node, &cont);
1905}
1906
1907
1908void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
1909  FlagsContinuation cont =
1910      FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
1911  VisitFloat32Compare(this, node, &cont);
1912}
1913
1914
1915void InstructionSelector::VisitFloat64Equal(Node* node) {
1916  FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
1917  VisitFloat64Compare(this, node, &cont);
1918}
1919
1920
1921void InstructionSelector::VisitFloat64LessThan(Node* node) {
1922  FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
1923  VisitFloat64Compare(this, node, &cont);
1924}
1925
1926
1927void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
1928  FlagsContinuation cont =
1929      FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
1930  VisitFloat64Compare(this, node, &cont);
1931}
1932
1933
1934void InstructionSelector::EmitPrepareArguments(
1935    ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1936    Node* node) {
1937  PPCOperandGenerator g(this);
1938
1939  // Prepare for C function call.
1940  if (descriptor->IsCFunctionCall()) {
1941    Emit(kArchPrepareCallCFunction |
1942             MiscField::encode(static_cast<int>(descriptor->ParameterCount())),
1943         0, nullptr, 0, nullptr);
1944
1945    // Poke any stack arguments.
1946    int slot = kStackFrameExtraParamSlot;
1947    for (PushParameter input : (*arguments)) {
1948      Emit(kPPC_StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
1949           g.TempImmediate(slot));
1950      ++slot;
1951    }
1952  } else {
1953    // Push any stack arguments.
1954    int num_slots = static_cast<int>(descriptor->StackParameterCount());
1955    int slot = 0;
1956    for (PushParameter input : (*arguments)) {
1957      if (slot == 0) {
1958        DCHECK(input.node());
1959        Emit(kPPC_PushFrame, g.NoOutput(), g.UseRegister(input.node()),
1960             g.TempImmediate(num_slots));
1961      } else {
1962        // Skip any alignment holes in pushed nodes.
1963        if (input.node()) {
1964          Emit(kPPC_StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
1965               g.TempImmediate(slot));
1966        }
1967      }
1968      ++slot;
1969    }
1970  }
1971}
1972
1973
1974bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
1975
1976int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; }
1977
1978void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1979  PPCOperandGenerator g(this);
1980  Emit(kPPC_DoubleExtractLowWord32, g.DefineAsRegister(node),
1981       g.UseRegister(node->InputAt(0)));
1982}
1983
1984
1985void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1986  PPCOperandGenerator g(this);
1987  Emit(kPPC_DoubleExtractHighWord32, g.DefineAsRegister(node),
1988       g.UseRegister(node->InputAt(0)));
1989}
1990
1991
1992void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1993  PPCOperandGenerator g(this);
1994  Node* left = node->InputAt(0);
1995  Node* right = node->InputAt(1);
1996  if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
1997      CanCover(node, left)) {
1998    left = left->InputAt(1);
1999    Emit(kPPC_DoubleConstruct, g.DefineAsRegister(node), g.UseRegister(left),
2000         g.UseRegister(right));
2001    return;
2002  }
2003  Emit(kPPC_DoubleInsertLowWord32, g.DefineSameAsFirst(node),
2004       g.UseRegister(left), g.UseRegister(right));
2005}
2006
2007
2008void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
2009  PPCOperandGenerator g(this);
2010  Node* left = node->InputAt(0);
2011  Node* right = node->InputAt(1);
2012  if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
2013      CanCover(node, left)) {
2014    left = left->InputAt(1);
2015    Emit(kPPC_DoubleConstruct, g.DefineAsRegister(node), g.UseRegister(right),
2016         g.UseRegister(left));
2017    return;
2018  }
2019  Emit(kPPC_DoubleInsertHighWord32, g.DefineSameAsFirst(node),
2020       g.UseRegister(left), g.UseRegister(right));
2021}
2022
2023void InstructionSelector::VisitAtomicLoad(Node* node) {
2024  LoadRepresentation load_rep = LoadRepresentationOf(node->op());
2025  PPCOperandGenerator g(this);
2026  Node* base = node->InputAt(0);
2027  Node* index = node->InputAt(1);
2028  ArchOpcode opcode = kArchNop;
2029  switch (load_rep.representation()) {
2030    case MachineRepresentation::kWord8:
2031      opcode = load_rep.IsSigned() ? kAtomicLoadInt8 : kAtomicLoadUint8;
2032      break;
2033    case MachineRepresentation::kWord16:
2034      opcode = load_rep.IsSigned() ? kAtomicLoadInt16 : kAtomicLoadUint16;
2035      break;
2036    case MachineRepresentation::kWord32:
2037      opcode = kAtomicLoadWord32;
2038      break;
2039    default:
2040      UNREACHABLE();
2041      return;
2042  }
2043  Emit(opcode | AddressingModeField::encode(kMode_MRR),
2044      g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
2045}
2046
2047void InstructionSelector::VisitAtomicStore(Node* node) {
2048  MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
2049  PPCOperandGenerator g(this);
2050  Node* base = node->InputAt(0);
2051  Node* index = node->InputAt(1);
2052  Node* value = node->InputAt(2);
2053  ArchOpcode opcode = kArchNop;
2054  switch (rep) {
2055    case MachineRepresentation::kWord8:
2056      opcode = kAtomicStoreWord8;
2057      break;
2058    case MachineRepresentation::kWord16:
2059      opcode = kAtomicStoreWord16;
2060      break;
2061    case MachineRepresentation::kWord32:
2062      opcode = kAtomicStoreWord32;
2063      break;
2064    default:
2065      UNREACHABLE();
2066      return;
2067  }
2068
2069  InstructionOperand inputs[4];
2070  size_t input_count = 0;
2071  inputs[input_count++] = g.UseUniqueRegister(base);
2072  inputs[input_count++] = g.UseUniqueRegister(index);
2073  inputs[input_count++] = g.UseUniqueRegister(value);
2074  Emit(opcode | AddressingModeField::encode(kMode_MRR),
2075      0, nullptr, input_count, inputs);
2076}
2077
2078// static
2079MachineOperatorBuilder::Flags
2080InstructionSelector::SupportedMachineOperatorFlags() {
2081  return MachineOperatorBuilder::kFloat32RoundDown |
2082         MachineOperatorBuilder::kFloat64RoundDown |
2083         MachineOperatorBuilder::kFloat32RoundUp |
2084         MachineOperatorBuilder::kFloat64RoundUp |
2085         MachineOperatorBuilder::kFloat32RoundTruncate |
2086         MachineOperatorBuilder::kFloat64RoundTruncate |
2087         MachineOperatorBuilder::kFloat64RoundTiesAway |
2088         MachineOperatorBuilder::kWord32Popcnt |
2089         MachineOperatorBuilder::kWord64Popcnt;
2090  // We omit kWord32ShiftIsSafe as s[rl]w use 0x3f as a mask rather than 0x1f.
2091}
2092
2093// static
2094MachineOperatorBuilder::AlignmentRequirements
2095InstructionSelector::AlignmentRequirements() {
2096  return MachineOperatorBuilder::AlignmentRequirements::
2097      FullUnalignedAccessSupport();
2098}
2099
2100}  // namespace compiler
2101}  // namespace internal
2102}  // namespace v8
2103