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/base/bits.h"
7#include "src/compiler/instruction-selector-impl.h"
8#include "src/compiler/node-matchers.h"
9#include "src/compiler/node-properties.h"
10
11namespace v8 {
12namespace internal {
13namespace compiler {
14
15#define TRACE_UNIMPL() \
16  PrintF("UNIMPLEMENTED instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
17
18#define TRACE() PrintF("instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
19
20
21// Adds Mips-specific methods for generating InstructionOperands.
22class Mips64OperandGenerator final : public OperandGenerator {
23 public:
24  explicit Mips64OperandGenerator(InstructionSelector* selector)
25      : OperandGenerator(selector) {}
26
27  InstructionOperand UseOperand(Node* node, InstructionCode opcode) {
28    if (CanBeImmediate(node, opcode)) {
29      return UseImmediate(node);
30    }
31    return UseRegister(node);
32  }
33
34  // Use the zero register if the node has the immediate value zero, otherwise
35  // assign a register.
36  InstructionOperand UseRegisterOrImmediateZero(Node* node) {
37    if ((IsIntegerConstant(node) && (GetIntegerConstantValue(node) == 0)) ||
38        (IsFloatConstant(node) &&
39         (bit_cast<int64_t>(GetFloatConstantValue(node)) == V8_INT64_C(0)))) {
40      return UseImmediate(node);
41    }
42    return UseRegister(node);
43  }
44
45  bool IsIntegerConstant(Node* node) {
46    return (node->opcode() == IrOpcode::kInt32Constant) ||
47           (node->opcode() == IrOpcode::kInt64Constant);
48  }
49
50  int64_t GetIntegerConstantValue(Node* node) {
51    if (node->opcode() == IrOpcode::kInt32Constant) {
52      return OpParameter<int32_t>(node);
53    }
54    DCHECK(node->opcode() == IrOpcode::kInt64Constant);
55    return OpParameter<int64_t>(node);
56  }
57
58  bool IsFloatConstant(Node* node) {
59    return (node->opcode() == IrOpcode::kFloat32Constant) ||
60           (node->opcode() == IrOpcode::kFloat64Constant);
61  }
62
63  double GetFloatConstantValue(Node* node) {
64    if (node->opcode() == IrOpcode::kFloat32Constant) {
65      return OpParameter<float>(node);
66    }
67    DCHECK_EQ(IrOpcode::kFloat64Constant, node->opcode());
68    return OpParameter<double>(node);
69  }
70
71  bool CanBeImmediate(Node* node, InstructionCode mode) {
72    return IsIntegerConstant(node) &&
73           CanBeImmediate(GetIntegerConstantValue(node), mode);
74  }
75
76  bool CanBeImmediate(int64_t value, InstructionCode opcode) {
77    switch (ArchOpcodeField::decode(opcode)) {
78      case kMips64Shl:
79      case kMips64Sar:
80      case kMips64Shr:
81        return is_uint5(value);
82      case kMips64Dshl:
83      case kMips64Dsar:
84      case kMips64Dshr:
85        return is_uint6(value);
86      case kMips64Add:
87      case kMips64And32:
88      case kMips64And:
89      case kMips64Dadd:
90      case kMips64Or32:
91      case kMips64Or:
92      case kMips64Tst:
93      case kMips64Xor:
94        return is_uint16(value);
95      case kMips64Lb:
96      case kMips64Lbu:
97      case kMips64Sb:
98      case kMips64Lh:
99      case kMips64Lhu:
100      case kMips64Sh:
101      case kMips64Lw:
102      case kMips64Sw:
103      case kMips64Ld:
104      case kMips64Sd:
105      case kMips64Lwc1:
106      case kMips64Swc1:
107      case kMips64Ldc1:
108      case kMips64Sdc1:
109      case kCheckedLoadInt8:
110      case kCheckedLoadUint8:
111      case kCheckedLoadInt16:
112      case kCheckedLoadUint16:
113      case kCheckedLoadWord32:
114      case kCheckedLoadWord64:
115      case kCheckedStoreWord8:
116      case kCheckedStoreWord16:
117      case kCheckedStoreWord32:
118      case kCheckedStoreWord64:
119      case kCheckedLoadFloat32:
120      case kCheckedLoadFloat64:
121      case kCheckedStoreFloat32:
122      case kCheckedStoreFloat64:
123        return is_int32(value);
124      default:
125        return is_int16(value);
126    }
127  }
128
129 private:
130  bool ImmediateFitsAddrMode1Instruction(int32_t imm) const {
131    TRACE_UNIMPL();
132    return false;
133  }
134};
135
136
137static void VisitRR(InstructionSelector* selector, ArchOpcode opcode,
138                    Node* node) {
139  Mips64OperandGenerator g(selector);
140  selector->Emit(opcode, g.DefineAsRegister(node),
141                 g.UseRegister(node->InputAt(0)));
142}
143
144
145static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
146                     Node* node) {
147  Mips64OperandGenerator g(selector);
148  selector->Emit(opcode, g.DefineAsRegister(node),
149                 g.UseRegister(node->InputAt(0)),
150                 g.UseRegister(node->InputAt(1)));
151}
152
153
154static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode,
155                     Node* node) {
156  Mips64OperandGenerator g(selector);
157  selector->Emit(opcode, g.DefineAsRegister(node),
158                 g.UseRegister(node->InputAt(0)),
159                 g.UseOperand(node->InputAt(1), opcode));
160}
161
162struct ExtendingLoadMatcher {
163  ExtendingLoadMatcher(Node* node, InstructionSelector* selector)
164      : matches_(false), selector_(selector), base_(nullptr), immediate_(0) {
165    Initialize(node);
166  }
167
168  bool Matches() const { return matches_; }
169
170  Node* base() const {
171    DCHECK(Matches());
172    return base_;
173  }
174  int64_t immediate() const {
175    DCHECK(Matches());
176    return immediate_;
177  }
178  ArchOpcode opcode() const {
179    DCHECK(Matches());
180    return opcode_;
181  }
182
183 private:
184  bool matches_;
185  InstructionSelector* selector_;
186  Node* base_;
187  int64_t immediate_;
188  ArchOpcode opcode_;
189
190  void Initialize(Node* node) {
191    Int64BinopMatcher m(node);
192    // When loading a 64-bit value and shifting by 32, we should
193    // just load and sign-extend the interesting 4 bytes instead.
194    // This happens, for example, when we're loading and untagging SMIs.
195    DCHECK(m.IsWord64Sar());
196    if (m.left().IsLoad() && m.right().Is(32) &&
197        selector_->CanCover(m.node(), m.left().node())) {
198      MachineRepresentation rep =
199          LoadRepresentationOf(m.left().node()->op()).representation();
200      DCHECK(ElementSizeLog2Of(rep) == 3);
201      if (rep != MachineRepresentation::kTaggedSigned &&
202          rep != MachineRepresentation::kTaggedPointer &&
203          rep != MachineRepresentation::kTagged &&
204          rep != MachineRepresentation::kWord64) {
205        return;
206      }
207
208      Mips64OperandGenerator g(selector_);
209      Node* load = m.left().node();
210      Node* offset = load->InputAt(1);
211      base_ = load->InputAt(0);
212      opcode_ = kMips64Lw;
213      if (g.CanBeImmediate(offset, opcode_)) {
214#if defined(V8_TARGET_LITTLE_ENDIAN)
215        immediate_ = g.GetIntegerConstantValue(offset) + 4;
216#elif defined(V8_TARGET_BIG_ENDIAN)
217        immediate_ = g.GetIntegerConstantValue(offset);
218#endif
219        matches_ = g.CanBeImmediate(immediate_, kMips64Lw);
220      }
221    }
222  }
223};
224
225bool TryEmitExtendingLoad(InstructionSelector* selector, Node* node,
226                          Node* output_node) {
227  ExtendingLoadMatcher m(node, selector);
228  Mips64OperandGenerator g(selector);
229  if (m.Matches()) {
230    InstructionOperand inputs[2];
231    inputs[0] = g.UseRegister(m.base());
232    InstructionCode opcode =
233        m.opcode() | AddressingModeField::encode(kMode_MRI);
234    DCHECK(is_int32(m.immediate()));
235    inputs[1] = g.TempImmediate(static_cast<int32_t>(m.immediate()));
236    InstructionOperand outputs[] = {g.DefineAsRegister(output_node)};
237    selector->Emit(opcode, arraysize(outputs), outputs, arraysize(inputs),
238                   inputs);
239    return true;
240  }
241  return false;
242}
243
244bool TryMatchImmediate(InstructionSelector* selector,
245                       InstructionCode* opcode_return, Node* node,
246                       size_t* input_count_return, InstructionOperand* inputs) {
247  Mips64OperandGenerator g(selector);
248  if (g.CanBeImmediate(node, *opcode_return)) {
249    *opcode_return |= AddressingModeField::encode(kMode_MRI);
250    inputs[0] = g.UseImmediate(node);
251    *input_count_return = 1;
252    return true;
253  }
254  return false;
255}
256
257static void VisitBinop(InstructionSelector* selector, Node* node,
258                       InstructionCode opcode, bool has_reverse_opcode,
259                       InstructionCode reverse_opcode,
260                       FlagsContinuation* cont) {
261  Mips64OperandGenerator g(selector);
262  Int32BinopMatcher m(node);
263  InstructionOperand inputs[4];
264  size_t input_count = 0;
265  InstructionOperand outputs[2];
266  size_t output_count = 0;
267
268  if (TryMatchImmediate(selector, &opcode, m.right().node(), &input_count,
269                        &inputs[1])) {
270    inputs[0] = g.UseRegister(m.left().node());
271    input_count++;
272  } else if (has_reverse_opcode &&
273             TryMatchImmediate(selector, &reverse_opcode, m.left().node(),
274                               &input_count, &inputs[1])) {
275    inputs[0] = g.UseRegister(m.right().node());
276    opcode = reverse_opcode;
277    input_count++;
278  } else {
279    inputs[input_count++] = g.UseRegister(m.left().node());
280    inputs[input_count++] = g.UseOperand(m.right().node(), opcode);
281  }
282
283  if (cont->IsBranch()) {
284    inputs[input_count++] = g.Label(cont->true_block());
285    inputs[input_count++] = g.Label(cont->false_block());
286  } else if (cont->IsTrap()) {
287    inputs[input_count++] = g.TempImmediate(cont->trap_id());
288  }
289
290  if (cont->IsDeoptimize()) {
291    // If we can deoptimize as a result of the binop, we need to make sure that
292    // the deopt inputs are not overwritten by the binop result. One way
293    // to achieve that is to declare the output register as same-as-first.
294    outputs[output_count++] = g.DefineSameAsFirst(node);
295  } else {
296    outputs[output_count++] = g.DefineAsRegister(node);
297  }
298  if (cont->IsSet()) {
299    outputs[output_count++] = g.DefineAsRegister(cont->result());
300  }
301
302  DCHECK_NE(0u, input_count);
303  DCHECK_NE(0u, output_count);
304  DCHECK_GE(arraysize(inputs), input_count);
305  DCHECK_GE(arraysize(outputs), output_count);
306
307  opcode = cont->Encode(opcode);
308  if (cont->IsDeoptimize()) {
309    selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
310                             cont->kind(), cont->reason(), cont->frame_state());
311  } else {
312    selector->Emit(opcode, output_count, outputs, input_count, inputs);
313  }
314}
315
316static void VisitBinop(InstructionSelector* selector, Node* node,
317                       InstructionCode opcode, bool has_reverse_opcode,
318                       InstructionCode reverse_opcode) {
319  FlagsContinuation cont;
320  VisitBinop(selector, node, opcode, has_reverse_opcode, reverse_opcode, &cont);
321}
322
323static void VisitBinop(InstructionSelector* selector, Node* node,
324                       InstructionCode opcode, FlagsContinuation* cont) {
325  VisitBinop(selector, node, opcode, false, kArchNop, cont);
326}
327
328static void VisitBinop(InstructionSelector* selector, Node* node,
329                       InstructionCode opcode) {
330  VisitBinop(selector, node, opcode, false, kArchNop);
331}
332
333void EmitLoad(InstructionSelector* selector, Node* node, InstructionCode opcode,
334              Node* output = nullptr) {
335  Mips64OperandGenerator g(selector);
336  Node* base = node->InputAt(0);
337  Node* index = node->InputAt(1);
338
339  if (g.CanBeImmediate(index, opcode)) {
340    selector->Emit(opcode | AddressingModeField::encode(kMode_MRI),
341                   g.DefineAsRegister(output == nullptr ? node : output),
342                   g.UseRegister(base), g.UseImmediate(index));
343  } else {
344    InstructionOperand addr_reg = g.TempRegister();
345    selector->Emit(kMips64Dadd | AddressingModeField::encode(kMode_None),
346                   addr_reg, g.UseRegister(index), g.UseRegister(base));
347    // Emit desired load opcode, using temp addr_reg.
348    selector->Emit(opcode | AddressingModeField::encode(kMode_MRI),
349                   g.DefineAsRegister(output == nullptr ? node : output),
350                   addr_reg, g.TempImmediate(0));
351  }
352}
353
354void InstructionSelector::VisitLoad(Node* node) {
355  LoadRepresentation load_rep = LoadRepresentationOf(node->op());
356
357  ArchOpcode opcode = kArchNop;
358  switch (load_rep.representation()) {
359    case MachineRepresentation::kFloat32:
360      opcode = kMips64Lwc1;
361      break;
362    case MachineRepresentation::kFloat64:
363      opcode = kMips64Ldc1;
364      break;
365    case MachineRepresentation::kBit:  // Fall through.
366    case MachineRepresentation::kWord8:
367      opcode = load_rep.IsUnsigned() ? kMips64Lbu : kMips64Lb;
368      break;
369    case MachineRepresentation::kWord16:
370      opcode = load_rep.IsUnsigned() ? kMips64Lhu : kMips64Lh;
371      break;
372    case MachineRepresentation::kWord32:
373      opcode = load_rep.IsUnsigned() ? kMips64Lwu : kMips64Lw;
374      break;
375    case MachineRepresentation::kTaggedSigned:   // Fall through.
376    case MachineRepresentation::kTaggedPointer:  // Fall through.
377    case MachineRepresentation::kTagged:  // Fall through.
378    case MachineRepresentation::kWord64:
379      opcode = kMips64Ld;
380      break;
381    case MachineRepresentation::kSimd128:  // Fall through.
382    case MachineRepresentation::kSimd1x4:  // Fall through.
383    case MachineRepresentation::kSimd1x8:  // Fall through.
384    case MachineRepresentation::kSimd1x16:  // Fall through.
385    case MachineRepresentation::kNone:
386      UNREACHABLE();
387      return;
388  }
389
390  EmitLoad(this, node, opcode);
391}
392
393void InstructionSelector::VisitProtectedLoad(Node* node) {
394  // TODO(eholk)
395  UNIMPLEMENTED();
396}
397
398void InstructionSelector::VisitStore(Node* node) {
399  Mips64OperandGenerator g(this);
400  Node* base = node->InputAt(0);
401  Node* index = node->InputAt(1);
402  Node* value = node->InputAt(2);
403
404  StoreRepresentation store_rep = StoreRepresentationOf(node->op());
405  WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
406  MachineRepresentation rep = store_rep.representation();
407
408  // TODO(mips): I guess this could be done in a better way.
409  if (write_barrier_kind != kNoWriteBarrier) {
410    DCHECK(CanBeTaggedPointer(rep));
411    InstructionOperand inputs[3];
412    size_t input_count = 0;
413    inputs[input_count++] = g.UseUniqueRegister(base);
414    inputs[input_count++] = g.UseUniqueRegister(index);
415    inputs[input_count++] = g.UseUniqueRegister(value);
416    RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
417    switch (write_barrier_kind) {
418      case kNoWriteBarrier:
419        UNREACHABLE();
420        break;
421      case kMapWriteBarrier:
422        record_write_mode = RecordWriteMode::kValueIsMap;
423        break;
424      case kPointerWriteBarrier:
425        record_write_mode = RecordWriteMode::kValueIsPointer;
426        break;
427      case kFullWriteBarrier:
428        record_write_mode = RecordWriteMode::kValueIsAny;
429        break;
430    }
431    InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
432    size_t const temp_count = arraysize(temps);
433    InstructionCode code = kArchStoreWithWriteBarrier;
434    code |= MiscField::encode(static_cast<int>(record_write_mode));
435    Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
436  } else {
437    ArchOpcode opcode = kArchNop;
438    switch (rep) {
439      case MachineRepresentation::kFloat32:
440        opcode = kMips64Swc1;
441        break;
442      case MachineRepresentation::kFloat64:
443        opcode = kMips64Sdc1;
444        break;
445      case MachineRepresentation::kBit:  // Fall through.
446      case MachineRepresentation::kWord8:
447        opcode = kMips64Sb;
448        break;
449      case MachineRepresentation::kWord16:
450        opcode = kMips64Sh;
451        break;
452      case MachineRepresentation::kWord32:
453        opcode = kMips64Sw;
454        break;
455      case MachineRepresentation::kTaggedSigned:   // Fall through.
456      case MachineRepresentation::kTaggedPointer:  // Fall through.
457      case MachineRepresentation::kTagged:  // Fall through.
458      case MachineRepresentation::kWord64:
459        opcode = kMips64Sd;
460        break;
461      case MachineRepresentation::kSimd128:  // Fall through.
462      case MachineRepresentation::kSimd1x4:  // Fall through.
463      case MachineRepresentation::kSimd1x8:  // Fall through.
464      case MachineRepresentation::kSimd1x16:  // Fall through.
465      case MachineRepresentation::kNone:
466        UNREACHABLE();
467        return;
468    }
469
470    if (g.CanBeImmediate(index, opcode)) {
471      Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
472           g.UseRegister(base), g.UseImmediate(index),
473           g.UseRegisterOrImmediateZero(value));
474    } else {
475      InstructionOperand addr_reg = g.TempRegister();
476      Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
477           g.UseRegister(index), g.UseRegister(base));
478      // Emit desired store opcode, using temp addr_reg.
479      Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
480           addr_reg, g.TempImmediate(0), g.UseRegisterOrImmediateZero(value));
481    }
482  }
483}
484
485void InstructionSelector::VisitProtectedStore(Node* node) {
486  // TODO(eholk)
487  UNIMPLEMENTED();
488}
489
490void InstructionSelector::VisitWord32And(Node* node) {
491  Mips64OperandGenerator g(this);
492  Int32BinopMatcher m(node);
493  if (m.left().IsWord32Shr() && CanCover(node, m.left().node()) &&
494      m.right().HasValue()) {
495    uint32_t mask = m.right().Value();
496    uint32_t mask_width = base::bits::CountPopulation32(mask);
497    uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
498    if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
499      // The mask must be contiguous, and occupy the least-significant bits.
500      DCHECK_EQ(0u, base::bits::CountTrailingZeros32(mask));
501
502      // Select Ext for And(Shr(x, imm), mask) where the mask is in the least
503      // significant bits.
504      Int32BinopMatcher mleft(m.left().node());
505      if (mleft.right().HasValue()) {
506        // Any shift value can match; int32 shifts use `value % 32`.
507        uint32_t lsb = mleft.right().Value() & 0x1f;
508
509        // Ext cannot extract bits past the register size, however since
510        // shifting the original value would have introduced some zeros we can
511        // still use Ext with a smaller mask and the remaining bits will be
512        // zeros.
513        if (lsb + mask_width > 32) mask_width = 32 - lsb;
514
515        Emit(kMips64Ext, g.DefineAsRegister(node),
516             g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
517             g.TempImmediate(mask_width));
518        return;
519      }
520      // Other cases fall through to the normal And operation.
521    }
522  }
523  if (m.right().HasValue()) {
524    uint32_t mask = m.right().Value();
525    uint32_t shift = base::bits::CountPopulation32(~mask);
526    uint32_t msb = base::bits::CountLeadingZeros32(~mask);
527    if (shift != 0 && shift != 32 && msb + shift == 32) {
528      // Insert zeros for (x >> K) << K => x & ~(2^K - 1) expression reduction
529      // and remove constant loading of inverted mask.
530      Emit(kMips64Ins, g.DefineSameAsFirst(node),
531           g.UseRegister(m.left().node()), g.TempImmediate(0),
532           g.TempImmediate(shift));
533      return;
534    }
535  }
536  VisitBinop(this, node, kMips64And32, true, kMips64And32);
537}
538
539
540void InstructionSelector::VisitWord64And(Node* node) {
541  Mips64OperandGenerator g(this);
542  Int64BinopMatcher m(node);
543  if (m.left().IsWord64Shr() && CanCover(node, m.left().node()) &&
544      m.right().HasValue()) {
545    uint64_t mask = m.right().Value();
546    uint32_t mask_width = base::bits::CountPopulation64(mask);
547    uint32_t mask_msb = base::bits::CountLeadingZeros64(mask);
548    if ((mask_width != 0) && (mask_msb + mask_width == 64)) {
549      // The mask must be contiguous, and occupy the least-significant bits.
550      DCHECK_EQ(0u, base::bits::CountTrailingZeros64(mask));
551
552      // Select Dext for And(Shr(x, imm), mask) where the mask is in the least
553      // significant bits.
554      Int64BinopMatcher mleft(m.left().node());
555      if (mleft.right().HasValue()) {
556        // Any shift value can match; int64 shifts use `value % 64`.
557        uint32_t lsb = static_cast<uint32_t>(mleft.right().Value() & 0x3f);
558
559        // Dext cannot extract bits past the register size, however since
560        // shifting the original value would have introduced some zeros we can
561        // still use Dext with a smaller mask and the remaining bits will be
562        // zeros.
563        if (lsb + mask_width > 64) mask_width = 64 - lsb;
564
565        if (lsb == 0 && mask_width == 64) {
566          Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(mleft.left().node()));
567        } else {
568          Emit(kMips64Dext, g.DefineAsRegister(node),
569               g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
570               g.TempImmediate(static_cast<int32_t>(mask_width)));
571        }
572        return;
573      }
574      // Other cases fall through to the normal And operation.
575    }
576  }
577  if (m.right().HasValue()) {
578    uint64_t mask = m.right().Value();
579    uint32_t shift = base::bits::CountPopulation64(~mask);
580    uint32_t msb = base::bits::CountLeadingZeros64(~mask);
581    if (shift != 0 && shift < 32 && msb + shift == 64) {
582      // Insert zeros for (x >> K) << K => x & ~(2^K - 1) expression reduction
583      // and remove constant loading of inverted mask. Dins cannot insert bits
584      // past word size, so shifts smaller than 32 are covered.
585      Emit(kMips64Dins, g.DefineSameAsFirst(node),
586           g.UseRegister(m.left().node()), g.TempImmediate(0),
587           g.TempImmediate(shift));
588      return;
589    }
590  }
591  VisitBinop(this, node, kMips64And, true, kMips64And);
592}
593
594
595void InstructionSelector::VisitWord32Or(Node* node) {
596  VisitBinop(this, node, kMips64Or32, true, kMips64Or32);
597}
598
599
600void InstructionSelector::VisitWord64Or(Node* node) {
601  VisitBinop(this, node, kMips64Or, true, kMips64Or);
602}
603
604
605void InstructionSelector::VisitWord32Xor(Node* node) {
606  Int32BinopMatcher m(node);
607  if (m.left().IsWord32Or() && CanCover(node, m.left().node()) &&
608      m.right().Is(-1)) {
609    Int32BinopMatcher mleft(m.left().node());
610    if (!mleft.right().HasValue()) {
611      Mips64OperandGenerator g(this);
612      Emit(kMips64Nor32, g.DefineAsRegister(node),
613           g.UseRegister(mleft.left().node()),
614           g.UseRegister(mleft.right().node()));
615      return;
616    }
617  }
618  if (m.right().Is(-1)) {
619    // Use Nor for bit negation and eliminate constant loading for xori.
620    Mips64OperandGenerator g(this);
621    Emit(kMips64Nor32, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
622         g.TempImmediate(0));
623    return;
624  }
625  VisitBinop(this, node, kMips64Xor32, true, kMips64Xor32);
626}
627
628
629void InstructionSelector::VisitWord64Xor(Node* node) {
630  Int64BinopMatcher m(node);
631  if (m.left().IsWord64Or() && CanCover(node, m.left().node()) &&
632      m.right().Is(-1)) {
633    Int64BinopMatcher mleft(m.left().node());
634    if (!mleft.right().HasValue()) {
635      Mips64OperandGenerator g(this);
636      Emit(kMips64Nor, g.DefineAsRegister(node),
637           g.UseRegister(mleft.left().node()),
638           g.UseRegister(mleft.right().node()));
639      return;
640    }
641  }
642  if (m.right().Is(-1)) {
643    // Use Nor for bit negation and eliminate constant loading for xori.
644    Mips64OperandGenerator g(this);
645    Emit(kMips64Nor, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
646         g.TempImmediate(0));
647    return;
648  }
649  VisitBinop(this, node, kMips64Xor, true, kMips64Xor);
650}
651
652
653void InstructionSelector::VisitWord32Shl(Node* node) {
654  Int32BinopMatcher m(node);
655  if (m.left().IsWord32And() && CanCover(node, m.left().node()) &&
656      m.right().IsInRange(1, 31)) {
657    Mips64OperandGenerator g(this);
658    Int32BinopMatcher mleft(m.left().node());
659    // Match Word32Shl(Word32And(x, mask), imm) to Shl where the mask is
660    // contiguous, and the shift immediate non-zero.
661    if (mleft.right().HasValue()) {
662      uint32_t mask = mleft.right().Value();
663      uint32_t mask_width = base::bits::CountPopulation32(mask);
664      uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
665      if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
666        uint32_t shift = m.right().Value();
667        DCHECK_EQ(0u, base::bits::CountTrailingZeros32(mask));
668        DCHECK_NE(0u, shift);
669        if ((shift + mask_width) >= 32) {
670          // If the mask is contiguous and reaches or extends beyond the top
671          // bit, only the shift is needed.
672          Emit(kMips64Shl, g.DefineAsRegister(node),
673               g.UseRegister(mleft.left().node()),
674               g.UseImmediate(m.right().node()));
675          return;
676        }
677      }
678    }
679  }
680  VisitRRO(this, kMips64Shl, node);
681}
682
683
684void InstructionSelector::VisitWord32Shr(Node* node) {
685  Int32BinopMatcher m(node);
686  if (m.left().IsWord32And() && m.right().HasValue()) {
687    uint32_t lsb = m.right().Value() & 0x1f;
688    Int32BinopMatcher mleft(m.left().node());
689    if (mleft.right().HasValue()) {
690      // Select Ext for Shr(And(x, mask), imm) where the result of the mask is
691      // shifted into the least-significant bits.
692      uint32_t mask = (mleft.right().Value() >> lsb) << lsb;
693      unsigned mask_width = base::bits::CountPopulation32(mask);
694      unsigned mask_msb = base::bits::CountLeadingZeros32(mask);
695      if ((mask_msb + mask_width + lsb) == 32) {
696        Mips64OperandGenerator g(this);
697        DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(mask));
698        Emit(kMips64Ext, g.DefineAsRegister(node),
699             g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
700             g.TempImmediate(mask_width));
701        return;
702      }
703    }
704  }
705  VisitRRO(this, kMips64Shr, node);
706}
707
708
709void InstructionSelector::VisitWord32Sar(Node* node) {
710  Int32BinopMatcher m(node);
711  if (m.left().IsWord32Shl() && CanCover(node, m.left().node())) {
712    Int32BinopMatcher mleft(m.left().node());
713    if (m.right().HasValue() && mleft.right().HasValue()) {
714      Mips64OperandGenerator g(this);
715      uint32_t sar = m.right().Value();
716      uint32_t shl = mleft.right().Value();
717      if ((sar == shl) && (sar == 16)) {
718        Emit(kMips64Seh, g.DefineAsRegister(node),
719             g.UseRegister(mleft.left().node()));
720        return;
721      } else if ((sar == shl) && (sar == 24)) {
722        Emit(kMips64Seb, g.DefineAsRegister(node),
723             g.UseRegister(mleft.left().node()));
724        return;
725      } else if ((sar == shl) && (sar == 32)) {
726        Emit(kMips64Shl, g.DefineAsRegister(node),
727             g.UseRegister(mleft.left().node()), g.TempImmediate(0));
728        return;
729      }
730    }
731  }
732  VisitRRO(this, kMips64Sar, node);
733}
734
735
736void InstructionSelector::VisitWord64Shl(Node* node) {
737  Mips64OperandGenerator g(this);
738  Int64BinopMatcher m(node);
739  if ((m.left().IsChangeInt32ToInt64() || m.left().IsChangeUint32ToUint64()) &&
740      m.right().IsInRange(32, 63) && CanCover(node, m.left().node())) {
741    // There's no need to sign/zero-extend to 64-bit if we shift out the upper
742    // 32 bits anyway.
743    Emit(kMips64Dshl, g.DefineSameAsFirst(node),
744         g.UseRegister(m.left().node()->InputAt(0)),
745         g.UseImmediate(m.right().node()));
746    return;
747  }
748  if (m.left().IsWord64And() && CanCover(node, m.left().node()) &&
749      m.right().IsInRange(1, 63)) {
750    // Match Word64Shl(Word64And(x, mask), imm) to Dshl where the mask is
751    // contiguous, and the shift immediate non-zero.
752    Int64BinopMatcher mleft(m.left().node());
753    if (mleft.right().HasValue()) {
754      uint64_t mask = mleft.right().Value();
755      uint32_t mask_width = base::bits::CountPopulation64(mask);
756      uint32_t mask_msb = base::bits::CountLeadingZeros64(mask);
757      if ((mask_width != 0) && (mask_msb + mask_width == 64)) {
758        uint64_t shift = m.right().Value();
759        DCHECK_EQ(0u, base::bits::CountTrailingZeros64(mask));
760        DCHECK_NE(0u, shift);
761
762        if ((shift + mask_width) >= 64) {
763          // If the mask is contiguous and reaches or extends beyond the top
764          // bit, only the shift is needed.
765          Emit(kMips64Dshl, g.DefineAsRegister(node),
766               g.UseRegister(mleft.left().node()),
767               g.UseImmediate(m.right().node()));
768          return;
769        }
770      }
771    }
772  }
773  VisitRRO(this, kMips64Dshl, node);
774}
775
776
777void InstructionSelector::VisitWord64Shr(Node* node) {
778  Int64BinopMatcher m(node);
779  if (m.left().IsWord64And() && m.right().HasValue()) {
780    uint32_t lsb = m.right().Value() & 0x3f;
781    Int64BinopMatcher mleft(m.left().node());
782    if (mleft.right().HasValue()) {
783      // Select Dext for Shr(And(x, mask), imm) where the result of the mask is
784      // shifted into the least-significant bits.
785      uint64_t mask = (mleft.right().Value() >> lsb) << lsb;
786      unsigned mask_width = base::bits::CountPopulation64(mask);
787      unsigned mask_msb = base::bits::CountLeadingZeros64(mask);
788      if ((mask_msb + mask_width + lsb) == 64) {
789        Mips64OperandGenerator g(this);
790        DCHECK_EQ(lsb, base::bits::CountTrailingZeros64(mask));
791        Emit(kMips64Dext, g.DefineAsRegister(node),
792             g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
793             g.TempImmediate(mask_width));
794        return;
795      }
796    }
797  }
798  VisitRRO(this, kMips64Dshr, node);
799}
800
801
802void InstructionSelector::VisitWord64Sar(Node* node) {
803  if (TryEmitExtendingLoad(this, node, node)) return;
804  VisitRRO(this, kMips64Dsar, node);
805}
806
807
808void InstructionSelector::VisitWord32Ror(Node* node) {
809  VisitRRO(this, kMips64Ror, node);
810}
811
812
813void InstructionSelector::VisitWord32Clz(Node* node) {
814  VisitRR(this, kMips64Clz, node);
815}
816
817
818void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
819
820
821void InstructionSelector::VisitWord64ReverseBits(Node* node) { UNREACHABLE(); }
822
823void InstructionSelector::VisitWord64ReverseBytes(Node* node) {
824  Mips64OperandGenerator g(this);
825  Emit(kMips64ByteSwap64, g.DefineAsRegister(node),
826       g.UseRegister(node->InputAt(0)));
827}
828
829void InstructionSelector::VisitWord32ReverseBytes(Node* node) {
830  Mips64OperandGenerator g(this);
831  Emit(kMips64ByteSwap32, g.DefineAsRegister(node),
832       g.UseRegister(node->InputAt(0)));
833}
834
835void InstructionSelector::VisitWord32Ctz(Node* node) {
836  Mips64OperandGenerator g(this);
837  Emit(kMips64Ctz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
838}
839
840
841void InstructionSelector::VisitWord64Ctz(Node* node) {
842  Mips64OperandGenerator g(this);
843  Emit(kMips64Dctz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
844}
845
846
847void InstructionSelector::VisitWord32Popcnt(Node* node) {
848  Mips64OperandGenerator g(this);
849  Emit(kMips64Popcnt, g.DefineAsRegister(node),
850       g.UseRegister(node->InputAt(0)));
851}
852
853
854void InstructionSelector::VisitWord64Popcnt(Node* node) {
855  Mips64OperandGenerator g(this);
856  Emit(kMips64Dpopcnt, g.DefineAsRegister(node),
857       g.UseRegister(node->InputAt(0)));
858}
859
860
861void InstructionSelector::VisitWord64Ror(Node* node) {
862  VisitRRO(this, kMips64Dror, node);
863}
864
865
866void InstructionSelector::VisitWord64Clz(Node* node) {
867  VisitRR(this, kMips64Dclz, node);
868}
869
870
871void InstructionSelector::VisitInt32Add(Node* node) {
872  Mips64OperandGenerator g(this);
873  Int32BinopMatcher m(node);
874
875  // Select Lsa for (left + (left_of_right << imm)).
876  if (m.right().opcode() == IrOpcode::kWord32Shl &&
877      CanCover(node, m.left().node()) && CanCover(node, m.right().node())) {
878    Int32BinopMatcher mright(m.right().node());
879    if (mright.right().HasValue() && !m.left().HasValue()) {
880      int32_t shift_value = static_cast<int32_t>(mright.right().Value());
881      Emit(kMips64Lsa, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
882           g.UseRegister(mright.left().node()), g.TempImmediate(shift_value));
883      return;
884    }
885  }
886
887  // Select Lsa for ((left_of_left << imm) + right).
888  if (m.left().opcode() == IrOpcode::kWord32Shl &&
889      CanCover(node, m.right().node()) && CanCover(node, m.left().node())) {
890    Int32BinopMatcher mleft(m.left().node());
891    if (mleft.right().HasValue() && !m.right().HasValue()) {
892      int32_t shift_value = static_cast<int32_t>(mleft.right().Value());
893      Emit(kMips64Lsa, g.DefineAsRegister(node),
894           g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
895           g.TempImmediate(shift_value));
896      return;
897    }
898  }
899  VisitBinop(this, node, kMips64Add, true, kMips64Add);
900}
901
902
903void InstructionSelector::VisitInt64Add(Node* node) {
904  Mips64OperandGenerator g(this);
905  Int64BinopMatcher m(node);
906
907  // Select Dlsa for (left + (left_of_right << imm)).
908  if (m.right().opcode() == IrOpcode::kWord64Shl &&
909      CanCover(node, m.left().node()) && CanCover(node, m.right().node())) {
910    Int64BinopMatcher mright(m.right().node());
911    if (mright.right().HasValue() && !m.left().HasValue()) {
912      int32_t shift_value = static_cast<int32_t>(mright.right().Value());
913      Emit(kMips64Dlsa, g.DefineAsRegister(node),
914           g.UseRegister(m.left().node()), g.UseRegister(mright.left().node()),
915           g.TempImmediate(shift_value));
916      return;
917    }
918  }
919
920  // Select Dlsa for ((left_of_left << imm) + right).
921  if (m.left().opcode() == IrOpcode::kWord64Shl &&
922      CanCover(node, m.right().node()) && CanCover(node, m.left().node())) {
923    Int64BinopMatcher mleft(m.left().node());
924    if (mleft.right().HasValue() && !m.right().HasValue()) {
925      int32_t shift_value = static_cast<int32_t>(mleft.right().Value());
926      Emit(kMips64Dlsa, g.DefineAsRegister(node),
927           g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
928           g.TempImmediate(shift_value));
929      return;
930    }
931  }
932
933  VisitBinop(this, node, kMips64Dadd, true, kMips64Dadd);
934}
935
936
937void InstructionSelector::VisitInt32Sub(Node* node) {
938  VisitBinop(this, node, kMips64Sub);
939}
940
941
942void InstructionSelector::VisitInt64Sub(Node* node) {
943  VisitBinop(this, node, kMips64Dsub);
944}
945
946
947void InstructionSelector::VisitInt32Mul(Node* node) {
948  Mips64OperandGenerator g(this);
949  Int32BinopMatcher m(node);
950  if (m.right().HasValue() && m.right().Value() > 0) {
951    int32_t value = m.right().Value();
952    if (base::bits::IsPowerOfTwo32(value)) {
953      Emit(kMips64Shl | AddressingModeField::encode(kMode_None),
954           g.DefineAsRegister(node), g.UseRegister(m.left().node()),
955           g.TempImmediate(WhichPowerOf2(value)));
956      return;
957    }
958    if (base::bits::IsPowerOfTwo32(value - 1)) {
959      Emit(kMips64Lsa, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
960           g.UseRegister(m.left().node()),
961           g.TempImmediate(WhichPowerOf2(value - 1)));
962      return;
963    }
964    if (base::bits::IsPowerOfTwo32(value + 1)) {
965      InstructionOperand temp = g.TempRegister();
966      Emit(kMips64Shl | AddressingModeField::encode(kMode_None), temp,
967           g.UseRegister(m.left().node()),
968           g.TempImmediate(WhichPowerOf2(value + 1)));
969      Emit(kMips64Sub | AddressingModeField::encode(kMode_None),
970           g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
971      return;
972    }
973  }
974  Node* left = node->InputAt(0);
975  Node* right = node->InputAt(1);
976  if (CanCover(node, left) && CanCover(node, right)) {
977    if (left->opcode() == IrOpcode::kWord64Sar &&
978        right->opcode() == IrOpcode::kWord64Sar) {
979      Int64BinopMatcher leftInput(left), rightInput(right);
980      if (leftInput.right().Is(32) && rightInput.right().Is(32)) {
981        // Combine untagging shifts with Dmul high.
982        Emit(kMips64DMulHigh, g.DefineSameAsFirst(node),
983             g.UseRegister(leftInput.left().node()),
984             g.UseRegister(rightInput.left().node()));
985        return;
986      }
987    }
988  }
989  VisitRRR(this, kMips64Mul, node);
990}
991
992
993void InstructionSelector::VisitInt32MulHigh(Node* node) {
994  VisitRRR(this, kMips64MulHigh, node);
995}
996
997
998void InstructionSelector::VisitUint32MulHigh(Node* node) {
999  VisitRRR(this, kMips64MulHighU, node);
1000}
1001
1002
1003void InstructionSelector::VisitInt64Mul(Node* node) {
1004  Mips64OperandGenerator g(this);
1005  Int64BinopMatcher m(node);
1006  // TODO(dusmil): Add optimization for shifts larger than 32.
1007  if (m.right().HasValue() && m.right().Value() > 0) {
1008    int32_t value = static_cast<int32_t>(m.right().Value());
1009    if (base::bits::IsPowerOfTwo32(value)) {
1010      Emit(kMips64Dshl | AddressingModeField::encode(kMode_None),
1011           g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1012           g.TempImmediate(WhichPowerOf2(value)));
1013      return;
1014    }
1015    if (base::bits::IsPowerOfTwo32(value - 1)) {
1016      // Dlsa macro will handle the shifting value out of bound cases.
1017      Emit(kMips64Dlsa, g.DefineAsRegister(node),
1018           g.UseRegister(m.left().node()), g.UseRegister(m.left().node()),
1019           g.TempImmediate(WhichPowerOf2(value - 1)));
1020      return;
1021    }
1022    if (base::bits::IsPowerOfTwo32(value + 1)) {
1023      InstructionOperand temp = g.TempRegister();
1024      Emit(kMips64Dshl | AddressingModeField::encode(kMode_None), temp,
1025           g.UseRegister(m.left().node()),
1026           g.TempImmediate(WhichPowerOf2(value + 1)));
1027      Emit(kMips64Dsub | AddressingModeField::encode(kMode_None),
1028           g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
1029      return;
1030    }
1031  }
1032  Emit(kMips64Dmul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1033       g.UseRegister(m.right().node()));
1034}
1035
1036
1037void InstructionSelector::VisitInt32Div(Node* node) {
1038  Mips64OperandGenerator g(this);
1039  Int32BinopMatcher m(node);
1040  Node* left = node->InputAt(0);
1041  Node* right = node->InputAt(1);
1042  if (CanCover(node, left) && CanCover(node, right)) {
1043    if (left->opcode() == IrOpcode::kWord64Sar &&
1044        right->opcode() == IrOpcode::kWord64Sar) {
1045      Int64BinopMatcher rightInput(right), leftInput(left);
1046      if (rightInput.right().Is(32) && leftInput.right().Is(32)) {
1047        // Combine both shifted operands with Ddiv.
1048        Emit(kMips64Ddiv, g.DefineSameAsFirst(node),
1049             g.UseRegister(leftInput.left().node()),
1050             g.UseRegister(rightInput.left().node()));
1051        return;
1052      }
1053    }
1054  }
1055  Emit(kMips64Div, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1056       g.UseRegister(m.right().node()));
1057}
1058
1059
1060void InstructionSelector::VisitUint32Div(Node* node) {
1061  Mips64OperandGenerator g(this);
1062  Int32BinopMatcher m(node);
1063  Emit(kMips64DivU, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1064       g.UseRegister(m.right().node()));
1065}
1066
1067
1068void InstructionSelector::VisitInt32Mod(Node* node) {
1069  Mips64OperandGenerator g(this);
1070  Int32BinopMatcher m(node);
1071  Node* left = node->InputAt(0);
1072  Node* right = node->InputAt(1);
1073  if (CanCover(node, left) && CanCover(node, right)) {
1074    if (left->opcode() == IrOpcode::kWord64Sar &&
1075        right->opcode() == IrOpcode::kWord64Sar) {
1076      Int64BinopMatcher rightInput(right), leftInput(left);
1077      if (rightInput.right().Is(32) && leftInput.right().Is(32)) {
1078        // Combine both shifted operands with Dmod.
1079        Emit(kMips64Dmod, g.DefineSameAsFirst(node),
1080             g.UseRegister(leftInput.left().node()),
1081             g.UseRegister(rightInput.left().node()));
1082        return;
1083      }
1084    }
1085  }
1086  Emit(kMips64Mod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1087       g.UseRegister(m.right().node()));
1088}
1089
1090
1091void InstructionSelector::VisitUint32Mod(Node* node) {
1092  Mips64OperandGenerator g(this);
1093  Int32BinopMatcher m(node);
1094  Emit(kMips64ModU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1095       g.UseRegister(m.right().node()));
1096}
1097
1098
1099void InstructionSelector::VisitInt64Div(Node* node) {
1100  Mips64OperandGenerator g(this);
1101  Int64BinopMatcher m(node);
1102  Emit(kMips64Ddiv, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1103       g.UseRegister(m.right().node()));
1104}
1105
1106
1107void InstructionSelector::VisitUint64Div(Node* node) {
1108  Mips64OperandGenerator g(this);
1109  Int64BinopMatcher m(node);
1110  Emit(kMips64DdivU, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1111       g.UseRegister(m.right().node()));
1112}
1113
1114
1115void InstructionSelector::VisitInt64Mod(Node* node) {
1116  Mips64OperandGenerator g(this);
1117  Int64BinopMatcher m(node);
1118  Emit(kMips64Dmod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1119       g.UseRegister(m.right().node()));
1120}
1121
1122
1123void InstructionSelector::VisitUint64Mod(Node* node) {
1124  Mips64OperandGenerator g(this);
1125  Int64BinopMatcher m(node);
1126  Emit(kMips64DmodU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1127       g.UseRegister(m.right().node()));
1128}
1129
1130
1131void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
1132  VisitRR(this, kMips64CvtDS, node);
1133}
1134
1135
1136void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
1137  VisitRR(this, kMips64CvtSW, node);
1138}
1139
1140
1141void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
1142  VisitRR(this, kMips64CvtSUw, node);
1143}
1144
1145
1146void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
1147  VisitRR(this, kMips64CvtDW, node);
1148}
1149
1150
1151void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
1152  VisitRR(this, kMips64CvtDUw, node);
1153}
1154
1155
1156void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
1157  VisitRR(this, kMips64TruncWS, node);
1158}
1159
1160
1161void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
1162  VisitRR(this, kMips64TruncUwS, node);
1163}
1164
1165
1166void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
1167  Mips64OperandGenerator g(this);
1168  Node* value = node->InputAt(0);
1169  // Match ChangeFloat64ToInt32(Float64Round##OP) to corresponding instruction
1170  // which does rounding and conversion to integer format.
1171  if (CanCover(node, value)) {
1172    switch (value->opcode()) {
1173      case IrOpcode::kFloat64RoundDown:
1174        Emit(kMips64FloorWD, g.DefineAsRegister(node),
1175             g.UseRegister(value->InputAt(0)));
1176        return;
1177      case IrOpcode::kFloat64RoundUp:
1178        Emit(kMips64CeilWD, g.DefineAsRegister(node),
1179             g.UseRegister(value->InputAt(0)));
1180        return;
1181      case IrOpcode::kFloat64RoundTiesEven:
1182        Emit(kMips64RoundWD, g.DefineAsRegister(node),
1183             g.UseRegister(value->InputAt(0)));
1184        return;
1185      case IrOpcode::kFloat64RoundTruncate:
1186        Emit(kMips64TruncWD, g.DefineAsRegister(node),
1187             g.UseRegister(value->InputAt(0)));
1188        return;
1189      default:
1190        break;
1191    }
1192    if (value->opcode() == IrOpcode::kChangeFloat32ToFloat64) {
1193      Node* next = value->InputAt(0);
1194      if (CanCover(value, next)) {
1195        // Match ChangeFloat64ToInt32(ChangeFloat32ToFloat64(Float64Round##OP))
1196        switch (next->opcode()) {
1197          case IrOpcode::kFloat32RoundDown:
1198            Emit(kMips64FloorWS, g.DefineAsRegister(node),
1199                 g.UseRegister(next->InputAt(0)));
1200            return;
1201          case IrOpcode::kFloat32RoundUp:
1202            Emit(kMips64CeilWS, g.DefineAsRegister(node),
1203                 g.UseRegister(next->InputAt(0)));
1204            return;
1205          case IrOpcode::kFloat32RoundTiesEven:
1206            Emit(kMips64RoundWS, g.DefineAsRegister(node),
1207                 g.UseRegister(next->InputAt(0)));
1208            return;
1209          case IrOpcode::kFloat32RoundTruncate:
1210            Emit(kMips64TruncWS, g.DefineAsRegister(node),
1211                 g.UseRegister(next->InputAt(0)));
1212            return;
1213          default:
1214            Emit(kMips64TruncWS, g.DefineAsRegister(node),
1215                 g.UseRegister(value->InputAt(0)));
1216            return;
1217        }
1218      } else {
1219        // Match float32 -> float64 -> int32 representation change path.
1220        Emit(kMips64TruncWS, g.DefineAsRegister(node),
1221             g.UseRegister(value->InputAt(0)));
1222        return;
1223      }
1224    }
1225  }
1226  VisitRR(this, kMips64TruncWD, node);
1227}
1228
1229
1230void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
1231  VisitRR(this, kMips64TruncUwD, node);
1232}
1233
1234void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) {
1235  VisitRR(this, kMips64TruncUwD, node);
1236}
1237
1238void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
1239  Mips64OperandGenerator g(this);
1240  InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
1241  InstructionOperand outputs[2];
1242  size_t output_count = 0;
1243  outputs[output_count++] = g.DefineAsRegister(node);
1244
1245  Node* success_output = NodeProperties::FindProjection(node, 1);
1246  if (success_output) {
1247    outputs[output_count++] = g.DefineAsRegister(success_output);
1248  }
1249
1250  this->Emit(kMips64TruncLS, output_count, outputs, 1, inputs);
1251}
1252
1253
1254void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) {
1255  Mips64OperandGenerator g(this);
1256  InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
1257  InstructionOperand outputs[2];
1258  size_t output_count = 0;
1259  outputs[output_count++] = g.DefineAsRegister(node);
1260
1261  Node* success_output = NodeProperties::FindProjection(node, 1);
1262  if (success_output) {
1263    outputs[output_count++] = g.DefineAsRegister(success_output);
1264  }
1265
1266  Emit(kMips64TruncLD, output_count, outputs, 1, inputs);
1267}
1268
1269
1270void InstructionSelector::VisitTryTruncateFloat32ToUint64(Node* node) {
1271  Mips64OperandGenerator g(this);
1272  InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
1273  InstructionOperand outputs[2];
1274  size_t output_count = 0;
1275  outputs[output_count++] = g.DefineAsRegister(node);
1276
1277  Node* success_output = NodeProperties::FindProjection(node, 1);
1278  if (success_output) {
1279    outputs[output_count++] = g.DefineAsRegister(success_output);
1280  }
1281
1282  Emit(kMips64TruncUlS, output_count, outputs, 1, inputs);
1283}
1284
1285
1286void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) {
1287  Mips64OperandGenerator g(this);
1288
1289  InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
1290  InstructionOperand outputs[2];
1291  size_t output_count = 0;
1292  outputs[output_count++] = g.DefineAsRegister(node);
1293
1294  Node* success_output = NodeProperties::FindProjection(node, 1);
1295  if (success_output) {
1296    outputs[output_count++] = g.DefineAsRegister(success_output);
1297  }
1298
1299  Emit(kMips64TruncUlD, output_count, outputs, 1, inputs);
1300}
1301
1302
1303void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
1304  Node* value = node->InputAt(0);
1305  if (value->opcode() == IrOpcode::kLoad && CanCover(node, value)) {
1306    // Generate sign-extending load.
1307    LoadRepresentation load_rep = LoadRepresentationOf(value->op());
1308    InstructionCode opcode = kArchNop;
1309    switch (load_rep.representation()) {
1310      case MachineRepresentation::kBit:  // Fall through.
1311      case MachineRepresentation::kWord8:
1312        opcode = load_rep.IsUnsigned() ? kMips64Lbu : kMips64Lb;
1313        break;
1314      case MachineRepresentation::kWord16:
1315        opcode = load_rep.IsUnsigned() ? kMips64Lhu : kMips64Lh;
1316        break;
1317      case MachineRepresentation::kWord32:
1318        opcode = kMips64Lw;
1319        break;
1320      default:
1321        UNREACHABLE();
1322        return;
1323    }
1324    EmitLoad(this, value, opcode, node);
1325  } else {
1326    Mips64OperandGenerator g(this);
1327    Emit(kMips64Shl, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
1328         g.TempImmediate(0));
1329  }
1330}
1331
1332
1333void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
1334  Mips64OperandGenerator g(this);
1335  Node* value = node->InputAt(0);
1336  switch (value->opcode()) {
1337    // 32-bit operations will write their result in a 64 bit register,
1338    // clearing the top 32 bits of the destination register.
1339    case IrOpcode::kUint32Div:
1340    case IrOpcode::kUint32Mod:
1341    case IrOpcode::kUint32MulHigh: {
1342      Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
1343      return;
1344    }
1345    case IrOpcode::kLoad: {
1346      LoadRepresentation load_rep = LoadRepresentationOf(value->op());
1347      if (load_rep.IsUnsigned()) {
1348        switch (load_rep.representation()) {
1349          case MachineRepresentation::kWord8:
1350          case MachineRepresentation::kWord16:
1351          case MachineRepresentation::kWord32:
1352            Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
1353            return;
1354          default:
1355            break;
1356        }
1357      }
1358    }
1359    default:
1360      break;
1361  }
1362  Emit(kMips64Dext, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
1363       g.TempImmediate(0), g.TempImmediate(32));
1364}
1365
1366
1367void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
1368  Mips64OperandGenerator g(this);
1369  Node* value = node->InputAt(0);
1370  if (CanCover(node, value)) {
1371    switch (value->opcode()) {
1372      case IrOpcode::kWord64Sar: {
1373        if (TryEmitExtendingLoad(this, value, node)) {
1374          return;
1375        } else {
1376          Int64BinopMatcher m(value);
1377          if (m.right().IsInRange(32, 63)) {
1378            // After smi untagging no need for truncate. Combine sequence.
1379            Emit(kMips64Dsar, g.DefineSameAsFirst(node),
1380                 g.UseRegister(m.left().node()),
1381                 g.UseImmediate(m.right().node()));
1382            return;
1383          }
1384        }
1385        break;
1386      }
1387      default:
1388        break;
1389    }
1390  }
1391  Emit(kMips64Ext, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
1392       g.TempImmediate(0), g.TempImmediate(32));
1393}
1394
1395
1396void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
1397  Mips64OperandGenerator g(this);
1398  Node* value = node->InputAt(0);
1399  // Match TruncateFloat64ToFloat32(ChangeInt32ToFloat64) to corresponding
1400  // instruction.
1401  if (CanCover(node, value) &&
1402      value->opcode() == IrOpcode::kChangeInt32ToFloat64) {
1403    Emit(kMips64CvtSW, g.DefineAsRegister(node),
1404         g.UseRegister(value->InputAt(0)));
1405    return;
1406  }
1407  VisitRR(this, kMips64CvtSD, node);
1408}
1409
1410void InstructionSelector::VisitTruncateFloat64ToWord32(Node* node) {
1411  VisitRR(this, kArchTruncateDoubleToI, node);
1412}
1413
1414void InstructionSelector::VisitRoundFloat64ToInt32(Node* node) {
1415  VisitRR(this, kMips64TruncWD, node);
1416}
1417
1418void InstructionSelector::VisitRoundInt64ToFloat32(Node* node) {
1419  VisitRR(this, kMips64CvtSL, node);
1420}
1421
1422
1423void InstructionSelector::VisitRoundInt64ToFloat64(Node* node) {
1424  VisitRR(this, kMips64CvtDL, node);
1425}
1426
1427
1428void InstructionSelector::VisitRoundUint64ToFloat32(Node* node) {
1429  VisitRR(this, kMips64CvtSUl, node);
1430}
1431
1432
1433void InstructionSelector::VisitRoundUint64ToFloat64(Node* node) {
1434  VisitRR(this, kMips64CvtDUl, node);
1435}
1436
1437
1438void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
1439  VisitRR(this, kMips64Float64ExtractLowWord32, node);
1440}
1441
1442
1443void InstructionSelector::VisitBitcastFloat64ToInt64(Node* node) {
1444  VisitRR(this, kMips64BitcastDL, node);
1445}
1446
1447
1448void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
1449  Mips64OperandGenerator g(this);
1450  Emit(kMips64Float64InsertLowWord32, g.DefineAsRegister(node),
1451       ImmediateOperand(ImmediateOperand::INLINE, 0),
1452       g.UseRegister(node->InputAt(0)));
1453}
1454
1455
1456void InstructionSelector::VisitBitcastInt64ToFloat64(Node* node) {
1457  VisitRR(this, kMips64BitcastLD, node);
1458}
1459
1460
1461void InstructionSelector::VisitFloat32Add(Node* node) {
1462  Mips64OperandGenerator g(this);
1463  if (kArchVariant == kMips64r2) {  // Select Madd.S(z, x, y).
1464    Float32BinopMatcher m(node);
1465    if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) {
1466      // For Add.S(Mul.S(x, y), z):
1467      Float32BinopMatcher mleft(m.left().node());
1468      Emit(kMips64MaddS, g.DefineAsRegister(node),
1469           g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1470           g.UseRegister(mleft.right().node()));
1471      return;
1472    }
1473    if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1474      // For Add.S(x, Mul.S(y, z)):
1475      Float32BinopMatcher mright(m.right().node());
1476      Emit(kMips64MaddS, g.DefineAsRegister(node),
1477           g.UseRegister(m.left().node()), g.UseRegister(mright.left().node()),
1478           g.UseRegister(mright.right().node()));
1479      return;
1480    }
1481  }
1482  VisitRRR(this, kMips64AddS, node);
1483}
1484
1485
1486void InstructionSelector::VisitFloat64Add(Node* node) {
1487  Mips64OperandGenerator g(this);
1488  if (kArchVariant == kMips64r2) {  // Select Madd.S(z, x, y).
1489    Float64BinopMatcher m(node);
1490    if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
1491      // For Add.D(Mul.D(x, y), z):
1492      Float64BinopMatcher mleft(m.left().node());
1493      Emit(kMips64MaddD, g.DefineAsRegister(node),
1494           g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1495           g.UseRegister(mleft.right().node()));
1496      return;
1497    }
1498    if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
1499      // For Add.D(x, Mul.D(y, z)):
1500      Float64BinopMatcher mright(m.right().node());
1501      Emit(kMips64MaddD, g.DefineAsRegister(node),
1502           g.UseRegister(m.left().node()), g.UseRegister(mright.left().node()),
1503           g.UseRegister(mright.right().node()));
1504      return;
1505    }
1506  }
1507  VisitRRR(this, kMips64AddD, node);
1508}
1509
1510
1511void InstructionSelector::VisitFloat32Sub(Node* node) {
1512  Mips64OperandGenerator g(this);
1513  if (kArchVariant == kMips64r2) {  // Select Madd.S(z, x, y).
1514    Float32BinopMatcher m(node);
1515    if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) {
1516      // For Sub.S(Mul.S(x,y), z) select Msub.S(z, x, y).
1517      Float32BinopMatcher mleft(m.left().node());
1518      Emit(kMips64MsubS, g.DefineAsRegister(node),
1519           g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1520           g.UseRegister(mleft.right().node()));
1521      return;
1522    }
1523  }
1524  VisitRRR(this, kMips64SubS, node);
1525}
1526
1527void InstructionSelector::VisitFloat64Sub(Node* node) {
1528  Mips64OperandGenerator g(this);
1529  if (kArchVariant == kMips64r2) {  // Select Madd.S(z, x, y).
1530    Float64BinopMatcher m(node);
1531    if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
1532      // For Sub.D(Mul.S(x,y), z) select Msub.D(z, x, y).
1533      Float64BinopMatcher mleft(m.left().node());
1534      Emit(kMips64MsubD, g.DefineAsRegister(node),
1535           g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1536           g.UseRegister(mleft.right().node()));
1537      return;
1538    }
1539  }
1540  VisitRRR(this, kMips64SubD, node);
1541}
1542
1543void InstructionSelector::VisitFloat32Mul(Node* node) {
1544  VisitRRR(this, kMips64MulS, node);
1545}
1546
1547
1548void InstructionSelector::VisitFloat64Mul(Node* node) {
1549  VisitRRR(this, kMips64MulD, node);
1550}
1551
1552
1553void InstructionSelector::VisitFloat32Div(Node* node) {
1554  VisitRRR(this, kMips64DivS, node);
1555}
1556
1557
1558void InstructionSelector::VisitFloat64Div(Node* node) {
1559  VisitRRR(this, kMips64DivD, node);
1560}
1561
1562
1563void InstructionSelector::VisitFloat64Mod(Node* node) {
1564  Mips64OperandGenerator g(this);
1565  Emit(kMips64ModD, g.DefineAsFixed(node, f0),
1566       g.UseFixed(node->InputAt(0), f12),
1567       g.UseFixed(node->InputAt(1), f14))->MarkAsCall();
1568}
1569
1570void InstructionSelector::VisitFloat32Max(Node* node) {
1571  Mips64OperandGenerator g(this);
1572  Emit(kMips64Float32Max, g.DefineAsRegister(node),
1573       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
1574}
1575
1576void InstructionSelector::VisitFloat64Max(Node* node) {
1577  Mips64OperandGenerator g(this);
1578  Emit(kMips64Float64Max, g.DefineAsRegister(node),
1579       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
1580}
1581
1582void InstructionSelector::VisitFloat32Min(Node* node) {
1583  Mips64OperandGenerator g(this);
1584  Emit(kMips64Float32Min, g.DefineAsRegister(node),
1585       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
1586}
1587
1588void InstructionSelector::VisitFloat64Min(Node* node) {
1589  Mips64OperandGenerator g(this);
1590  Emit(kMips64Float64Min, g.DefineAsRegister(node),
1591       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
1592}
1593
1594
1595void InstructionSelector::VisitFloat32Abs(Node* node) {
1596  VisitRR(this, kMips64AbsS, node);
1597}
1598
1599
1600void InstructionSelector::VisitFloat64Abs(Node* node) {
1601  VisitRR(this, kMips64AbsD, node);
1602}
1603
1604void InstructionSelector::VisitFloat32Sqrt(Node* node) {
1605  VisitRR(this, kMips64SqrtS, node);
1606}
1607
1608
1609void InstructionSelector::VisitFloat64Sqrt(Node* node) {
1610  VisitRR(this, kMips64SqrtD, node);
1611}
1612
1613
1614void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1615  VisitRR(this, kMips64Float32RoundDown, node);
1616}
1617
1618
1619void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1620  VisitRR(this, kMips64Float64RoundDown, node);
1621}
1622
1623
1624void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1625  VisitRR(this, kMips64Float32RoundUp, node);
1626}
1627
1628
1629void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1630  VisitRR(this, kMips64Float64RoundUp, node);
1631}
1632
1633
1634void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1635  VisitRR(this, kMips64Float32RoundTruncate, node);
1636}
1637
1638
1639void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
1640  VisitRR(this, kMips64Float64RoundTruncate, node);
1641}
1642
1643
1644void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
1645  UNREACHABLE();
1646}
1647
1648
1649void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1650  VisitRR(this, kMips64Float32RoundTiesEven, node);
1651}
1652
1653
1654void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1655  VisitRR(this, kMips64Float64RoundTiesEven, node);
1656}
1657
1658void InstructionSelector::VisitFloat32Neg(Node* node) {
1659  VisitRR(this, kMips64NegS, node);
1660}
1661
1662void InstructionSelector::VisitFloat64Neg(Node* node) {
1663  VisitRR(this, kMips64NegD, node);
1664}
1665
1666void InstructionSelector::VisitFloat64Ieee754Binop(Node* node,
1667                                                   InstructionCode opcode) {
1668  Mips64OperandGenerator g(this);
1669  Emit(opcode, g.DefineAsFixed(node, f0), g.UseFixed(node->InputAt(0), f2),
1670       g.UseFixed(node->InputAt(1), f4))
1671      ->MarkAsCall();
1672}
1673
1674void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
1675                                                  InstructionCode opcode) {
1676  Mips64OperandGenerator g(this);
1677  Emit(opcode, g.DefineAsFixed(node, f0), g.UseFixed(node->InputAt(0), f12))
1678      ->MarkAsCall();
1679}
1680
1681void InstructionSelector::EmitPrepareArguments(
1682    ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1683    Node* node) {
1684  Mips64OperandGenerator g(this);
1685
1686  // Prepare for C function call.
1687  if (descriptor->IsCFunctionCall()) {
1688    Emit(kArchPrepareCallCFunction |
1689             MiscField::encode(static_cast<int>(descriptor->ParameterCount())),
1690         0, nullptr, 0, nullptr);
1691
1692    // Poke any stack arguments.
1693    int slot = kCArgSlotCount;
1694    for (PushParameter input : (*arguments)) {
1695      Emit(kMips64StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
1696           g.TempImmediate(slot << kPointerSizeLog2));
1697      ++slot;
1698    }
1699  } else {
1700    int push_count = static_cast<int>(descriptor->StackParameterCount());
1701    if (push_count > 0) {
1702      Emit(kMips64StackClaim, g.NoOutput(),
1703           g.TempImmediate(push_count << kPointerSizeLog2));
1704    }
1705    for (size_t n = 0; n < arguments->size(); ++n) {
1706      PushParameter input = (*arguments)[n];
1707      if (input.node()) {
1708        Emit(kMips64StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
1709             g.TempImmediate(static_cast<int>(n << kPointerSizeLog2)));
1710      }
1711    }
1712  }
1713}
1714
1715
1716bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
1717
1718int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; }
1719
1720void InstructionSelector::VisitUnalignedLoad(Node* node) {
1721  UnalignedLoadRepresentation load_rep =
1722      UnalignedLoadRepresentationOf(node->op());
1723  Mips64OperandGenerator g(this);
1724  Node* base = node->InputAt(0);
1725  Node* index = node->InputAt(1);
1726
1727  ArchOpcode opcode = kArchNop;
1728  switch (load_rep.representation()) {
1729    case MachineRepresentation::kFloat32:
1730      opcode = kMips64Ulwc1;
1731      break;
1732    case MachineRepresentation::kFloat64:
1733      opcode = kMips64Uldc1;
1734      break;
1735    case MachineRepresentation::kBit:  // Fall through.
1736    case MachineRepresentation::kWord8:
1737      UNREACHABLE();
1738      break;
1739    case MachineRepresentation::kWord16:
1740      opcode = load_rep.IsUnsigned() ? kMips64Ulhu : kMips64Ulh;
1741      break;
1742    case MachineRepresentation::kWord32:
1743      opcode = load_rep.IsUnsigned() ? kMips64Ulwu : kMips64Ulw;
1744      break;
1745    case MachineRepresentation::kTaggedSigned:   // Fall through.
1746    case MachineRepresentation::kTaggedPointer:  // Fall through.
1747    case MachineRepresentation::kTagged:  // Fall through.
1748    case MachineRepresentation::kWord64:
1749      opcode = kMips64Uld;
1750      break;
1751    case MachineRepresentation::kSimd128:  // Fall through.
1752    case MachineRepresentation::kSimd1x4:  // Fall through.
1753    case MachineRepresentation::kSimd1x8:  // Fall through.
1754    case MachineRepresentation::kSimd1x16:  // Fall through.
1755    case MachineRepresentation::kNone:
1756      UNREACHABLE();
1757      return;
1758  }
1759
1760  if (g.CanBeImmediate(index, opcode)) {
1761    Emit(opcode | AddressingModeField::encode(kMode_MRI),
1762         g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
1763  } else {
1764    InstructionOperand addr_reg = g.TempRegister();
1765    Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
1766         g.UseRegister(index), g.UseRegister(base));
1767    // Emit desired load opcode, using temp addr_reg.
1768    Emit(opcode | AddressingModeField::encode(kMode_MRI),
1769         g.DefineAsRegister(node), addr_reg, g.TempImmediate(0));
1770  }
1771}
1772
1773void InstructionSelector::VisitUnalignedStore(Node* node) {
1774  Mips64OperandGenerator g(this);
1775  Node* base = node->InputAt(0);
1776  Node* index = node->InputAt(1);
1777  Node* value = node->InputAt(2);
1778
1779  UnalignedStoreRepresentation rep = UnalignedStoreRepresentationOf(node->op());
1780  ArchOpcode opcode = kArchNop;
1781  switch (rep) {
1782    case MachineRepresentation::kFloat32:
1783      opcode = kMips64Uswc1;
1784      break;
1785    case MachineRepresentation::kFloat64:
1786      opcode = kMips64Usdc1;
1787      break;
1788    case MachineRepresentation::kBit:  // Fall through.
1789    case MachineRepresentation::kWord8:
1790      UNREACHABLE();
1791      break;
1792    case MachineRepresentation::kWord16:
1793      opcode = kMips64Ush;
1794      break;
1795    case MachineRepresentation::kWord32:
1796      opcode = kMips64Usw;
1797      break;
1798    case MachineRepresentation::kTaggedSigned:   // Fall through.
1799    case MachineRepresentation::kTaggedPointer:  // Fall through.
1800    case MachineRepresentation::kTagged:  // Fall through.
1801    case MachineRepresentation::kWord64:
1802      opcode = kMips64Usd;
1803      break;
1804    case MachineRepresentation::kSimd128:  // Fall through.
1805    case MachineRepresentation::kSimd1x4:  // Fall through.
1806    case MachineRepresentation::kSimd1x8:  // Fall through.
1807    case MachineRepresentation::kSimd1x16:  // Fall through.
1808    case MachineRepresentation::kNone:
1809      UNREACHABLE();
1810      return;
1811  }
1812
1813  if (g.CanBeImmediate(index, opcode)) {
1814    Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
1815         g.UseRegister(base), g.UseImmediate(index),
1816         g.UseRegisterOrImmediateZero(value));
1817  } else {
1818    InstructionOperand addr_reg = g.TempRegister();
1819    Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
1820         g.UseRegister(index), g.UseRegister(base));
1821    // Emit desired store opcode, using temp addr_reg.
1822    Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
1823         addr_reg, g.TempImmediate(0), g.UseRegisterOrImmediateZero(value));
1824  }
1825}
1826
1827void InstructionSelector::VisitCheckedLoad(Node* node) {
1828  CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
1829  Mips64OperandGenerator g(this);
1830  Node* const buffer = node->InputAt(0);
1831  Node* const offset = node->InputAt(1);
1832  Node* const length = node->InputAt(2);
1833  ArchOpcode opcode = kArchNop;
1834  switch (load_rep.representation()) {
1835    case MachineRepresentation::kWord8:
1836      opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
1837      break;
1838    case MachineRepresentation::kWord16:
1839      opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
1840      break;
1841    case MachineRepresentation::kWord32:
1842      opcode = kCheckedLoadWord32;
1843      break;
1844    case MachineRepresentation::kWord64:
1845      opcode = kCheckedLoadWord64;
1846      break;
1847    case MachineRepresentation::kFloat32:
1848      opcode = kCheckedLoadFloat32;
1849      break;
1850    case MachineRepresentation::kFloat64:
1851      opcode = kCheckedLoadFloat64;
1852      break;
1853    case MachineRepresentation::kBit:
1854    case MachineRepresentation::kTaggedSigned:   // Fall through.
1855    case MachineRepresentation::kTaggedPointer:  // Fall through.
1856    case MachineRepresentation::kTagged:
1857    case MachineRepresentation::kSimd128:
1858    case MachineRepresentation::kSimd1x4:   // Fall through.
1859    case MachineRepresentation::kSimd1x8:   // Fall through.
1860    case MachineRepresentation::kSimd1x16:  // Fall through.
1861    case MachineRepresentation::kNone:
1862      UNREACHABLE();
1863      return;
1864  }
1865  InstructionOperand offset_operand = g.CanBeImmediate(offset, opcode)
1866                                          ? g.UseImmediate(offset)
1867                                          : g.UseRegister(offset);
1868
1869  InstructionOperand length_operand = (!g.CanBeImmediate(offset, opcode))
1870                                          ? g.CanBeImmediate(length, opcode)
1871                                                ? g.UseImmediate(length)
1872                                                : g.UseRegister(length)
1873                                          : g.UseRegister(length);
1874
1875  if (length->opcode() == IrOpcode::kInt32Constant) {
1876    Int32Matcher m(length);
1877    if (m.IsPowerOf2()) {
1878      Emit(opcode, g.DefineAsRegister(node), offset_operand,
1879           g.UseImmediate(length), g.UseRegister(buffer));
1880      return;
1881    }
1882  }
1883
1884  Emit(opcode | AddressingModeField::encode(kMode_MRI),
1885       g.DefineAsRegister(node), offset_operand, length_operand,
1886       g.UseRegister(buffer));
1887}
1888
1889
1890void InstructionSelector::VisitCheckedStore(Node* node) {
1891  MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
1892  Mips64OperandGenerator g(this);
1893  Node* const buffer = node->InputAt(0);
1894  Node* const offset = node->InputAt(1);
1895  Node* const length = node->InputAt(2);
1896  Node* const value = node->InputAt(3);
1897  ArchOpcode opcode = kArchNop;
1898  switch (rep) {
1899    case MachineRepresentation::kWord8:
1900      opcode = kCheckedStoreWord8;
1901      break;
1902    case MachineRepresentation::kWord16:
1903      opcode = kCheckedStoreWord16;
1904      break;
1905    case MachineRepresentation::kWord32:
1906      opcode = kCheckedStoreWord32;
1907      break;
1908    case MachineRepresentation::kWord64:
1909      opcode = kCheckedStoreWord64;
1910      break;
1911    case MachineRepresentation::kFloat32:
1912      opcode = kCheckedStoreFloat32;
1913      break;
1914    case MachineRepresentation::kFloat64:
1915      opcode = kCheckedStoreFloat64;
1916      break;
1917    case MachineRepresentation::kBit:
1918    case MachineRepresentation::kTaggedSigned:   // Fall through.
1919    case MachineRepresentation::kTaggedPointer:  // Fall through.
1920    case MachineRepresentation::kTagged:
1921    case MachineRepresentation::kSimd128:
1922    case MachineRepresentation::kSimd1x4:   // Fall through.
1923    case MachineRepresentation::kSimd1x8:   // Fall through.
1924    case MachineRepresentation::kSimd1x16:  // Fall through.
1925    case MachineRepresentation::kNone:
1926      UNREACHABLE();
1927      return;
1928  }
1929  InstructionOperand offset_operand = g.CanBeImmediate(offset, opcode)
1930                                          ? g.UseImmediate(offset)
1931                                          : g.UseRegister(offset);
1932
1933  InstructionOperand length_operand = (!g.CanBeImmediate(offset, opcode))
1934                                          ? g.CanBeImmediate(length, opcode)
1935                                                ? g.UseImmediate(length)
1936                                                : g.UseRegister(length)
1937                                          : g.UseRegister(length);
1938
1939  if (length->opcode() == IrOpcode::kInt32Constant) {
1940    Int32Matcher m(length);
1941    if (m.IsPowerOf2()) {
1942      Emit(opcode, g.NoOutput(), offset_operand, g.UseImmediate(length),
1943           g.UseRegisterOrImmediateZero(value), g.UseRegister(buffer));
1944      return;
1945    }
1946  }
1947
1948  Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
1949       offset_operand, length_operand, g.UseRegisterOrImmediateZero(value),
1950       g.UseRegister(buffer));
1951}
1952
1953
1954namespace {
1955
1956// Shared routine for multiple compare operations.
1957static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1958                         InstructionOperand left, InstructionOperand right,
1959                         FlagsContinuation* cont) {
1960  Mips64OperandGenerator g(selector);
1961  opcode = cont->Encode(opcode);
1962  if (cont->IsBranch()) {
1963    selector->Emit(opcode, g.NoOutput(), left, right,
1964                   g.Label(cont->true_block()), g.Label(cont->false_block()));
1965  } else if (cont->IsDeoptimize()) {
1966    selector->EmitDeoptimize(opcode, g.NoOutput(), left, right, cont->kind(),
1967                             cont->reason(), cont->frame_state());
1968  } else if (cont->IsSet()) {
1969    selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
1970  } else {
1971    DCHECK(cont->IsTrap());
1972    selector->Emit(opcode, g.NoOutput(), left, right,
1973                   g.TempImmediate(cont->trap_id()));
1974  }
1975}
1976
1977
1978// Shared routine for multiple float32 compare operations.
1979void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1980                         FlagsContinuation* cont) {
1981  Mips64OperandGenerator g(selector);
1982  Float32BinopMatcher m(node);
1983  InstructionOperand lhs, rhs;
1984
1985  lhs = m.left().IsZero() ? g.UseImmediate(m.left().node())
1986                          : g.UseRegister(m.left().node());
1987  rhs = m.right().IsZero() ? g.UseImmediate(m.right().node())
1988                           : g.UseRegister(m.right().node());
1989  VisitCompare(selector, kMips64CmpS, lhs, rhs, cont);
1990}
1991
1992
1993// Shared routine for multiple float64 compare operations.
1994void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1995                         FlagsContinuation* cont) {
1996  Mips64OperandGenerator g(selector);
1997  Float64BinopMatcher m(node);
1998  InstructionOperand lhs, rhs;
1999
2000  lhs = m.left().IsZero() ? g.UseImmediate(m.left().node())
2001                          : g.UseRegister(m.left().node());
2002  rhs = m.right().IsZero() ? g.UseImmediate(m.right().node())
2003                           : g.UseRegister(m.right().node());
2004  VisitCompare(selector, kMips64CmpD, lhs, rhs, cont);
2005}
2006
2007
2008// Shared routine for multiple word compare operations.
2009void VisitWordCompare(InstructionSelector* selector, Node* node,
2010                      InstructionCode opcode, FlagsContinuation* cont,
2011                      bool commutative) {
2012  Mips64OperandGenerator g(selector);
2013  Node* left = node->InputAt(0);
2014  Node* right = node->InputAt(1);
2015
2016  // Match immediates on left or right side of comparison.
2017  if (g.CanBeImmediate(right, opcode)) {
2018    if (opcode == kMips64Tst) {
2019      VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
2020                   cont);
2021    } else {
2022      switch (cont->condition()) {
2023        case kEqual:
2024        case kNotEqual:
2025          if (cont->IsSet()) {
2026            VisitCompare(selector, opcode, g.UseRegister(left),
2027                         g.UseImmediate(right), cont);
2028          } else {
2029            VisitCompare(selector, opcode, g.UseRegister(left),
2030                         g.UseRegister(right), cont);
2031          }
2032          break;
2033        case kSignedLessThan:
2034        case kSignedGreaterThanOrEqual:
2035        case kUnsignedLessThan:
2036        case kUnsignedGreaterThanOrEqual:
2037          VisitCompare(selector, opcode, g.UseRegister(left),
2038                       g.UseImmediate(right), cont);
2039          break;
2040        default:
2041          VisitCompare(selector, opcode, g.UseRegister(left),
2042                       g.UseRegister(right), cont);
2043      }
2044    }
2045  } else if (g.CanBeImmediate(left, opcode)) {
2046    if (!commutative) cont->Commute();
2047    if (opcode == kMips64Tst) {
2048      VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
2049                   cont);
2050    } else {
2051      switch (cont->condition()) {
2052        case kEqual:
2053        case kNotEqual:
2054          if (cont->IsSet()) {
2055            VisitCompare(selector, opcode, g.UseRegister(right),
2056                         g.UseImmediate(left), cont);
2057          } else {
2058            VisitCompare(selector, opcode, g.UseRegister(right),
2059                         g.UseRegister(left), cont);
2060          }
2061          break;
2062        case kSignedLessThan:
2063        case kSignedGreaterThanOrEqual:
2064        case kUnsignedLessThan:
2065        case kUnsignedGreaterThanOrEqual:
2066          VisitCompare(selector, opcode, g.UseRegister(right),
2067                       g.UseImmediate(left), cont);
2068          break;
2069        default:
2070          VisitCompare(selector, opcode, g.UseRegister(right),
2071                       g.UseRegister(left), cont);
2072      }
2073    }
2074  } else {
2075    VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
2076                 cont);
2077  }
2078}
2079
2080bool IsNodeUnsigned(Node* n) {
2081  NodeMatcher m(n);
2082
2083  if (m.IsLoad()) {
2084    LoadRepresentation load_rep = LoadRepresentationOf(n->op());
2085    return load_rep.IsUnsigned();
2086  } else if (m.IsUnalignedLoad()) {
2087    UnalignedLoadRepresentation load_rep =
2088        UnalignedLoadRepresentationOf(n->op());
2089    return load_rep.IsUnsigned();
2090  } else {
2091    return m.IsUint32Div() || m.IsUint32LessThan() ||
2092           m.IsUint32LessThanOrEqual() || m.IsUint32Mod() ||
2093           m.IsUint32MulHigh() || m.IsChangeFloat64ToUint32() ||
2094           m.IsTruncateFloat64ToUint32() || m.IsTruncateFloat32ToUint32();
2095  }
2096}
2097
2098// Shared routine for multiple word compare operations.
2099void VisitFullWord32Compare(InstructionSelector* selector, Node* node,
2100                            InstructionCode opcode, FlagsContinuation* cont) {
2101  Mips64OperandGenerator g(selector);
2102  InstructionOperand leftOp = g.TempRegister();
2103  InstructionOperand rightOp = g.TempRegister();
2104
2105  selector->Emit(kMips64Dshl, leftOp, g.UseRegister(node->InputAt(0)),
2106                 g.TempImmediate(32));
2107  selector->Emit(kMips64Dshl, rightOp, g.UseRegister(node->InputAt(1)),
2108                 g.TempImmediate(32));
2109
2110  VisitCompare(selector, opcode, leftOp, rightOp, cont);
2111}
2112
2113void VisitOptimizedWord32Compare(InstructionSelector* selector, Node* node,
2114                                 InstructionCode opcode,
2115                                 FlagsContinuation* cont) {
2116  if (FLAG_debug_code) {
2117    Mips64OperandGenerator g(selector);
2118    InstructionOperand leftOp = g.TempRegister();
2119    InstructionOperand rightOp = g.TempRegister();
2120    InstructionOperand optimizedResult = g.TempRegister();
2121    InstructionOperand fullResult = g.TempRegister();
2122    FlagsCondition condition = cont->condition();
2123    InstructionCode testOpcode = opcode |
2124                                 FlagsConditionField::encode(condition) |
2125                                 FlagsModeField::encode(kFlags_set);
2126
2127    selector->Emit(testOpcode, optimizedResult, g.UseRegister(node->InputAt(0)),
2128                   g.UseRegister(node->InputAt(1)));
2129
2130    selector->Emit(kMips64Dshl, leftOp, g.UseRegister(node->InputAt(0)),
2131                   g.TempImmediate(32));
2132    selector->Emit(kMips64Dshl, rightOp, g.UseRegister(node->InputAt(1)),
2133                   g.TempImmediate(32));
2134    selector->Emit(testOpcode, fullResult, leftOp, rightOp);
2135
2136    selector->Emit(
2137        kMips64AssertEqual, g.NoOutput(), optimizedResult, fullResult,
2138        g.TempImmediate(BailoutReason::kUnsupportedNonPrimitiveCompare));
2139  }
2140
2141  VisitWordCompare(selector, node, opcode, cont, false);
2142}
2143
2144void VisitWord32Compare(InstructionSelector* selector, Node* node,
2145                        FlagsContinuation* cont) {
2146  // MIPS64 doesn't support Word32 compare instructions. Instead it relies
2147  // that the values in registers are correctly sign-extended and uses
2148  // Word64 comparison instead. This behavior is correct in most cases,
2149  // but doesn't work when comparing signed with unsigned operands.
2150  // We could simulate full Word32 compare in all cases but this would
2151  // create an unnecessary overhead since unsigned integers are rarely
2152  // used in JavaScript.
2153  // The solution proposed here tries to match a comparison of signed
2154  // with unsigned operand, and perform full Word32Compare only
2155  // in those cases. Unfortunately, the solution is not complete because
2156  // it might skip cases where Word32 full compare is needed, so
2157  // basically it is a hack.
2158  if (IsNodeUnsigned(node->InputAt(0)) != IsNodeUnsigned(node->InputAt(1))) {
2159    VisitFullWord32Compare(selector, node, kMips64Cmp, cont);
2160  } else {
2161    VisitOptimizedWord32Compare(selector, node, kMips64Cmp, cont);
2162  }
2163}
2164
2165
2166void VisitWord64Compare(InstructionSelector* selector, Node* node,
2167                        FlagsContinuation* cont) {
2168  VisitWordCompare(selector, node, kMips64Cmp, cont, false);
2169}
2170
2171
2172
2173void EmitWordCompareZero(InstructionSelector* selector, Node* value,
2174                         FlagsContinuation* cont) {
2175  Mips64OperandGenerator g(selector);
2176  InstructionCode opcode = cont->Encode(kMips64Cmp);
2177  InstructionOperand const value_operand = g.UseRegister(value);
2178  if (cont->IsBranch()) {
2179    selector->Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
2180                   g.Label(cont->true_block()), g.Label(cont->false_block()));
2181  } else if (cont->IsDeoptimize()) {
2182    selector->EmitDeoptimize(opcode, g.NoOutput(), value_operand,
2183                             g.TempImmediate(0), cont->kind(), cont->reason(),
2184                             cont->frame_state());
2185  } else if (cont->IsTrap()) {
2186    selector->Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
2187                   g.TempImmediate(cont->trap_id()));
2188  } else {
2189    selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
2190                   g.TempImmediate(0));
2191  }
2192}
2193
2194
2195// Shared routine for word comparisons against zero.
2196void VisitWordCompareZero(InstructionSelector* selector, Node* user,
2197                          Node* value, FlagsContinuation* cont) {
2198  // Try to combine with comparisons against 0 by simply inverting the branch.
2199  while (selector->CanCover(user, value)) {
2200    if (value->opcode() == IrOpcode::kWord32Equal) {
2201      Int32BinopMatcher m(value);
2202      if (!m.right().Is(0)) break;
2203      user = value;
2204      value = m.left().node();
2205    } else if (value->opcode() == IrOpcode::kWord64Equal) {
2206      Int64BinopMatcher m(value);
2207      if (!m.right().Is(0)) break;
2208      user = value;
2209      value = m.left().node();
2210    } else {
2211      break;
2212    }
2213
2214    cont->Negate();
2215  }
2216
2217  if (selector->CanCover(user, value)) {
2218    switch (value->opcode()) {
2219      case IrOpcode::kWord32Equal:
2220        cont->OverwriteAndNegateIfEqual(kEqual);
2221        return VisitWord32Compare(selector, value, cont);
2222      case IrOpcode::kInt32LessThan:
2223        cont->OverwriteAndNegateIfEqual(kSignedLessThan);
2224        return VisitWord32Compare(selector, value, cont);
2225      case IrOpcode::kInt32LessThanOrEqual:
2226        cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
2227        return VisitWord32Compare(selector, value, cont);
2228      case IrOpcode::kUint32LessThan:
2229        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
2230        return VisitWord32Compare(selector, value, cont);
2231      case IrOpcode::kUint32LessThanOrEqual:
2232        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
2233        return VisitWord32Compare(selector, value, cont);
2234      case IrOpcode::kWord64Equal:
2235        cont->OverwriteAndNegateIfEqual(kEqual);
2236        return VisitWord64Compare(selector, value, cont);
2237      case IrOpcode::kInt64LessThan:
2238        cont->OverwriteAndNegateIfEqual(kSignedLessThan);
2239        return VisitWord64Compare(selector, value, cont);
2240      case IrOpcode::kInt64LessThanOrEqual:
2241        cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
2242        return VisitWord64Compare(selector, value, cont);
2243      case IrOpcode::kUint64LessThan:
2244        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
2245        return VisitWord64Compare(selector, value, cont);
2246      case IrOpcode::kUint64LessThanOrEqual:
2247        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
2248        return VisitWord64Compare(selector, value, cont);
2249      case IrOpcode::kFloat32Equal:
2250        cont->OverwriteAndNegateIfEqual(kEqual);
2251        return VisitFloat32Compare(selector, value, cont);
2252      case IrOpcode::kFloat32LessThan:
2253        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
2254        return VisitFloat32Compare(selector, value, cont);
2255      case IrOpcode::kFloat32LessThanOrEqual:
2256        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
2257        return VisitFloat32Compare(selector, value, cont);
2258      case IrOpcode::kFloat64Equal:
2259        cont->OverwriteAndNegateIfEqual(kEqual);
2260        return VisitFloat64Compare(selector, value, cont);
2261      case IrOpcode::kFloat64LessThan:
2262        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
2263        return VisitFloat64Compare(selector, value, cont);
2264      case IrOpcode::kFloat64LessThanOrEqual:
2265        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
2266        return VisitFloat64Compare(selector, value, cont);
2267      case IrOpcode::kProjection:
2268        // Check if this is the overflow output projection of an
2269        // <Operation>WithOverflow node.
2270        if (ProjectionIndexOf(value->op()) == 1u) {
2271          // We cannot combine the <Operation>WithOverflow with this branch
2272          // unless the 0th projection (the use of the actual value of the
2273          // <Operation> is either nullptr, which means there's no use of the
2274          // actual value, or was already defined, which means it is scheduled
2275          // *AFTER* this branch).
2276          Node* const node = value->InputAt(0);
2277          Node* const result = NodeProperties::FindProjection(node, 0);
2278          if (result == nullptr || selector->IsDefined(result)) {
2279            switch (node->opcode()) {
2280              case IrOpcode::kInt32AddWithOverflow:
2281                cont->OverwriteAndNegateIfEqual(kOverflow);
2282                return VisitBinop(selector, node, kMips64Dadd, cont);
2283              case IrOpcode::kInt32SubWithOverflow:
2284                cont->OverwriteAndNegateIfEqual(kOverflow);
2285                return VisitBinop(selector, node, kMips64Dsub, cont);
2286              case IrOpcode::kInt32MulWithOverflow:
2287                cont->OverwriteAndNegateIfEqual(kOverflow);
2288                return VisitBinop(selector, node, kMips64MulOvf, cont);
2289              case IrOpcode::kInt64AddWithOverflow:
2290                cont->OverwriteAndNegateIfEqual(kOverflow);
2291                return VisitBinop(selector, node, kMips64DaddOvf, cont);
2292              case IrOpcode::kInt64SubWithOverflow:
2293                cont->OverwriteAndNegateIfEqual(kOverflow);
2294                return VisitBinop(selector, node, kMips64DsubOvf, cont);
2295              default:
2296                break;
2297            }
2298          }
2299        }
2300        break;
2301      case IrOpcode::kWord32And:
2302      case IrOpcode::kWord64And:
2303        return VisitWordCompare(selector, value, kMips64Tst, cont, true);
2304      default:
2305        break;
2306    }
2307  }
2308
2309  // Continuation could not be combined with a compare, emit compare against 0.
2310  EmitWordCompareZero(selector, value, cont);
2311}
2312
2313}  // namespace
2314
2315void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
2316                                      BasicBlock* fbranch) {
2317  FlagsContinuation cont(kNotEqual, tbranch, fbranch);
2318  VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
2319}
2320
2321void InstructionSelector::VisitDeoptimizeIf(Node* node) {
2322  DeoptimizeParameters p = DeoptimizeParametersOf(node->op());
2323  FlagsContinuation cont = FlagsContinuation::ForDeoptimize(
2324      kNotEqual, p.kind(), p.reason(), node->InputAt(1));
2325  VisitWordCompareZero(this, node, node->InputAt(0), &cont);
2326}
2327
2328void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
2329  DeoptimizeParameters p = DeoptimizeParametersOf(node->op());
2330  FlagsContinuation cont = FlagsContinuation::ForDeoptimize(
2331      kEqual, p.kind(), p.reason(), node->InputAt(1));
2332  VisitWordCompareZero(this, node, node->InputAt(0), &cont);
2333}
2334
2335void InstructionSelector::VisitTrapIf(Node* node, Runtime::FunctionId func_id) {
2336  FlagsContinuation cont =
2337      FlagsContinuation::ForTrap(kNotEqual, func_id, node->InputAt(1));
2338  VisitWordCompareZero(this, node, node->InputAt(0), &cont);
2339}
2340
2341void InstructionSelector::VisitTrapUnless(Node* node,
2342                                          Runtime::FunctionId func_id) {
2343  FlagsContinuation cont =
2344      FlagsContinuation::ForTrap(kEqual, func_id, node->InputAt(1));
2345  VisitWordCompareZero(this, node, node->InputAt(0), &cont);
2346}
2347
2348void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
2349  Mips64OperandGenerator g(this);
2350  InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
2351
2352  // Emit either ArchTableSwitch or ArchLookupSwitch.
2353  size_t table_space_cost = 10 + 2 * sw.value_range;
2354  size_t table_time_cost = 3;
2355  size_t lookup_space_cost = 2 + 2 * sw.case_count;
2356  size_t lookup_time_cost = sw.case_count;
2357  if (sw.case_count > 0 &&
2358      table_space_cost + 3 * table_time_cost <=
2359          lookup_space_cost + 3 * lookup_time_cost &&
2360      sw.min_value > std::numeric_limits<int32_t>::min()) {
2361    InstructionOperand index_operand = value_operand;
2362    if (sw.min_value) {
2363      index_operand = g.TempRegister();
2364      Emit(kMips64Sub, index_operand, value_operand,
2365           g.TempImmediate(sw.min_value));
2366    }
2367    // Generate a table lookup.
2368    return EmitTableSwitch(sw, index_operand);
2369  }
2370
2371  // Generate a sequence of conditional jumps.
2372  return EmitLookupSwitch(sw, value_operand);
2373}
2374
2375
2376void InstructionSelector::VisitWord32Equal(Node* const node) {
2377  FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2378  Int32BinopMatcher m(node);
2379  if (m.right().Is(0)) {
2380    return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
2381  }
2382
2383  VisitWord32Compare(this, node, &cont);
2384}
2385
2386
2387void InstructionSelector::VisitInt32LessThan(Node* node) {
2388  FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
2389  VisitWord32Compare(this, node, &cont);
2390}
2391
2392
2393void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
2394  FlagsContinuation cont =
2395      FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
2396  VisitWord32Compare(this, node, &cont);
2397}
2398
2399
2400void InstructionSelector::VisitUint32LessThan(Node* node) {
2401  FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
2402  VisitWord32Compare(this, node, &cont);
2403}
2404
2405
2406void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
2407  FlagsContinuation cont =
2408      FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
2409  VisitWord32Compare(this, node, &cont);
2410}
2411
2412
2413void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
2414  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2415    FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2416    return VisitBinop(this, node, kMips64Dadd, &cont);
2417  }
2418  FlagsContinuation cont;
2419  VisitBinop(this, node, kMips64Dadd, &cont);
2420}
2421
2422
2423void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
2424  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2425    FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2426    return VisitBinop(this, node, kMips64Dsub, &cont);
2427  }
2428  FlagsContinuation cont;
2429  VisitBinop(this, node, kMips64Dsub, &cont);
2430}
2431
2432void InstructionSelector::VisitInt32MulWithOverflow(Node* node) {
2433  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2434    FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2435    return VisitBinop(this, node, kMips64MulOvf, &cont);
2436  }
2437  FlagsContinuation cont;
2438  VisitBinop(this, node, kMips64MulOvf, &cont);
2439}
2440
2441void InstructionSelector::VisitInt64AddWithOverflow(Node* node) {
2442  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2443    FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2444    return VisitBinop(this, node, kMips64DaddOvf, &cont);
2445  }
2446  FlagsContinuation cont;
2447  VisitBinop(this, node, kMips64DaddOvf, &cont);
2448}
2449
2450
2451void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
2452  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2453    FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2454    return VisitBinop(this, node, kMips64DsubOvf, &cont);
2455  }
2456  FlagsContinuation cont;
2457  VisitBinop(this, node, kMips64DsubOvf, &cont);
2458}
2459
2460
2461void InstructionSelector::VisitWord64Equal(Node* const node) {
2462  FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2463  Int64BinopMatcher m(node);
2464  if (m.right().Is(0)) {
2465    return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
2466  }
2467
2468  VisitWord64Compare(this, node, &cont);
2469}
2470
2471
2472void InstructionSelector::VisitInt64LessThan(Node* node) {
2473  FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
2474  VisitWord64Compare(this, node, &cont);
2475}
2476
2477
2478void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
2479  FlagsContinuation cont =
2480      FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
2481  VisitWord64Compare(this, node, &cont);
2482}
2483
2484
2485void InstructionSelector::VisitUint64LessThan(Node* node) {
2486  FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
2487  VisitWord64Compare(this, node, &cont);
2488}
2489
2490
2491void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) {
2492  FlagsContinuation cont =
2493      FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
2494  VisitWord64Compare(this, node, &cont);
2495}
2496
2497
2498void InstructionSelector::VisitFloat32Equal(Node* node) {
2499  FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2500  VisitFloat32Compare(this, node, &cont);
2501}
2502
2503
2504void InstructionSelector::VisitFloat32LessThan(Node* node) {
2505  FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
2506  VisitFloat32Compare(this, node, &cont);
2507}
2508
2509
2510void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
2511  FlagsContinuation cont =
2512      FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
2513  VisitFloat32Compare(this, node, &cont);
2514}
2515
2516
2517void InstructionSelector::VisitFloat64Equal(Node* node) {
2518  FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2519  VisitFloat64Compare(this, node, &cont);
2520}
2521
2522
2523void InstructionSelector::VisitFloat64LessThan(Node* node) {
2524  FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
2525  VisitFloat64Compare(this, node, &cont);
2526}
2527
2528
2529void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
2530  FlagsContinuation cont =
2531      FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
2532  VisitFloat64Compare(this, node, &cont);
2533}
2534
2535
2536void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
2537  VisitRR(this, kMips64Float64ExtractLowWord32, node);
2538}
2539
2540
2541void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
2542  VisitRR(this, kMips64Float64ExtractHighWord32, node);
2543}
2544
2545void InstructionSelector::VisitFloat64SilenceNaN(Node* node) {
2546  VisitRR(this, kMips64Float64SilenceNaN, node);
2547}
2548
2549void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
2550  Mips64OperandGenerator g(this);
2551  Node* left = node->InputAt(0);
2552  Node* right = node->InputAt(1);
2553  Emit(kMips64Float64InsertLowWord32, g.DefineSameAsFirst(node),
2554       g.UseRegister(left), g.UseRegister(right));
2555}
2556
2557
2558void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
2559  Mips64OperandGenerator g(this);
2560  Node* left = node->InputAt(0);
2561  Node* right = node->InputAt(1);
2562  Emit(kMips64Float64InsertHighWord32, g.DefineSameAsFirst(node),
2563       g.UseRegister(left), g.UseRegister(right));
2564}
2565
2566void InstructionSelector::VisitAtomicLoad(Node* node) {
2567  LoadRepresentation load_rep = LoadRepresentationOf(node->op());
2568  Mips64OperandGenerator g(this);
2569  Node* base = node->InputAt(0);
2570  Node* index = node->InputAt(1);
2571  ArchOpcode opcode = kArchNop;
2572  switch (load_rep.representation()) {
2573    case MachineRepresentation::kWord8:
2574      opcode = load_rep.IsSigned() ? kAtomicLoadInt8 : kAtomicLoadUint8;
2575      break;
2576    case MachineRepresentation::kWord16:
2577      opcode = load_rep.IsSigned() ? kAtomicLoadInt16 : kAtomicLoadUint16;
2578      break;
2579    case MachineRepresentation::kWord32:
2580      opcode = kAtomicLoadWord32;
2581      break;
2582    default:
2583      UNREACHABLE();
2584      return;
2585  }
2586  if (g.CanBeImmediate(index, opcode)) {
2587    Emit(opcode | AddressingModeField::encode(kMode_MRI),
2588         g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
2589  } else {
2590    InstructionOperand addr_reg = g.TempRegister();
2591    Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
2592         g.UseRegister(index), g.UseRegister(base));
2593    // Emit desired load opcode, using temp addr_reg.
2594    Emit(opcode | AddressingModeField::encode(kMode_MRI),
2595         g.DefineAsRegister(node), addr_reg, g.TempImmediate(0));
2596  }
2597}
2598
2599void InstructionSelector::VisitAtomicStore(Node* node) {
2600  MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
2601  Mips64OperandGenerator g(this);
2602  Node* base = node->InputAt(0);
2603  Node* index = node->InputAt(1);
2604  Node* value = node->InputAt(2);
2605  ArchOpcode opcode = kArchNop;
2606  switch (rep) {
2607    case MachineRepresentation::kWord8:
2608      opcode = kAtomicStoreWord8;
2609      break;
2610    case MachineRepresentation::kWord16:
2611      opcode = kAtomicStoreWord16;
2612      break;
2613    case MachineRepresentation::kWord32:
2614      opcode = kAtomicStoreWord32;
2615      break;
2616    default:
2617      UNREACHABLE();
2618      return;
2619  }
2620
2621  if (g.CanBeImmediate(index, opcode)) {
2622    Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
2623         g.UseRegister(base), g.UseImmediate(index),
2624         g.UseRegisterOrImmediateZero(value));
2625  } else {
2626    InstructionOperand addr_reg = g.TempRegister();
2627    Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
2628         g.UseRegister(index), g.UseRegister(base));
2629    // Emit desired store opcode, using temp addr_reg.
2630    Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
2631         addr_reg, g.TempImmediate(0), g.UseRegisterOrImmediateZero(value));
2632  }
2633}
2634
2635// static
2636MachineOperatorBuilder::Flags
2637InstructionSelector::SupportedMachineOperatorFlags() {
2638  MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags;
2639  return flags | MachineOperatorBuilder::kWord32Ctz |
2640         MachineOperatorBuilder::kWord64Ctz |
2641         MachineOperatorBuilder::kWord32Popcnt |
2642         MachineOperatorBuilder::kWord64Popcnt |
2643         MachineOperatorBuilder::kWord32ShiftIsSafe |
2644         MachineOperatorBuilder::kInt32DivIsSafe |
2645         MachineOperatorBuilder::kUint32DivIsSafe |
2646         MachineOperatorBuilder::kFloat64RoundDown |
2647         MachineOperatorBuilder::kFloat32RoundDown |
2648         MachineOperatorBuilder::kFloat64RoundUp |
2649         MachineOperatorBuilder::kFloat32RoundUp |
2650         MachineOperatorBuilder::kFloat64RoundTruncate |
2651         MachineOperatorBuilder::kFloat32RoundTruncate |
2652         MachineOperatorBuilder::kFloat64RoundTiesEven |
2653         MachineOperatorBuilder::kFloat32RoundTiesEven |
2654         MachineOperatorBuilder::kWord32ReverseBytes |
2655         MachineOperatorBuilder::kWord64ReverseBytes;
2656}
2657
2658// static
2659MachineOperatorBuilder::AlignmentRequirements
2660InstructionSelector::AlignmentRequirements() {
2661  if (kArchVariant == kMips64r6) {
2662    return MachineOperatorBuilder::AlignmentRequirements::
2663        FullUnalignedAccessSupport();
2664  } else {
2665    DCHECK(kArchVariant == kMips64r2);
2666    return MachineOperatorBuilder::AlignmentRequirements::
2667        NoUnalignedAccessSupport();
2668  }
2669}
2670
2671}  // namespace compiler
2672}  // namespace internal
2673}  // namespace v8
2674