deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / compiler / arm / instruction-selector-arm.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 // Adds Arm-specific methods for generating InstructionOperands.
15 class ArmOperandGenerator : public OperandGenerator {
16  public:
17   explicit ArmOperandGenerator(InstructionSelector* selector)
18       : OperandGenerator(selector) {}
19
20   bool CanBeImmediate(int32_t value) const {
21     return Assembler::ImmediateFitsAddrMode1Instruction(value);
22   }
23
24   bool CanBeImmediate(uint32_t value) const {
25     return CanBeImmediate(bit_cast<int32_t>(value));
26   }
27
28   bool CanBeImmediate(Node* node, InstructionCode opcode) {
29     Int32Matcher m(node);
30     if (!m.HasValue()) return false;
31     int32_t value = m.Value();
32     switch (ArchOpcodeField::decode(opcode)) {
33       case kArmAnd:
34       case kArmMov:
35       case kArmMvn:
36       case kArmBic:
37         return CanBeImmediate(value) || CanBeImmediate(~value);
38
39       case kArmAdd:
40       case kArmSub:
41       case kArmCmp:
42       case kArmCmn:
43         return CanBeImmediate(value) || CanBeImmediate(-value);
44
45       case kArmTst:
46       case kArmTeq:
47       case kArmOrr:
48       case kArmEor:
49       case kArmRsb:
50         return CanBeImmediate(value);
51
52       case kArmVldrF32:
53       case kArmVstrF32:
54       case kArmVldrF64:
55       case kArmVstrF64:
56         return value >= -1020 && value <= 1020 && (value % 4) == 0;
57
58       case kArmLdrb:
59       case kArmLdrsb:
60       case kArmStrb:
61       case kArmLdr:
62       case kArmStr:
63       case kArmStoreWriteBarrier:
64         return value >= -4095 && value <= 4095;
65
66       case kArmLdrh:
67       case kArmLdrsh:
68       case kArmStrh:
69         return value >= -255 && value <= 255;
70
71       default:
72         break;
73     }
74     return false;
75   }
76 };
77
78
79 namespace {
80
81 void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
82                     Node* node) {
83   ArmOperandGenerator g(selector);
84   selector->Emit(opcode, g.DefineAsRegister(node),
85                  g.UseRegister(node->InputAt(0)));
86 }
87
88
89 void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
90                      Node* node) {
91   ArmOperandGenerator g(selector);
92   selector->Emit(opcode, g.DefineAsRegister(node),
93                  g.UseRegister(node->InputAt(0)),
94                  g.UseRegister(node->InputAt(1)));
95 }
96
97
98 template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax,
99           AddressingMode kImmMode, AddressingMode kRegMode>
100 bool TryMatchShift(InstructionSelector* selector,
101                    InstructionCode* opcode_return, Node* node,
102                    InstructionOperand* value_return,
103                    InstructionOperand* shift_return) {
104   ArmOperandGenerator g(selector);
105   if (node->opcode() == kOpcode) {
106     Int32BinopMatcher m(node);
107     *value_return = g.UseRegister(m.left().node());
108     if (m.right().IsInRange(kImmMin, kImmMax)) {
109       *opcode_return |= AddressingModeField::encode(kImmMode);
110       *shift_return = g.UseImmediate(m.right().node());
111     } else {
112       *opcode_return |= AddressingModeField::encode(kRegMode);
113       *shift_return = g.UseRegister(m.right().node());
114     }
115     return true;
116   }
117   return false;
118 }
119
120
121 bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return,
122                  Node* node, InstructionOperand* value_return,
123                  InstructionOperand* shift_return) {
124   return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I,
125                        kMode_Operand2_R_ROR_R>(selector, opcode_return, node,
126                                                value_return, shift_return);
127 }
128
129
130 bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return,
131                  Node* node, InstructionOperand* value_return,
132                  InstructionOperand* shift_return) {
133   return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I,
134                        kMode_Operand2_R_ASR_R>(selector, opcode_return, node,
135                                                value_return, shift_return);
136 }
137
138
139 bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return,
140                  Node* node, InstructionOperand* value_return,
141                  InstructionOperand* shift_return) {
142   return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I,
143                        kMode_Operand2_R_LSL_R>(selector, opcode_return, node,
144                                                value_return, shift_return);
145 }
146
147
148 bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return,
149                  Node* node, InstructionOperand* value_return,
150                  InstructionOperand* shift_return) {
151   return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I,
152                        kMode_Operand2_R_LSR_R>(selector, opcode_return, node,
153                                                value_return, shift_return);
154 }
155
156
157 bool TryMatchShift(InstructionSelector* selector,
158                    InstructionCode* opcode_return, Node* node,
159                    InstructionOperand* value_return,
160                    InstructionOperand* shift_return) {
161   return (
162       TryMatchASR(selector, opcode_return, node, value_return, shift_return) ||
163       TryMatchLSL(selector, opcode_return, node, value_return, shift_return) ||
164       TryMatchLSR(selector, opcode_return, node, value_return, shift_return) ||
165       TryMatchROR(selector, opcode_return, node, value_return, shift_return));
166 }
167
168
169 bool TryMatchImmediateOrShift(InstructionSelector* selector,
170                               InstructionCode* opcode_return, Node* node,
171                               size_t* input_count_return,
172                               InstructionOperand* inputs) {
173   ArmOperandGenerator g(selector);
174   if (g.CanBeImmediate(node, *opcode_return)) {
175     *opcode_return |= AddressingModeField::encode(kMode_Operand2_I);
176     inputs[0] = g.UseImmediate(node);
177     *input_count_return = 1;
178     return true;
179   }
180   if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) {
181     *input_count_return = 2;
182     return true;
183   }
184   return false;
185 }
186
187
188 void VisitBinop(InstructionSelector* selector, Node* node,
189                 InstructionCode opcode, InstructionCode reverse_opcode,
190                 FlagsContinuation* cont) {
191   ArmOperandGenerator g(selector);
192   Int32BinopMatcher m(node);
193   InstructionOperand inputs[5];
194   size_t input_count = 0;
195   InstructionOperand outputs[2];
196   size_t output_count = 0;
197
198   if (m.left().node() == m.right().node()) {
199     // If both inputs refer to the same operand, enforce allocating a register
200     // for both of them to ensure that we don't end up generating code like
201     // this:
202     //
203     //   mov r0, r1, asr #16
204     //   adds r0, r0, r1, asr #16
205     //   bvs label
206     InstructionOperand const input = g.UseRegister(m.left().node());
207     opcode |= AddressingModeField::encode(kMode_Operand2_R);
208     inputs[input_count++] = input;
209     inputs[input_count++] = input;
210   } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
211                                       &input_count, &inputs[1])) {
212     inputs[0] = g.UseRegister(m.left().node());
213     input_count++;
214   } else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
215                                       m.left().node(), &input_count,
216                                       &inputs[1])) {
217     inputs[0] = g.UseRegister(m.right().node());
218     opcode = reverse_opcode;
219     input_count++;
220   } else {
221     opcode |= AddressingModeField::encode(kMode_Operand2_R);
222     inputs[input_count++] = g.UseRegister(m.left().node());
223     inputs[input_count++] = g.UseRegister(m.right().node());
224   }
225
226   if (cont->IsBranch()) {
227     inputs[input_count++] = g.Label(cont->true_block());
228     inputs[input_count++] = g.Label(cont->false_block());
229   }
230
231   outputs[output_count++] = g.DefineAsRegister(node);
232   if (cont->IsSet()) {
233     outputs[output_count++] = g.DefineAsRegister(cont->result());
234   }
235
236   DCHECK_NE(0u, input_count);
237   DCHECK_NE(0u, output_count);
238   DCHECK_GE(arraysize(inputs), input_count);
239   DCHECK_GE(arraysize(outputs), output_count);
240   DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
241
242   selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
243                  inputs);
244 }
245
246
247 void VisitBinop(InstructionSelector* selector, Node* node,
248                 InstructionCode opcode, InstructionCode reverse_opcode) {
249   FlagsContinuation cont;
250   VisitBinop(selector, node, opcode, reverse_opcode, &cont);
251 }
252
253
254 }  // namespace
255
256
257 void InstructionSelector::VisitLoad(Node* node) {
258   MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
259   MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
260   ArmOperandGenerator g(this);
261   Node* base = node->InputAt(0);
262   Node* index = node->InputAt(1);
263
264   ArchOpcode opcode;
265   switch (rep) {
266     case kRepFloat32:
267       opcode = kArmVldrF32;
268       break;
269     case kRepFloat64:
270       opcode = kArmVldrF64;
271       break;
272     case kRepBit:  // Fall through.
273     case kRepWord8:
274       opcode = typ == kTypeUint32 ? kArmLdrb : kArmLdrsb;
275       break;
276     case kRepWord16:
277       opcode = typ == kTypeUint32 ? kArmLdrh : kArmLdrsh;
278       break;
279     case kRepTagged:  // Fall through.
280     case kRepWord32:
281       opcode = kArmLdr;
282       break;
283     default:
284       UNREACHABLE();
285       return;
286   }
287
288   if (g.CanBeImmediate(index, opcode)) {
289     Emit(opcode | AddressingModeField::encode(kMode_Offset_RI),
290          g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
291   } else {
292     Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
293          g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
294   }
295 }
296
297
298 void InstructionSelector::VisitStore(Node* node) {
299   ArmOperandGenerator g(this);
300   Node* base = node->InputAt(0);
301   Node* index = node->InputAt(1);
302   Node* value = node->InputAt(2);
303
304   StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
305   MachineType rep = RepresentationOf(store_rep.machine_type());
306   if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
307     DCHECK(rep == kRepTagged);
308     // TODO(dcarney): refactor RecordWrite function to take temp registers
309     //                and pass them here instead of using fixed regs
310     // TODO(dcarney): handle immediate indices.
311     InstructionOperand temps[] = {g.TempRegister(r5), g.TempRegister(r6)};
312     Emit(kArmStoreWriteBarrier, g.NoOutput(), g.UseFixed(base, r4),
313          g.UseFixed(index, r5), g.UseFixed(value, r6), arraysize(temps), temps);
314     return;
315   }
316   DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
317
318   ArchOpcode opcode;
319   switch (rep) {
320     case kRepFloat32:
321       opcode = kArmVstrF32;
322       break;
323     case kRepFloat64:
324       opcode = kArmVstrF64;
325       break;
326     case kRepBit:  // Fall through.
327     case kRepWord8:
328       opcode = kArmStrb;
329       break;
330     case kRepWord16:
331       opcode = kArmStrh;
332       break;
333     case kRepTagged:  // Fall through.
334     case kRepWord32:
335       opcode = kArmStr;
336       break;
337     default:
338       UNREACHABLE();
339       return;
340   }
341
342   if (g.CanBeImmediate(index, opcode)) {
343     Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), g.NoOutput(),
344          g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
345   } else {
346     Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(),
347          g.UseRegister(base), g.UseRegister(index), g.UseRegister(value));
348   }
349 }
350
351
352 void InstructionSelector::VisitCheckedLoad(Node* node) {
353   MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
354   MachineType typ = TypeOf(OpParameter<MachineType>(node));
355   ArmOperandGenerator g(this);
356   Node* const buffer = node->InputAt(0);
357   Node* const offset = node->InputAt(1);
358   Node* const length = node->InputAt(2);
359   ArchOpcode opcode;
360   switch (rep) {
361     case kRepWord8:
362       opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
363       break;
364     case kRepWord16:
365       opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
366       break;
367     case kRepWord32:
368       opcode = kCheckedLoadWord32;
369       break;
370     case kRepFloat32:
371       opcode = kCheckedLoadFloat32;
372       break;
373     case kRepFloat64:
374       opcode = kCheckedLoadFloat64;
375       break;
376     default:
377       UNREACHABLE();
378       return;
379   }
380   InstructionOperand offset_operand = g.UseRegister(offset);
381   InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
382                                           ? g.UseImmediate(length)
383                                           : g.UseRegister(length);
384   Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
385        g.DefineAsRegister(node), offset_operand, length_operand,
386        g.UseRegister(buffer), offset_operand);
387 }
388
389
390 void InstructionSelector::VisitCheckedStore(Node* node) {
391   MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
392   ArmOperandGenerator g(this);
393   Node* const buffer = node->InputAt(0);
394   Node* const offset = node->InputAt(1);
395   Node* const length = node->InputAt(2);
396   Node* const value = node->InputAt(3);
397   ArchOpcode opcode;
398   switch (rep) {
399     case kRepWord8:
400       opcode = kCheckedStoreWord8;
401       break;
402     case kRepWord16:
403       opcode = kCheckedStoreWord16;
404       break;
405     case kRepWord32:
406       opcode = kCheckedStoreWord32;
407       break;
408     case kRepFloat32:
409       opcode = kCheckedStoreFloat32;
410       break;
411     case kRepFloat64:
412       opcode = kCheckedStoreFloat64;
413       break;
414     default:
415       UNREACHABLE();
416       return;
417   }
418   InstructionOperand offset_operand = g.UseRegister(offset);
419   InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
420                                           ? g.UseImmediate(length)
421                                           : g.UseRegister(length);
422   Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(),
423        offset_operand, length_operand, g.UseRegister(value),
424        g.UseRegister(buffer), offset_operand);
425 }
426
427
428 namespace {
429
430 void EmitBic(InstructionSelector* selector, Node* node, Node* left,
431              Node* right) {
432   ArmOperandGenerator g(selector);
433   InstructionCode opcode = kArmBic;
434   InstructionOperand value_operand;
435   InstructionOperand shift_operand;
436   if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) {
437     selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left),
438                    value_operand, shift_operand);
439     return;
440   }
441   selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
442                  g.DefineAsRegister(node), g.UseRegister(left),
443                  g.UseRegister(right));
444 }
445
446
447 void EmitUbfx(InstructionSelector* selector, Node* node, Node* left,
448               uint32_t lsb, uint32_t width) {
449   DCHECK_LE(1u, width);
450   DCHECK_LE(width, 32u - lsb);
451   ArmOperandGenerator g(selector);
452   selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left),
453                  g.TempImmediate(lsb), g.TempImmediate(width));
454 }
455
456 }  // namespace
457
458
459 void InstructionSelector::VisitWord32And(Node* node) {
460   ArmOperandGenerator g(this);
461   Int32BinopMatcher m(node);
462   if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) {
463     Int32BinopMatcher mleft(m.left().node());
464     if (mleft.right().Is(-1)) {
465       EmitBic(this, node, m.right().node(), mleft.left().node());
466       return;
467     }
468   }
469   if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) {
470     Int32BinopMatcher mright(m.right().node());
471     if (mright.right().Is(-1)) {
472       EmitBic(this, node, m.left().node(), mright.left().node());
473       return;
474     }
475   }
476   if (m.right().HasValue()) {
477     uint32_t const value = m.right().Value();
478     uint32_t width = base::bits::CountPopulation32(value);
479     uint32_t msb = base::bits::CountLeadingZeros32(value);
480     // Try to interpret this AND as UBFX.
481     if (IsSupported(ARMv7) && width != 0 && msb + width == 32) {
482       DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
483       if (m.left().IsWord32Shr()) {
484         Int32BinopMatcher mleft(m.left().node());
485         if (mleft.right().IsInRange(0, 31)) {
486           // UBFX cannot extract bits past the register size, however since
487           // shifting the original value would have introduced some zeros we can
488           // still use UBFX with a smaller mask and the remaining bits will be
489           // zeros.
490           uint32_t const lsb = mleft.right().Value();
491           return EmitUbfx(this, node, mleft.left().node(), lsb,
492                           std::min(width, 32 - lsb));
493         }
494       }
495       return EmitUbfx(this, node, m.left().node(), 0, width);
496     }
497     // Try to interpret this AND as BIC.
498     if (g.CanBeImmediate(~value)) {
499       Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
500            g.DefineAsRegister(node), g.UseRegister(m.left().node()),
501            g.TempImmediate(~value));
502       return;
503     }
504     // Try to interpret this AND as UXTH.
505     if (value == 0xffff) {
506       Emit(kArmUxth, g.DefineAsRegister(m.node()),
507            g.UseRegister(m.left().node()), g.TempImmediate(0));
508       return;
509     }
510     // Try to interpret this AND as BFC.
511     if (IsSupported(ARMv7)) {
512       width = 32 - width;
513       msb = base::bits::CountLeadingZeros32(~value);
514       uint32_t lsb = base::bits::CountTrailingZeros32(~value);
515       if (msb + width + lsb == 32) {
516         Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
517              g.TempImmediate(lsb), g.TempImmediate(width));
518         return;
519       }
520     }
521   }
522   VisitBinop(this, node, kArmAnd, kArmAnd);
523 }
524
525
526 void InstructionSelector::VisitWord32Or(Node* node) {
527   VisitBinop(this, node, kArmOrr, kArmOrr);
528 }
529
530
531 void InstructionSelector::VisitWord32Xor(Node* node) {
532   ArmOperandGenerator g(this);
533   Int32BinopMatcher m(node);
534   if (m.right().Is(-1)) {
535     InstructionCode opcode = kArmMvn;
536     InstructionOperand value_operand;
537     InstructionOperand shift_operand;
538     if (TryMatchShift(this, &opcode, m.left().node(), &value_operand,
539                       &shift_operand)) {
540       Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand);
541       return;
542     }
543     Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
544          g.DefineAsRegister(node), g.UseRegister(m.left().node()));
545     return;
546   }
547   VisitBinop(this, node, kArmEor, kArmEor);
548 }
549
550
551 namespace {
552
553 template <typename TryMatchShift>
554 void VisitShift(InstructionSelector* selector, Node* node,
555                 TryMatchShift try_match_shift, FlagsContinuation* cont) {
556   ArmOperandGenerator g(selector);
557   InstructionCode opcode = kArmMov;
558   InstructionOperand inputs[4];
559   size_t input_count = 2;
560   InstructionOperand outputs[2];
561   size_t output_count = 0;
562
563   CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1]));
564
565   if (cont->IsBranch()) {
566     inputs[input_count++] = g.Label(cont->true_block());
567     inputs[input_count++] = g.Label(cont->false_block());
568   }
569
570   outputs[output_count++] = g.DefineAsRegister(node);
571   if (cont->IsSet()) {
572     outputs[output_count++] = g.DefineAsRegister(cont->result());
573   }
574
575   DCHECK_NE(0u, input_count);
576   DCHECK_NE(0u, output_count);
577   DCHECK_GE(arraysize(inputs), input_count);
578   DCHECK_GE(arraysize(outputs), output_count);
579   DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
580
581   selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
582                  inputs);
583 }
584
585
586 template <typename TryMatchShift>
587 void VisitShift(InstructionSelector* selector, Node* node,
588                               TryMatchShift try_match_shift) {
589   FlagsContinuation cont;
590   VisitShift(selector, node, try_match_shift, &cont);
591 }
592
593 }  // namespace
594
595
596 void InstructionSelector::VisitWord32Shl(Node* node) {
597   VisitShift(this, node, TryMatchLSL);
598 }
599
600
601 void InstructionSelector::VisitWord32Shr(Node* node) {
602   ArmOperandGenerator g(this);
603   Int32BinopMatcher m(node);
604   if (IsSupported(ARMv7) && m.left().IsWord32And() &&
605       m.right().IsInRange(0, 31)) {
606     uint32_t lsb = m.right().Value();
607     Int32BinopMatcher mleft(m.left().node());
608     if (mleft.right().HasValue()) {
609       uint32_t value = (mleft.right().Value() >> lsb) << lsb;
610       uint32_t width = base::bits::CountPopulation32(value);
611       uint32_t msb = base::bits::CountLeadingZeros32(value);
612       if (msb + width + lsb == 32) {
613         DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));
614         return EmitUbfx(this, node, mleft.left().node(), lsb, width);
615       }
616     }
617   }
618   VisitShift(this, node, TryMatchLSR);
619 }
620
621
622 void InstructionSelector::VisitWord32Sar(Node* node) {
623   ArmOperandGenerator g(this);
624   Int32BinopMatcher m(node);
625   if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
626     Int32BinopMatcher mleft(m.left().node());
627     if (mleft.right().Is(16) && m.right().Is(16)) {
628       Emit(kArmSxth, g.DefineAsRegister(node),
629            g.UseRegister(mleft.left().node()), g.TempImmediate(0));
630       return;
631     } else if (mleft.right().Is(24) && m.right().Is(24)) {
632       Emit(kArmSxtb, g.DefineAsRegister(node),
633            g.UseRegister(mleft.left().node()), g.TempImmediate(0));
634       return;
635     }
636   }
637   VisitShift(this, node, TryMatchASR);
638 }
639
640
641 void InstructionSelector::VisitWord32Ror(Node* node) {
642   VisitShift(this, node, TryMatchROR);
643 }
644
645
646 void InstructionSelector::VisitWord32Clz(Node* node) {
647   ArmOperandGenerator g(this);
648   Emit(kArmClz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
649 }
650
651
652 void InstructionSelector::VisitInt32Add(Node* node) {
653   ArmOperandGenerator g(this);
654   Int32BinopMatcher m(node);
655   if (CanCover(node, m.left().node())) {
656     switch (m.left().opcode()) {
657       case IrOpcode::kInt32Mul: {
658         Int32BinopMatcher mleft(m.left().node());
659         Emit(kArmMla, g.DefineAsRegister(node),
660              g.UseRegister(mleft.left().node()),
661              g.UseRegister(mleft.right().node()),
662              g.UseRegister(m.right().node()));
663         return;
664       }
665       case IrOpcode::kInt32MulHigh: {
666         Int32BinopMatcher mleft(m.left().node());
667         Emit(kArmSmmla, g.DefineAsRegister(node),
668              g.UseRegister(mleft.left().node()),
669              g.UseRegister(mleft.right().node()),
670              g.UseRegister(m.right().node()));
671         return;
672       }
673       case IrOpcode::kWord32And: {
674         Int32BinopMatcher mleft(m.left().node());
675         if (mleft.right().Is(0xff)) {
676           Emit(kArmUxtab, g.DefineAsRegister(node),
677                g.UseRegister(m.right().node()),
678                g.UseRegister(mleft.left().node()), g.TempImmediate(0));
679           return;
680         } else if (mleft.right().Is(0xffff)) {
681           Emit(kArmUxtah, g.DefineAsRegister(node),
682                g.UseRegister(m.right().node()),
683                g.UseRegister(mleft.left().node()), g.TempImmediate(0));
684           return;
685         }
686       }
687       case IrOpcode::kWord32Sar: {
688         Int32BinopMatcher mleft(m.left().node());
689         if (CanCover(mleft.node(), mleft.left().node()) &&
690             mleft.left().IsWord32Shl()) {
691           Int32BinopMatcher mleftleft(mleft.left().node());
692           if (mleft.right().Is(24) && mleftleft.right().Is(24)) {
693             Emit(kArmSxtab, g.DefineAsRegister(node),
694                  g.UseRegister(m.right().node()),
695                  g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
696             return;
697           } else if (mleft.right().Is(16) && mleftleft.right().Is(16)) {
698             Emit(kArmSxtah, g.DefineAsRegister(node),
699                  g.UseRegister(m.right().node()),
700                  g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
701             return;
702           }
703         }
704       }
705       default:
706         break;
707     }
708   }
709   if (CanCover(node, m.right().node())) {
710     switch (m.right().opcode()) {
711       case IrOpcode::kInt32Mul: {
712         Int32BinopMatcher mright(m.right().node());
713         Emit(kArmMla, g.DefineAsRegister(node),
714              g.UseRegister(mright.left().node()),
715              g.UseRegister(mright.right().node()),
716              g.UseRegister(m.left().node()));
717         return;
718       }
719       case IrOpcode::kInt32MulHigh: {
720         Int32BinopMatcher mright(m.right().node());
721         Emit(kArmSmmla, g.DefineAsRegister(node),
722              g.UseRegister(mright.left().node()),
723              g.UseRegister(mright.right().node()),
724              g.UseRegister(m.left().node()));
725         return;
726       }
727       case IrOpcode::kWord32And: {
728         Int32BinopMatcher mright(m.right().node());
729         if (mright.right().Is(0xff)) {
730           Emit(kArmUxtab, g.DefineAsRegister(node),
731                g.UseRegister(m.left().node()),
732                g.UseRegister(mright.left().node()), g.TempImmediate(0));
733           return;
734         } else if (mright.right().Is(0xffff)) {
735           Emit(kArmUxtah, g.DefineAsRegister(node),
736                g.UseRegister(m.left().node()),
737                g.UseRegister(mright.left().node()), g.TempImmediate(0));
738           return;
739         }
740       }
741       case IrOpcode::kWord32Sar: {
742         Int32BinopMatcher mright(m.right().node());
743         if (CanCover(mright.node(), mright.left().node()) &&
744             mright.left().IsWord32Shl()) {
745           Int32BinopMatcher mrightleft(mright.left().node());
746           if (mright.right().Is(24) && mrightleft.right().Is(24)) {
747             Emit(kArmSxtab, g.DefineAsRegister(node),
748                  g.UseRegister(m.left().node()),
749                  g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
750             return;
751           } else if (mright.right().Is(16) && mrightleft.right().Is(16)) {
752             Emit(kArmSxtah, g.DefineAsRegister(node),
753                  g.UseRegister(m.left().node()),
754                  g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
755             return;
756           }
757         }
758       }
759       default:
760         break;
761     }
762   }
763   VisitBinop(this, node, kArmAdd, kArmAdd);
764 }
765
766
767 void InstructionSelector::VisitInt32Sub(Node* node) {
768   ArmOperandGenerator g(this);
769   Int32BinopMatcher m(node);
770   if (IsSupported(MLS) && m.right().IsInt32Mul() &&
771       CanCover(node, m.right().node())) {
772     Int32BinopMatcher mright(m.right().node());
773     Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
774          g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
775     return;
776   }
777   VisitBinop(this, node, kArmSub, kArmRsb);
778 }
779
780
781 void InstructionSelector::VisitInt32Mul(Node* node) {
782   ArmOperandGenerator g(this);
783   Int32BinopMatcher m(node);
784   if (m.right().HasValue() && m.right().Value() > 0) {
785     int32_t value = m.right().Value();
786     if (base::bits::IsPowerOfTwo32(value - 1)) {
787       Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
788            g.DefineAsRegister(node), g.UseRegister(m.left().node()),
789            g.UseRegister(m.left().node()),
790            g.TempImmediate(WhichPowerOf2(value - 1)));
791       return;
792     }
793     if (value < kMaxInt && base::bits::IsPowerOfTwo32(value + 1)) {
794       Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
795            g.DefineAsRegister(node), g.UseRegister(m.left().node()),
796            g.UseRegister(m.left().node()),
797            g.TempImmediate(WhichPowerOf2(value + 1)));
798       return;
799     }
800   }
801   Emit(kArmMul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
802        g.UseRegister(m.right().node()));
803 }
804
805
806 void InstructionSelector::VisitInt32MulHigh(Node* node) {
807   ArmOperandGenerator g(this);
808   Emit(kArmSmmul, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
809        g.UseRegister(node->InputAt(1)));
810 }
811
812
813 void InstructionSelector::VisitUint32MulHigh(Node* node) {
814   ArmOperandGenerator g(this);
815   InstructionOperand outputs[] = {g.TempRegister(), g.DefineAsRegister(node)};
816   InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
817                                  g.UseRegister(node->InputAt(1))};
818   Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs);
819 }
820
821
822 static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
823                     ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
824                     InstructionOperand result_operand,
825                     InstructionOperand left_operand,
826                     InstructionOperand right_operand) {
827   ArmOperandGenerator g(selector);
828   if (selector->IsSupported(SUDIV)) {
829     selector->Emit(div_opcode, result_operand, left_operand, right_operand);
830     return;
831   }
832   InstructionOperand left_double_operand = g.TempDoubleRegister();
833   InstructionOperand right_double_operand = g.TempDoubleRegister();
834   InstructionOperand result_double_operand = g.TempDoubleRegister();
835   selector->Emit(f64i32_opcode, left_double_operand, left_operand);
836   selector->Emit(f64i32_opcode, right_double_operand, right_operand);
837   selector->Emit(kArmVdivF64, result_double_operand, left_double_operand,
838                  right_double_operand);
839   selector->Emit(i32f64_opcode, result_operand, result_double_operand);
840 }
841
842
843 static void VisitDiv(InstructionSelector* selector, Node* node,
844                      ArchOpcode div_opcode, ArchOpcode f64i32_opcode,
845                      ArchOpcode i32f64_opcode) {
846   ArmOperandGenerator g(selector);
847   Int32BinopMatcher m(node);
848   EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode,
849           g.DefineAsRegister(node), g.UseRegister(m.left().node()),
850           g.UseRegister(m.right().node()));
851 }
852
853
854 void InstructionSelector::VisitInt32Div(Node* node) {
855   VisitDiv(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
856 }
857
858
859 void InstructionSelector::VisitUint32Div(Node* node) {
860   VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
861 }
862
863
864 static void VisitMod(InstructionSelector* selector, Node* node,
865                      ArchOpcode div_opcode, ArchOpcode f64i32_opcode,
866                      ArchOpcode i32f64_opcode) {
867   ArmOperandGenerator g(selector);
868   Int32BinopMatcher m(node);
869   InstructionOperand div_operand = g.TempRegister();
870   InstructionOperand result_operand = g.DefineAsRegister(node);
871   InstructionOperand left_operand = g.UseRegister(m.left().node());
872   InstructionOperand right_operand = g.UseRegister(m.right().node());
873   EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand,
874           left_operand, right_operand);
875   if (selector->IsSupported(MLS)) {
876     selector->Emit(kArmMls, result_operand, div_operand, right_operand,
877                    left_operand);
878     return;
879   }
880   InstructionOperand mul_operand = g.TempRegister();
881   selector->Emit(kArmMul, mul_operand, div_operand, right_operand);
882   selector->Emit(kArmSub, result_operand, left_operand, mul_operand);
883 }
884
885
886 void InstructionSelector::VisitInt32Mod(Node* node) {
887   VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
888 }
889
890
891 void InstructionSelector::VisitUint32Mod(Node* node) {
892   VisitMod(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
893 }
894
895
896 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
897   ArmOperandGenerator g(this);
898   Emit(kArmVcvtF64F32, g.DefineAsRegister(node),
899        g.UseRegister(node->InputAt(0)));
900 }
901
902
903 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
904   ArmOperandGenerator g(this);
905   Emit(kArmVcvtF64S32, g.DefineAsRegister(node),
906        g.UseRegister(node->InputAt(0)));
907 }
908
909
910 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
911   ArmOperandGenerator g(this);
912   Emit(kArmVcvtF64U32, g.DefineAsRegister(node),
913        g.UseRegister(node->InputAt(0)));
914 }
915
916
917 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
918   ArmOperandGenerator g(this);
919   Emit(kArmVcvtS32F64, g.DefineAsRegister(node),
920        g.UseRegister(node->InputAt(0)));
921 }
922
923
924 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
925   ArmOperandGenerator g(this);
926   Emit(kArmVcvtU32F64, g.DefineAsRegister(node),
927        g.UseRegister(node->InputAt(0)));
928 }
929
930
931 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
932   ArmOperandGenerator g(this);
933   Emit(kArmVcvtF32F64, g.DefineAsRegister(node),
934        g.UseRegister(node->InputAt(0)));
935 }
936
937
938 void InstructionSelector::VisitFloat64Add(Node* node) {
939   ArmOperandGenerator g(this);
940   Float64BinopMatcher m(node);
941   if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
942     Float64BinopMatcher mleft(m.left().node());
943     Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
944          g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
945          g.UseRegister(mleft.right().node()));
946     return;
947   }
948   if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
949     Float64BinopMatcher mright(m.right().node());
950     Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
951          g.UseRegister(mright.left().node()),
952          g.UseRegister(mright.right().node()));
953     return;
954   }
955   VisitRRRFloat64(this, kArmVaddF64, node);
956 }
957
958
959 void InstructionSelector::VisitFloat64Sub(Node* node) {
960   ArmOperandGenerator g(this);
961   Float64BinopMatcher m(node);
962   if (m.left().IsMinusZero()) {
963     if (m.right().IsFloat64RoundDown() &&
964         CanCover(m.node(), m.right().node())) {
965       if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
966           CanCover(m.right().node(), m.right().InputAt(0))) {
967         Float64BinopMatcher mright0(m.right().InputAt(0));
968         if (mright0.left().IsMinusZero()) {
969           Emit(kArmVrintpF64, g.DefineAsRegister(node),
970                g.UseRegister(mright0.right().node()));
971           return;
972         }
973       }
974     }
975     Emit(kArmVnegF64, g.DefineAsRegister(node),
976          g.UseRegister(m.right().node()));
977     return;
978   }
979   if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
980     Float64BinopMatcher mright(m.right().node());
981     Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
982          g.UseRegister(mright.left().node()),
983          g.UseRegister(mright.right().node()));
984     return;
985   }
986   VisitRRRFloat64(this, kArmVsubF64, node);
987 }
988
989
990 void InstructionSelector::VisitFloat64Mul(Node* node) {
991   VisitRRRFloat64(this, kArmVmulF64, node);
992 }
993
994
995 void InstructionSelector::VisitFloat64Div(Node* node) {
996   VisitRRRFloat64(this, kArmVdivF64, node);
997 }
998
999
1000 void InstructionSelector::VisitFloat64Mod(Node* node) {
1001   ArmOperandGenerator g(this);
1002   Emit(kArmVmodF64, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1003        g.UseFixed(node->InputAt(1), d1))->MarkAsCall();
1004 }
1005
1006
1007 void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); }
1008
1009
1010 void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
1011
1012
1013 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
1014   ArmOperandGenerator g(this);
1015   Emit(kArmVsqrtF64, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
1016 }
1017
1018
1019 void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1020   VisitRRFloat64(this, kArmVrintmF64, node);
1021 }
1022
1023
1024 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
1025   VisitRRFloat64(this, kArmVrintzF64, node);
1026 }
1027
1028
1029 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
1030   VisitRRFloat64(this, kArmVrintaF64, node);
1031 }
1032
1033
1034 void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
1035   ArmOperandGenerator g(this);
1036   const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
1037
1038   FrameStateDescriptor* frame_state_descriptor = NULL;
1039   if (descriptor->NeedsFrameState()) {
1040     frame_state_descriptor =
1041         GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
1042   }
1043
1044   CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
1045
1046   // Compute InstructionOperands for inputs and outputs.
1047   // TODO(turbofan): on ARM64 it's probably better to use the code object in a
1048   // register if there are multiple uses of it. Improve constant pool and the
1049   // heuristics in the register allocator for where to emit constants.
1050   InitializeCallBuffer(node, &buffer, true, false);
1051
1052   // TODO(dcarney): might be possible to use claim/poke instead
1053   // Push any stack arguments.
1054   for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
1055        ++i) {
1056     Emit(kArmPush, g.NoOutput(), g.UseRegister(*i));
1057   }
1058
1059   // Pass label of exception handler block.
1060   CallDescriptor::Flags flags = descriptor->flags();
1061   if (handler != nullptr) {
1062     flags |= CallDescriptor::kHasExceptionHandler;
1063     buffer.instruction_args.push_back(g.Label(handler));
1064   }
1065
1066   // Select the appropriate opcode based on the call type.
1067   InstructionCode opcode;
1068   switch (descriptor->kind()) {
1069     case CallDescriptor::kCallCodeObject: {
1070       opcode = kArchCallCodeObject;
1071       break;
1072     }
1073     case CallDescriptor::kCallJSFunction:
1074       opcode = kArchCallJSFunction;
1075       break;
1076     default:
1077       UNREACHABLE();
1078       return;
1079   }
1080   opcode |= MiscField::encode(flags);
1081
1082   // Emit the call instruction.
1083   InstructionOperand* first_output =
1084       buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
1085   Instruction* call_instr =
1086       Emit(opcode, buffer.outputs.size(), first_output,
1087            buffer.instruction_args.size(), &buffer.instruction_args.front());
1088   call_instr->MarkAsCall();
1089 }
1090
1091
1092 namespace {
1093
1094 // Shared routine for multiple float compare operations.
1095 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1096                          FlagsContinuation* cont) {
1097   ArmOperandGenerator g(selector);
1098   Float64BinopMatcher m(node);
1099   InstructionOperand rhs = m.right().Is(0.0) ? g.UseImmediate(m.right().node())
1100                                              : g.UseRegister(m.right().node());
1101   if (cont->IsBranch()) {
1102     selector->Emit(cont->Encode(kArmVcmpF64), g.NoOutput(),
1103                    g.UseRegister(m.left().node()), rhs,
1104                    g.Label(cont->true_block()), g.Label(cont->false_block()));
1105   } else {
1106     DCHECK(cont->IsSet());
1107     selector->Emit(cont->Encode(kArmVcmpF64),
1108                    g.DefineAsRegister(cont->result()),
1109                    g.UseRegister(m.left().node()), rhs);
1110   }
1111 }
1112
1113
1114 // Shared routine for multiple word compare operations.
1115 void VisitWordCompare(InstructionSelector* selector, Node* node,
1116                       InstructionCode opcode, FlagsContinuation* cont) {
1117   ArmOperandGenerator g(selector);
1118   Int32BinopMatcher m(node);
1119   InstructionOperand inputs[5];
1120   size_t input_count = 0;
1121   InstructionOperand outputs[1];
1122   size_t output_count = 0;
1123
1124   if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
1125                                &input_count, &inputs[1])) {
1126     inputs[0] = g.UseRegister(m.left().node());
1127     input_count++;
1128   } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
1129                                       &input_count, &inputs[1])) {
1130     if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1131     inputs[0] = g.UseRegister(m.right().node());
1132     input_count++;
1133   } else {
1134     opcode |= AddressingModeField::encode(kMode_Operand2_R);
1135     inputs[input_count++] = g.UseRegister(m.left().node());
1136     inputs[input_count++] = g.UseRegister(m.right().node());
1137   }
1138
1139   if (cont->IsBranch()) {
1140     inputs[input_count++] = g.Label(cont->true_block());
1141     inputs[input_count++] = g.Label(cont->false_block());
1142   } else {
1143     DCHECK(cont->IsSet());
1144     outputs[output_count++] = g.DefineAsRegister(cont->result());
1145   }
1146
1147   DCHECK_NE(0u, input_count);
1148   DCHECK_GE(arraysize(inputs), input_count);
1149   DCHECK_GE(arraysize(outputs), output_count);
1150
1151   selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
1152                  inputs);
1153 }
1154
1155
1156 void VisitWordCompare(InstructionSelector* selector, Node* node,
1157                       FlagsContinuation* cont) {
1158   VisitWordCompare(selector, node, kArmCmp, cont);
1159 }
1160
1161
1162 // Shared routine for word comparisons against zero.
1163 void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1164                           Node* value, FlagsContinuation* cont) {
1165   while (selector->CanCover(user, value)) {
1166     switch (value->opcode()) {
1167       case IrOpcode::kWord32Equal: {
1168         // Combine with comparisons against 0 by simply inverting the
1169         // continuation.
1170         Int32BinopMatcher m(value);
1171         if (m.right().Is(0)) {
1172           user = value;
1173           value = m.left().node();
1174           cont->Negate();
1175           continue;
1176         }
1177         cont->OverwriteAndNegateIfEqual(kEqual);
1178         return VisitWordCompare(selector, value, cont);
1179       }
1180       case IrOpcode::kInt32LessThan:
1181         cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1182         return VisitWordCompare(selector, value, cont);
1183       case IrOpcode::kInt32LessThanOrEqual:
1184         cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1185         return VisitWordCompare(selector, value, cont);
1186       case IrOpcode::kUint32LessThan:
1187         cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1188         return VisitWordCompare(selector, value, cont);
1189       case IrOpcode::kUint32LessThanOrEqual:
1190         cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1191         return VisitWordCompare(selector, value, cont);
1192       case IrOpcode::kFloat64Equal:
1193         cont->OverwriteAndNegateIfEqual(kEqual);
1194         return VisitFloat64Compare(selector, value, cont);
1195       case IrOpcode::kFloat64LessThan:
1196         cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1197         return VisitFloat64Compare(selector, value, cont);
1198       case IrOpcode::kFloat64LessThanOrEqual:
1199         cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1200         return VisitFloat64Compare(selector, value, cont);
1201       case IrOpcode::kProjection:
1202         // Check if this is the overflow output projection of an
1203         // <Operation>WithOverflow node.
1204         if (ProjectionIndexOf(value->op()) == 1u) {
1205           // We cannot combine the <Operation>WithOverflow with this branch
1206           // unless the 0th projection (the use of the actual value of the
1207           // <Operation> is either NULL, which means there's no use of the
1208           // actual value, or was already defined, which means it is scheduled
1209           // *AFTER* this branch).
1210           Node* const node = value->InputAt(0);
1211           Node* const result = NodeProperties::FindProjection(node, 0);
1212           if (!result || selector->IsDefined(result)) {
1213             switch (node->opcode()) {
1214               case IrOpcode::kInt32AddWithOverflow:
1215                 cont->OverwriteAndNegateIfEqual(kOverflow);
1216                 return VisitBinop(selector, node, kArmAdd, kArmAdd, cont);
1217               case IrOpcode::kInt32SubWithOverflow:
1218                 cont->OverwriteAndNegateIfEqual(kOverflow);
1219                 return VisitBinop(selector, node, kArmSub, kArmRsb, cont);
1220               default:
1221                 break;
1222             }
1223           }
1224         }
1225         break;
1226       case IrOpcode::kInt32Add:
1227         return VisitWordCompare(selector, value, kArmCmn, cont);
1228       case IrOpcode::kInt32Sub:
1229         return VisitWordCompare(selector, value, kArmCmp, cont);
1230       case IrOpcode::kWord32And:
1231         return VisitWordCompare(selector, value, kArmTst, cont);
1232       case IrOpcode::kWord32Or:
1233         return VisitBinop(selector, value, kArmOrr, kArmOrr, cont);
1234       case IrOpcode::kWord32Xor:
1235         return VisitWordCompare(selector, value, kArmTeq, cont);
1236       case IrOpcode::kWord32Sar:
1237         return VisitShift(selector, value, TryMatchASR, cont);
1238       case IrOpcode::kWord32Shl:
1239         return VisitShift(selector, value, TryMatchLSL, cont);
1240       case IrOpcode::kWord32Shr:
1241         return VisitShift(selector, value, TryMatchLSR, cont);
1242       case IrOpcode::kWord32Ror:
1243         return VisitShift(selector, value, TryMatchROR, cont);
1244       default:
1245         break;
1246     }
1247     break;
1248   }
1249
1250   // Continuation could not be combined with a compare, emit compare against 0.
1251   ArmOperandGenerator g(selector);
1252   InstructionCode const opcode =
1253       cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R);
1254   InstructionOperand const value_operand = g.UseRegister(value);
1255   if (cont->IsBranch()) {
1256     selector->Emit(opcode, g.NoOutput(), value_operand, value_operand,
1257                    g.Label(cont->true_block()), g.Label(cont->false_block()));
1258   } else {
1259     selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
1260                    value_operand);
1261   }
1262 }
1263
1264 }  // namespace
1265
1266
1267 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1268                                       BasicBlock* fbranch) {
1269   FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1270   VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
1271 }
1272
1273
1274 void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1275   ArmOperandGenerator g(this);
1276   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1277
1278   // Emit either ArchTableSwitch or ArchLookupSwitch.
1279   size_t table_space_cost = 4 + sw.value_range;
1280   size_t table_time_cost = 3;
1281   size_t lookup_space_cost = 3 + 2 * sw.case_count;
1282   size_t lookup_time_cost = sw.case_count;
1283   if (sw.case_count > 0 &&
1284       table_space_cost + 3 * table_time_cost <=
1285           lookup_space_cost + 3 * lookup_time_cost &&
1286       sw.min_value > std::numeric_limits<int32_t>::min()) {
1287     InstructionOperand index_operand = value_operand;
1288     if (sw.min_value) {
1289       index_operand = g.TempRegister();
1290       Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I),
1291            index_operand, value_operand, g.TempImmediate(sw.min_value));
1292     }
1293     // Generate a table lookup.
1294     return EmitTableSwitch(sw, index_operand);
1295   }
1296
1297   // Generate a sequence of conditional jumps.
1298   return EmitLookupSwitch(sw, value_operand);
1299 }
1300
1301
1302 void InstructionSelector::VisitWord32Equal(Node* const node) {
1303   FlagsContinuation cont(kEqual, node);
1304   Int32BinopMatcher m(node);
1305   if (m.right().Is(0)) {
1306     return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
1307   }
1308   VisitWordCompare(this, node, &cont);
1309 }
1310
1311
1312 void InstructionSelector::VisitInt32LessThan(Node* node) {
1313   FlagsContinuation cont(kSignedLessThan, node);
1314   VisitWordCompare(this, node, &cont);
1315 }
1316
1317
1318 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
1319   FlagsContinuation cont(kSignedLessThanOrEqual, node);
1320   VisitWordCompare(this, node, &cont);
1321 }
1322
1323
1324 void InstructionSelector::VisitUint32LessThan(Node* node) {
1325   FlagsContinuation cont(kUnsignedLessThan, node);
1326   VisitWordCompare(this, node, &cont);
1327 }
1328
1329
1330 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
1331   FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
1332   VisitWordCompare(this, node, &cont);
1333 }
1334
1335
1336 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
1337   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1338     FlagsContinuation cont(kOverflow, ovf);
1339     return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
1340   }
1341   FlagsContinuation cont;
1342   VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
1343 }
1344
1345
1346 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
1347   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1348     FlagsContinuation cont(kOverflow, ovf);
1349     return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
1350   }
1351   FlagsContinuation cont;
1352   VisitBinop(this, node, kArmSub, kArmRsb, &cont);
1353 }
1354
1355
1356 void InstructionSelector::VisitFloat64Equal(Node* node) {
1357   FlagsContinuation cont(kEqual, node);
1358   VisitFloat64Compare(this, node, &cont);
1359 }
1360
1361
1362 void InstructionSelector::VisitFloat64LessThan(Node* node) {
1363   FlagsContinuation cont(kUnsignedLessThan, node);
1364   VisitFloat64Compare(this, node, &cont);
1365 }
1366
1367
1368 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
1369   FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
1370   VisitFloat64Compare(this, node, &cont);
1371 }
1372
1373
1374 void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1375   ArmOperandGenerator g(this);
1376   Emit(kArmVmovLowU32F64, g.DefineAsRegister(node),
1377        g.UseRegister(node->InputAt(0)));
1378 }
1379
1380
1381 void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1382   ArmOperandGenerator g(this);
1383   Emit(kArmVmovHighU32F64, g.DefineAsRegister(node),
1384        g.UseRegister(node->InputAt(0)));
1385 }
1386
1387
1388 void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1389   ArmOperandGenerator g(this);
1390   Node* left = node->InputAt(0);
1391   Node* right = node->InputAt(1);
1392   if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
1393       CanCover(node, left)) {
1394     left = left->InputAt(1);
1395     Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right),
1396          g.UseRegister(left));
1397     return;
1398   }
1399   Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
1400        g.UseRegister(right));
1401 }
1402
1403
1404 void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1405   ArmOperandGenerator g(this);
1406   Node* left = node->InputAt(0);
1407   Node* right = node->InputAt(1);
1408   if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
1409       CanCover(node, left)) {
1410     left = left->InputAt(1);
1411     Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left),
1412          g.UseRegister(right));
1413     return;
1414   }
1415   Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
1416        g.UseRegister(right));
1417 }
1418
1419
1420 // static
1421 MachineOperatorBuilder::Flags
1422 InstructionSelector::SupportedMachineOperatorFlags() {
1423   MachineOperatorBuilder::Flags flags =
1424       MachineOperatorBuilder::kInt32DivIsSafe |
1425       MachineOperatorBuilder::kUint32DivIsSafe;
1426
1427   if (CpuFeatures::IsSupported(ARMv8)) {
1428     flags |= MachineOperatorBuilder::kFloat64RoundDown |
1429              MachineOperatorBuilder::kFloat64RoundTruncate |
1430              MachineOperatorBuilder::kFloat64RoundTiesAway;
1431   }
1432   return flags;
1433 }
1434
1435 }  // namespace compiler
1436 }  // namespace internal
1437 }  // namespace v8