d723453c017518329fdb440bec63d62e6468a8d2
[platform/upstream/nodejs.git] / deps / v8 / src / compiler / mips / instruction-selector-mips.cc
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/bits.h"
6 #include "src/compiler/instruction-selector-impl.h"
7 #include "src/compiler/node-matchers.h"
8 #include "src/compiler/node-properties.h"
9
10 namespace v8 {
11 namespace internal {
12 namespace compiler {
13
14 #define TRACE_UNIMPL() \
15   PrintF("UNIMPLEMENTED instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
16
17 #define TRACE() PrintF("instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
18
19
20 // Adds Mips-specific methods for generating InstructionOperands.
21 class MipsOperandGenerator FINAL : public OperandGenerator {
22  public:
23   explicit MipsOperandGenerator(InstructionSelector* selector)
24       : OperandGenerator(selector) {}
25
26   InstructionOperand UseOperand(Node* node, InstructionCode opcode) {
27     if (CanBeImmediate(node, opcode)) {
28       return UseImmediate(node);
29     }
30     return UseRegister(node);
31   }
32
33   bool CanBeImmediate(Node* node, InstructionCode opcode) {
34     Int32Matcher m(node);
35     if (!m.HasValue()) return false;
36     int32_t value = m.Value();
37     switch (ArchOpcodeField::decode(opcode)) {
38       case kMipsShl:
39       case kMipsSar:
40       case kMipsShr:
41         return is_uint5(value);
42       case kMipsXor:
43         return is_uint16(value);
44       case kMipsLdc1:
45       case kMipsSdc1:
46       case kCheckedLoadFloat32:
47       case kCheckedLoadFloat64:
48       case kCheckedStoreFloat32:
49       case kCheckedStoreFloat64:
50         return is_int16(value + kIntSize);
51       default:
52         return is_int16(value);
53     }
54   }
55
56  private:
57   bool ImmediateFitsAddrMode1Instruction(int32_t imm) const {
58     TRACE_UNIMPL();
59     return false;
60   }
61 };
62
63
64 static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
65                      Node* node) {
66   MipsOperandGenerator g(selector);
67   selector->Emit(opcode, g.DefineAsRegister(node),
68                  g.UseRegister(node->InputAt(0)),
69                  g.UseRegister(node->InputAt(1)));
70 }
71
72
73 static void VisitRR(InstructionSelector* selector, ArchOpcode opcode,
74                     Node* node) {
75   MipsOperandGenerator g(selector);
76   selector->Emit(opcode, g.DefineAsRegister(node),
77                  g.UseRegister(node->InputAt(0)));
78 }
79
80
81 static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode,
82                      Node* node) {
83   MipsOperandGenerator g(selector);
84   selector->Emit(opcode, g.DefineAsRegister(node),
85                  g.UseRegister(node->InputAt(0)),
86                  g.UseOperand(node->InputAt(1), opcode));
87 }
88
89
90 static void VisitBinop(InstructionSelector* selector, Node* node,
91                        InstructionCode opcode, FlagsContinuation* cont) {
92   MipsOperandGenerator g(selector);
93   Int32BinopMatcher m(node);
94   InstructionOperand inputs[4];
95   size_t input_count = 0;
96   InstructionOperand outputs[2];
97   size_t output_count = 0;
98
99   inputs[input_count++] = g.UseRegister(m.left().node());
100   inputs[input_count++] = g.UseOperand(m.right().node(), opcode);
101
102   if (cont->IsBranch()) {
103     inputs[input_count++] = g.Label(cont->true_block());
104     inputs[input_count++] = g.Label(cont->false_block());
105   }
106
107   outputs[output_count++] = g.DefineAsRegister(node);
108   if (cont->IsSet()) {
109     outputs[output_count++] = g.DefineAsRegister(cont->result());
110   }
111
112   DCHECK_NE(0u, input_count);
113   DCHECK_NE(0u, output_count);
114   DCHECK_GE(arraysize(inputs), input_count);
115   DCHECK_GE(arraysize(outputs), output_count);
116
117   Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
118                                       outputs, input_count, inputs);
119   if (cont->IsBranch()) instr->MarkAsControl();
120 }
121
122
123 static void VisitBinop(InstructionSelector* selector, Node* node,
124                        InstructionCode opcode) {
125   FlagsContinuation cont;
126   VisitBinop(selector, node, opcode, &cont);
127 }
128
129
130 void InstructionSelector::VisitLoad(Node* node) {
131   MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
132   MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
133   MipsOperandGenerator g(this);
134   Node* base = node->InputAt(0);
135   Node* index = node->InputAt(1);
136
137   ArchOpcode opcode;
138   switch (rep) {
139     case kRepFloat32:
140       opcode = kMipsLwc1;
141       break;
142     case kRepFloat64:
143       opcode = kMipsLdc1;
144       break;
145     case kRepBit:  // Fall through.
146     case kRepWord8:
147       opcode = typ == kTypeUint32 ? kMipsLbu : kMipsLb;
148       break;
149     case kRepWord16:
150       opcode = typ == kTypeUint32 ? kMipsLhu : kMipsLh;
151       break;
152     case kRepTagged:  // Fall through.
153     case kRepWord32:
154       opcode = kMipsLw;
155       break;
156     default:
157       UNREACHABLE();
158       return;
159   }
160
161   if (g.CanBeImmediate(index, opcode)) {
162     Emit(opcode | AddressingModeField::encode(kMode_MRI),
163          g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
164   } else {
165     InstructionOperand addr_reg = g.TempRegister();
166     Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
167          g.UseRegister(index), g.UseRegister(base));
168     // Emit desired load opcode, using temp addr_reg.
169     Emit(opcode | AddressingModeField::encode(kMode_MRI),
170          g.DefineAsRegister(node), addr_reg, g.TempImmediate(0));
171   }
172 }
173
174
175 void InstructionSelector::VisitStore(Node* node) {
176   MipsOperandGenerator g(this);
177   Node* base = node->InputAt(0);
178   Node* index = node->InputAt(1);
179   Node* value = node->InputAt(2);
180
181   StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
182   MachineType rep = RepresentationOf(store_rep.machine_type());
183   if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
184     DCHECK(rep == kRepTagged);
185     // TODO(dcarney): refactor RecordWrite function to take temp registers
186     //                and pass them here instead of using fixed regs
187     // TODO(dcarney): handle immediate indices.
188     InstructionOperand temps[] = {g.TempRegister(t1), g.TempRegister(t2)};
189     Emit(kMipsStoreWriteBarrier, g.NoOutput(), g.UseFixed(base, t0),
190          g.UseFixed(index, t1), g.UseFixed(value, t2), arraysize(temps), temps);
191     return;
192   }
193   DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
194
195   ArchOpcode opcode;
196   switch (rep) {
197     case kRepFloat32:
198       opcode = kMipsSwc1;
199       break;
200     case kRepFloat64:
201       opcode = kMipsSdc1;
202       break;
203     case kRepBit:  // Fall through.
204     case kRepWord8:
205       opcode = kMipsSb;
206       break;
207     case kRepWord16:
208       opcode = kMipsSh;
209       break;
210     case kRepTagged:  // Fall through.
211     case kRepWord32:
212       opcode = kMipsSw;
213       break;
214     default:
215       UNREACHABLE();
216       return;
217   }
218
219   if (g.CanBeImmediate(index, opcode)) {
220     Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
221          g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
222   } else {
223     InstructionOperand addr_reg = g.TempRegister();
224     Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
225          g.UseRegister(index), g.UseRegister(base));
226     // Emit desired store opcode, using temp addr_reg.
227     Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
228          addr_reg, g.TempImmediate(0), g.UseRegister(value));
229   }
230 }
231
232
233 void InstructionSelector::VisitWord32And(Node* node) {
234   VisitBinop(this, node, kMipsAnd);
235 }
236
237
238 void InstructionSelector::VisitWord32Or(Node* node) {
239   VisitBinop(this, node, kMipsOr);
240 }
241
242
243 void InstructionSelector::VisitWord32Xor(Node* node) {
244   VisitBinop(this, node, kMipsXor);
245 }
246
247
248 void InstructionSelector::VisitWord32Shl(Node* node) {
249   VisitRRO(this, kMipsShl, node);
250 }
251
252
253 void InstructionSelector::VisitWord32Shr(Node* node) {
254   VisitRRO(this, kMipsShr, node);
255 }
256
257
258 void InstructionSelector::VisitWord32Sar(Node* node) {
259   VisitRRO(this, kMipsSar, node);
260 }
261
262
263 void InstructionSelector::VisitWord32Ror(Node* node) {
264   VisitRRO(this, kMipsRor, node);
265 }
266
267
268 void InstructionSelector::VisitInt32Add(Node* node) {
269   MipsOperandGenerator g(this);
270
271   // TODO(plind): Consider multiply & add optimization from arm port.
272   VisitBinop(this, node, kMipsAdd);
273 }
274
275
276 void InstructionSelector::VisitInt32Sub(Node* node) {
277   VisitBinop(this, node, kMipsSub);
278 }
279
280
281 void InstructionSelector::VisitInt32Mul(Node* node) {
282   MipsOperandGenerator g(this);
283   Int32BinopMatcher m(node);
284   if (m.right().HasValue() && m.right().Value() > 0) {
285     int32_t value = m.right().Value();
286     if (base::bits::IsPowerOfTwo32(value)) {
287       Emit(kMipsShl | AddressingModeField::encode(kMode_None),
288            g.DefineAsRegister(node), g.UseRegister(m.left().node()),
289            g.TempImmediate(WhichPowerOf2(value)));
290       return;
291     }
292     if (base::bits::IsPowerOfTwo32(value - 1)) {
293       InstructionOperand temp = g.TempRegister();
294       Emit(kMipsShl | AddressingModeField::encode(kMode_None), temp,
295            g.UseRegister(m.left().node()),
296            g.TempImmediate(WhichPowerOf2(value - 1)));
297       Emit(kMipsAdd | AddressingModeField::encode(kMode_None),
298            g.DefineAsRegister(node), g.UseRegister(m.left().node()), temp);
299       return;
300     }
301     if (base::bits::IsPowerOfTwo32(value + 1)) {
302       InstructionOperand temp = g.TempRegister();
303       Emit(kMipsShl | AddressingModeField::encode(kMode_None), temp,
304            g.UseRegister(m.left().node()),
305            g.TempImmediate(WhichPowerOf2(value + 1)));
306       Emit(kMipsSub | AddressingModeField::encode(kMode_None),
307            g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
308       return;
309     }
310   }
311   Emit(kMipsMul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
312        g.UseRegister(m.right().node()));
313 }
314
315
316 void InstructionSelector::VisitInt32MulHigh(Node* node) {
317   MipsOperandGenerator g(this);
318   Emit(kMipsMulHigh, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
319        g.UseRegister(node->InputAt(1)));
320 }
321
322
323 void InstructionSelector::VisitUint32MulHigh(Node* node) {
324   MipsOperandGenerator g(this);
325   Emit(kMipsMulHighU, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
326        g.UseRegister(node->InputAt(1)));
327 }
328
329
330 void InstructionSelector::VisitInt32Div(Node* node) {
331   MipsOperandGenerator g(this);
332   Int32BinopMatcher m(node);
333   Emit(kMipsDiv, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
334        g.UseRegister(m.right().node()));
335 }
336
337
338 void InstructionSelector::VisitUint32Div(Node* node) {
339   MipsOperandGenerator g(this);
340   Int32BinopMatcher m(node);
341   Emit(kMipsDivU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
342        g.UseRegister(m.right().node()));
343 }
344
345
346 void InstructionSelector::VisitInt32Mod(Node* node) {
347   MipsOperandGenerator g(this);
348   Int32BinopMatcher m(node);
349   Emit(kMipsMod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
350        g.UseRegister(m.right().node()));
351 }
352
353
354 void InstructionSelector::VisitUint32Mod(Node* node) {
355   MipsOperandGenerator g(this);
356   Int32BinopMatcher m(node);
357   Emit(kMipsModU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
358        g.UseRegister(m.right().node()));
359 }
360
361
362 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
363   MipsOperandGenerator g(this);
364   Emit(kMipsCvtDS, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
365 }
366
367
368 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
369   MipsOperandGenerator g(this);
370   Emit(kMipsCvtDW, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
371 }
372
373
374 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
375   MipsOperandGenerator g(this);
376   Emit(kMipsCvtDUw, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
377 }
378
379
380 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
381   MipsOperandGenerator g(this);
382   Emit(kMipsTruncWD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
383 }
384
385
386 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
387   MipsOperandGenerator g(this);
388   Emit(kMipsTruncUwD, g.DefineAsRegister(node),
389        g.UseRegister(node->InputAt(0)));
390 }
391
392
393 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
394   MipsOperandGenerator g(this);
395   Emit(kMipsCvtSD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
396 }
397
398
399 void InstructionSelector::VisitFloat64Add(Node* node) {
400   VisitRRR(this, kMipsAddD, node);
401 }
402
403
404 void InstructionSelector::VisitFloat64Sub(Node* node) {
405   VisitRRR(this, kMipsSubD, node);
406 }
407
408
409 void InstructionSelector::VisitFloat64Mul(Node* node) {
410   VisitRRR(this, kMipsMulD, node);
411 }
412
413
414 void InstructionSelector::VisitFloat64Div(Node* node) {
415   VisitRRR(this, kMipsDivD, node);
416 }
417
418
419 void InstructionSelector::VisitFloat64Mod(Node* node) {
420   MipsOperandGenerator g(this);
421   Emit(kMipsModD, g.DefineAsFixed(node, f0), g.UseFixed(node->InputAt(0), f12),
422        g.UseFixed(node->InputAt(1), f14))->MarkAsCall();
423 }
424
425
426 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
427   MipsOperandGenerator g(this);
428   Emit(kMipsSqrtD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
429 }
430
431
432 void InstructionSelector::VisitFloat64Floor(Node* node) {
433   VisitRR(this, kMipsFloat64Floor, node);
434 }
435
436
437 void InstructionSelector::VisitFloat64Ceil(Node* node) {
438   VisitRR(this, kMipsFloat64Ceil, node);
439 }
440
441
442 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
443   VisitRR(this, kMipsFloat64RoundTruncate, node);
444 }
445
446
447 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
448   UNREACHABLE();
449 }
450
451
452 void InstructionSelector::VisitCall(Node* node) {
453   MipsOperandGenerator g(this);
454   const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
455
456   FrameStateDescriptor* frame_state_descriptor = NULL;
457   if (descriptor->NeedsFrameState()) {
458     frame_state_descriptor =
459         GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
460   }
461
462   CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
463
464   // Compute InstructionOperands for inputs and outputs.
465   InitializeCallBuffer(node, &buffer, true, false);
466   // Possibly align stack here for functions.
467   int push_count = buffer.pushed_nodes.size();
468   if (push_count > 0) {
469     Emit(kMipsStackClaim | MiscField::encode(push_count), g.NoOutput());
470   }
471   int slot = buffer.pushed_nodes.size() - 1;
472   for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
473        ++i) {
474     Emit(kMipsStoreToStackSlot | MiscField::encode(slot), g.NoOutput(),
475          g.UseRegister(*i));
476     slot--;
477   }
478
479   // Select the appropriate opcode based on the call type.
480   InstructionCode opcode;
481   switch (descriptor->kind()) {
482     case CallDescriptor::kCallCodeObject: {
483       opcode = kArchCallCodeObject;
484       break;
485     }
486     case CallDescriptor::kCallJSFunction:
487       opcode = kArchCallJSFunction;
488       break;
489     default:
490       UNREACHABLE();
491       return;
492   }
493   opcode |= MiscField::encode(descriptor->flags());
494
495   // Emit the call instruction.
496   InstructionOperand* first_output =
497       buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
498   Instruction* call_instr =
499       Emit(opcode, buffer.outputs.size(), first_output,
500            buffer.instruction_args.size(), &buffer.instruction_args.front());
501   call_instr->MarkAsCall();
502 }
503
504
505 void InstructionSelector::VisitCheckedLoad(Node* node) {
506   MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
507   MachineType typ = TypeOf(OpParameter<MachineType>(node));
508   MipsOperandGenerator g(this);
509   Node* const buffer = node->InputAt(0);
510   Node* const offset = node->InputAt(1);
511   Node* const length = node->InputAt(2);
512   ArchOpcode opcode;
513   switch (rep) {
514     case kRepWord8:
515       opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
516       break;
517     case kRepWord16:
518       opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
519       break;
520     case kRepWord32:
521       opcode = kCheckedLoadWord32;
522       break;
523     case kRepFloat32:
524       opcode = kCheckedLoadFloat32;
525       break;
526     case kRepFloat64:
527       opcode = kCheckedLoadFloat64;
528       break;
529     default:
530       UNREACHABLE();
531       return;
532   }
533   InstructionOperand offset_operand = g.CanBeImmediate(offset, opcode)
534                                           ? g.UseImmediate(offset)
535                                           : g.UseRegister(offset);
536
537   InstructionOperand length_operand = (!g.CanBeImmediate(offset, opcode))
538                                           ? g.CanBeImmediate(length, opcode)
539                                                 ? g.UseImmediate(length)
540                                                 : g.UseRegister(length)
541                                           : g.UseRegister(length);
542
543   Emit(opcode | AddressingModeField::encode(kMode_MRI),
544        g.DefineAsRegister(node), offset_operand, length_operand,
545        g.UseRegister(buffer));
546 }
547
548
549 void InstructionSelector::VisitCheckedStore(Node* node) {
550   MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
551   MipsOperandGenerator g(this);
552   Node* const buffer = node->InputAt(0);
553   Node* const offset = node->InputAt(1);
554   Node* const length = node->InputAt(2);
555   Node* const value = node->InputAt(3);
556   ArchOpcode opcode;
557   switch (rep) {
558     case kRepWord8:
559       opcode = kCheckedStoreWord8;
560       break;
561     case kRepWord16:
562       opcode = kCheckedStoreWord16;
563       break;
564     case kRepWord32:
565       opcode = kCheckedStoreWord32;
566       break;
567     case kRepFloat32:
568       opcode = kCheckedStoreFloat32;
569       break;
570     case kRepFloat64:
571       opcode = kCheckedStoreFloat64;
572       break;
573     default:
574       UNREACHABLE();
575       return;
576   }
577   InstructionOperand offset_operand = g.CanBeImmediate(offset, opcode)
578                                           ? g.UseImmediate(offset)
579                                           : g.UseRegister(offset);
580
581   InstructionOperand length_operand = (!g.CanBeImmediate(offset, opcode))
582                                           ? g.CanBeImmediate(length, opcode)
583                                                 ? g.UseImmediate(length)
584                                                 : g.UseRegister(length)
585                                           : g.UseRegister(length);
586
587   Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
588        offset_operand, length_operand, g.UseRegister(value),
589        g.UseRegister(buffer));
590 }
591
592
593 namespace {
594
595 // Shared routine for multiple compare operations.
596 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
597                          InstructionOperand left, InstructionOperand right,
598                          FlagsContinuation* cont) {
599   MipsOperandGenerator g(selector);
600   opcode = cont->Encode(opcode);
601   if (cont->IsBranch()) {
602     selector->Emit(opcode, g.NoOutput(), left, right,
603                    g.Label(cont->true_block()),
604                    g.Label(cont->false_block()))->MarkAsControl();
605   } else {
606     DCHECK(cont->IsSet());
607     // TODO(plind): Revisit and test this path.
608     selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
609   }
610 }
611
612
613 // Shared routine for multiple float compare operations.
614 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
615                          FlagsContinuation* cont) {
616   MipsOperandGenerator g(selector);
617   Node* left = node->InputAt(0);
618   Node* right = node->InputAt(1);
619   VisitCompare(selector, kMipsCmpD, g.UseRegister(left), g.UseRegister(right),
620                cont);
621 }
622
623
624 // Shared routine for multiple word compare operations.
625 void VisitWordCompare(InstructionSelector* selector, Node* node,
626                       InstructionCode opcode, FlagsContinuation* cont,
627                       bool commutative) {
628   MipsOperandGenerator g(selector);
629   Node* left = node->InputAt(0);
630   Node* right = node->InputAt(1);
631
632   // Match immediates on left or right side of comparison.
633   if (g.CanBeImmediate(right, opcode)) {
634     VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
635                  cont);
636   } else if (g.CanBeImmediate(left, opcode)) {
637     if (!commutative) cont->Commute();
638     VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
639                  cont);
640   } else {
641     VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
642                  cont);
643   }
644 }
645
646
647 void VisitWordCompare(InstructionSelector* selector, Node* node,
648                       FlagsContinuation* cont) {
649   VisitWordCompare(selector, node, kMipsCmp, cont, false);
650 }
651
652 }  // namespace
653
654
655 // Shared routine for word comparisons against zero.
656 void VisitWordCompareZero(InstructionSelector* selector, Node* user,
657                           Node* value, FlagsContinuation* cont) {
658   while (selector->CanCover(user, value)) {
659     switch (value->opcode()) {
660       case IrOpcode::kWord32Equal: {
661         // Combine with comparisons against 0 by simply inverting the
662         // continuation.
663         Int32BinopMatcher m(value);
664         if (m.right().Is(0)) {
665           user = value;
666           value = m.left().node();
667           cont->Negate();
668           continue;
669         }
670         cont->OverwriteAndNegateIfEqual(kEqual);
671         return VisitWordCompare(selector, value, cont);
672       }
673       case IrOpcode::kInt32LessThan:
674         cont->OverwriteAndNegateIfEqual(kSignedLessThan);
675         return VisitWordCompare(selector, value, cont);
676       case IrOpcode::kInt32LessThanOrEqual:
677         cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
678         return VisitWordCompare(selector, value, cont);
679       case IrOpcode::kUint32LessThan:
680         cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
681         return VisitWordCompare(selector, value, cont);
682       case IrOpcode::kUint32LessThanOrEqual:
683         cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
684         return VisitWordCompare(selector, value, cont);
685       case IrOpcode::kFloat64Equal:
686         cont->OverwriteAndNegateIfEqual(kEqual);
687         return VisitFloat64Compare(selector, value, cont);
688       case IrOpcode::kFloat64LessThan:
689         cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
690         return VisitFloat64Compare(selector, value, cont);
691       case IrOpcode::kFloat64LessThanOrEqual:
692         cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
693         return VisitFloat64Compare(selector, value, cont);
694       case IrOpcode::kProjection:
695         // Check if this is the overflow output projection of an
696         // <Operation>WithOverflow node.
697         if (ProjectionIndexOf(value->op()) == 1u) {
698           // We cannot combine the <Operation>WithOverflow with this branch
699           // unless the 0th projection (the use of the actual value of the
700           // <Operation> is either NULL, which means there's no use of the
701           // actual value, or was already defined, which means it is scheduled
702           // *AFTER* this branch).
703           Node* const node = value->InputAt(0);
704           Node* const result = NodeProperties::FindProjection(node, 0);
705           if (!result || selector->IsDefined(result)) {
706             switch (node->opcode()) {
707               case IrOpcode::kInt32AddWithOverflow:
708                 cont->OverwriteAndNegateIfEqual(kOverflow);
709                 return VisitBinop(selector, node, kMipsAddOvf, cont);
710               case IrOpcode::kInt32SubWithOverflow:
711                 cont->OverwriteAndNegateIfEqual(kOverflow);
712                 return VisitBinop(selector, node, kMipsSubOvf, cont);
713               default:
714                 break;
715             }
716           }
717         }
718         break;
719       case IrOpcode::kWord32And:
720         return VisitWordCompare(selector, value, kMipsTst, cont, true);
721       default:
722         break;
723     }
724     break;
725   }
726
727   // Continuation could not be combined with a compare, emit compare against 0.
728   MipsOperandGenerator g(selector);
729   InstructionCode const opcode = cont->Encode(kMipsCmp);
730   InstructionOperand const value_operand = g.UseRegister(value);
731   if (cont->IsBranch()) {
732     selector->Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
733                    g.Label(cont->true_block()),
734                    g.Label(cont->false_block()))->MarkAsControl();
735   } else {
736     selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
737                    g.TempImmediate(0));
738   }
739 }
740
741
742 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
743                                       BasicBlock* fbranch) {
744   FlagsContinuation cont(kNotEqual, tbranch, fbranch);
745   VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
746 }
747
748
749 void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
750                                       BasicBlock** case_branches,
751                                       int32_t* case_values, size_t case_count,
752                                       int32_t min_value, int32_t max_value) {
753   MipsOperandGenerator g(this);
754   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
755   InstructionOperand default_operand = g.Label(default_branch);
756
757   // Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value}
758   // is 2^31-1, so don't assume that it's non-zero below.
759   size_t value_range =
760       1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
761
762   // Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
763   // instruction.
764   size_t table_space_cost = 9 + value_range;
765   size_t table_time_cost = 9;
766   size_t lookup_space_cost = 2 + 2 * case_count;
767   size_t lookup_time_cost = case_count;
768   if (case_count > 0 &&
769       table_space_cost + 3 * table_time_cost <=
770           lookup_space_cost + 3 * lookup_time_cost &&
771       min_value > std::numeric_limits<int32_t>::min()) {
772     InstructionOperand index_operand = value_operand;
773     if (min_value) {
774       index_operand = g.TempRegister();
775       Emit(kMipsSub, index_operand, value_operand, g.TempImmediate(min_value));
776     }
777     size_t input_count = 2 + value_range;
778     auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
779     inputs[0] = index_operand;
780     std::fill(&inputs[1], &inputs[input_count], default_operand);
781     for (size_t index = 0; index < case_count; ++index) {
782       size_t value = case_values[index] - min_value;
783       BasicBlock* branch = case_branches[index];
784       DCHECK_LE(0u, value);
785       DCHECK_LT(value + 2, input_count);
786       inputs[value + 2] = g.Label(branch);
787     }
788     Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
789         ->MarkAsControl();
790     return;
791   }
792
793   // Generate a sequence of conditional jumps.
794   size_t input_count = 2 + case_count * 2;
795   auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
796   inputs[0] = value_operand;
797   inputs[1] = default_operand;
798   for (size_t index = 0; index < case_count; ++index) {
799     int32_t value = case_values[index];
800     BasicBlock* branch = case_branches[index];
801     inputs[index * 2 + 2 + 0] = g.TempImmediate(value);
802     inputs[index * 2 + 2 + 1] = g.Label(branch);
803   }
804   Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
805       ->MarkAsControl();
806 }
807
808
809 void InstructionSelector::VisitWord32Equal(Node* const node) {
810   FlagsContinuation cont(kEqual, node);
811   Int32BinopMatcher m(node);
812   if (m.right().Is(0)) {
813     return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
814   }
815   VisitWordCompare(this, node, &cont);
816 }
817
818
819 void InstructionSelector::VisitInt32LessThan(Node* node) {
820   FlagsContinuation cont(kSignedLessThan, node);
821   VisitWordCompare(this, node, &cont);
822 }
823
824
825 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
826   FlagsContinuation cont(kSignedLessThanOrEqual, node);
827   VisitWordCompare(this, node, &cont);
828 }
829
830
831 void InstructionSelector::VisitUint32LessThan(Node* node) {
832   FlagsContinuation cont(kUnsignedLessThan, node);
833   VisitWordCompare(this, node, &cont);
834 }
835
836
837 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
838   FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
839   VisitWordCompare(this, node, &cont);
840 }
841
842
843 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
844   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
845     FlagsContinuation cont(kOverflow, ovf);
846     return VisitBinop(this, node, kMipsAddOvf, &cont);
847   }
848   FlagsContinuation cont;
849   VisitBinop(this, node, kMipsAddOvf, &cont);
850 }
851
852
853 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
854   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
855     FlagsContinuation cont(kOverflow, ovf);
856     return VisitBinop(this, node, kMipsSubOvf, &cont);
857   }
858   FlagsContinuation cont;
859   VisitBinop(this, node, kMipsSubOvf, &cont);
860 }
861
862
863 void InstructionSelector::VisitFloat64Equal(Node* node) {
864   FlagsContinuation cont(kEqual, node);
865   VisitFloat64Compare(this, node, &cont);
866 }
867
868
869 void InstructionSelector::VisitFloat64LessThan(Node* node) {
870   FlagsContinuation cont(kUnsignedLessThan, node);
871   VisitFloat64Compare(this, node, &cont);
872 }
873
874
875 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
876   FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
877   VisitFloat64Compare(this, node, &cont);
878 }
879
880
881 // static
882 MachineOperatorBuilder::Flags
883 InstructionSelector::SupportedMachineOperatorFlags() {
884   if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
885     return MachineOperatorBuilder::kFloat64Floor |
886            MachineOperatorBuilder::kFloat64Ceil |
887            MachineOperatorBuilder::kFloat64RoundTruncate;
888   }
889   return MachineOperatorBuilder::kNoFlags;
890 }
891
892 }  // namespace compiler
893 }  // namespace internal
894 }  // namespace v8