Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / 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/compiler/instruction-selector-impl.h"
6 #include "src/compiler/node-matchers.h"
7 #include "src/compiler-intrinsics.h"
8
9 namespace v8 {
10 namespace internal {
11 namespace compiler {
12
13 // Adds Arm-specific methods for generating InstructionOperands.
14 class ArmOperandGenerator V8_FINAL : public OperandGenerator {
15  public:
16   explicit ArmOperandGenerator(InstructionSelector* selector)
17       : OperandGenerator(selector) {}
18
19   InstructionOperand* UseOperand(Node* node, InstructionCode opcode) {
20     if (CanBeImmediate(node, opcode)) {
21       return UseImmediate(node);
22     }
23     return UseRegister(node);
24   }
25
26   bool CanBeImmediate(Node* node, InstructionCode opcode) {
27     int32_t value;
28     switch (node->opcode()) {
29       case IrOpcode::kInt32Constant:
30       case IrOpcode::kNumberConstant:
31         value = ValueOf<int32_t>(node->op());
32         break;
33       default:
34         return false;
35     }
36     switch (ArchOpcodeField::decode(opcode)) {
37       case kArmAnd:
38       case kArmMov:
39       case kArmMvn:
40       case kArmBic:
41         return ImmediateFitsAddrMode1Instruction(value) ||
42                ImmediateFitsAddrMode1Instruction(~value);
43
44       case kArmAdd:
45       case kArmSub:
46       case kArmCmp:
47       case kArmCmn:
48         return ImmediateFitsAddrMode1Instruction(value) ||
49                ImmediateFitsAddrMode1Instruction(-value);
50
51       case kArmTst:
52       case kArmTeq:
53       case kArmOrr:
54       case kArmEor:
55       case kArmRsb:
56         return ImmediateFitsAddrMode1Instruction(value);
57
58       case kArmFloat64Load:
59       case kArmFloat64Store:
60         return value >= -1020 && value <= 1020 && (value % 4) == 0;
61
62       case kArmLoadWord8:
63       case kArmStoreWord8:
64       case kArmLoadWord32:
65       case kArmStoreWord32:
66       case kArmStoreWriteBarrier:
67         return value >= -4095 && value <= 4095;
68
69       case kArmLoadWord16:
70       case kArmStoreWord16:
71         return value >= -255 && value <= 255;
72
73       case kArchJmp:
74       case kArchNop:
75       case kArchRet:
76       case kArchDeoptimize:
77       case kArmMul:
78       case kArmMla:
79       case kArmMls:
80       case kArmSdiv:
81       case kArmUdiv:
82       case kArmBfc:
83       case kArmUbfx:
84       case kArmCallCodeObject:
85       case kArmCallJSFunction:
86       case kArmCallAddress:
87       case kArmPush:
88       case kArmDrop:
89       case kArmVcmpF64:
90       case kArmVaddF64:
91       case kArmVsubF64:
92       case kArmVmulF64:
93       case kArmVmlaF64:
94       case kArmVmlsF64:
95       case kArmVdivF64:
96       case kArmVmodF64:
97       case kArmVnegF64:
98       case kArmVcvtF64S32:
99       case kArmVcvtF64U32:
100       case kArmVcvtS32F64:
101       case kArmVcvtU32F64:
102         return false;
103     }
104     UNREACHABLE();
105     return false;
106   }
107
108  private:
109   bool ImmediateFitsAddrMode1Instruction(int32_t imm) const {
110     return Assembler::ImmediateFitsAddrMode1Instruction(imm);
111   }
112 };
113
114
115 static void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
116                             Node* node) {
117   ArmOperandGenerator g(selector);
118   selector->Emit(opcode, g.DefineAsDoubleRegister(node),
119                  g.UseDoubleRegister(node->InputAt(0)),
120                  g.UseDoubleRegister(node->InputAt(1)));
121 }
122
123
124 static bool TryMatchROR(InstructionSelector* selector,
125                         InstructionCode* opcode_return, Node* node,
126                         InstructionOperand** value_return,
127                         InstructionOperand** shift_return) {
128   ArmOperandGenerator g(selector);
129   if (node->opcode() != IrOpcode::kWord32Or) return false;
130   Int32BinopMatcher m(node);
131   Node* shl = m.left().node();
132   Node* shr = m.right().node();
133   if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) {
134     std::swap(shl, shr);
135   } else if (!m.left().IsWord32Shl() || !m.right().IsWord32Shr()) {
136     return false;
137   }
138   Int32BinopMatcher mshr(shr);
139   Int32BinopMatcher mshl(shl);
140   Node* value = mshr.left().node();
141   if (value != mshl.left().node()) return false;
142   Node* shift = mshr.right().node();
143   Int32Matcher mshift(shift);
144   if (mshift.IsInRange(1, 31) && mshl.right().Is(32 - mshift.Value())) {
145     *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_I);
146     *value_return = g.UseRegister(value);
147     *shift_return = g.UseImmediate(shift);
148     return true;
149   }
150   if (mshl.right().IsInt32Sub()) {
151     Int32BinopMatcher mshlright(mshl.right().node());
152     if (!mshlright.left().Is(32)) return false;
153     if (mshlright.right().node() != shift) return false;
154     *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_R);
155     *value_return = g.UseRegister(value);
156     *shift_return = g.UseRegister(shift);
157     return true;
158   }
159   return false;
160 }
161
162
163 static inline bool TryMatchASR(InstructionSelector* selector,
164                                InstructionCode* opcode_return, Node* node,
165                                InstructionOperand** value_return,
166                                InstructionOperand** shift_return) {
167   ArmOperandGenerator g(selector);
168   if (node->opcode() != IrOpcode::kWord32Sar) return false;
169   Int32BinopMatcher m(node);
170   *value_return = g.UseRegister(m.left().node());
171   if (m.right().IsInRange(1, 32)) {
172     *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_I);
173     *shift_return = g.UseImmediate(m.right().node());
174   } else {
175     *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_R);
176     *shift_return = g.UseRegister(m.right().node());
177   }
178   return true;
179 }
180
181
182 static inline bool TryMatchLSL(InstructionSelector* selector,
183                                InstructionCode* opcode_return, Node* node,
184                                InstructionOperand** value_return,
185                                InstructionOperand** shift_return) {
186   ArmOperandGenerator g(selector);
187   if (node->opcode() != IrOpcode::kWord32Shl) return false;
188   Int32BinopMatcher m(node);
189   *value_return = g.UseRegister(m.left().node());
190   if (m.right().IsInRange(0, 31)) {
191     *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_I);
192     *shift_return = g.UseImmediate(m.right().node());
193   } else {
194     *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_R);
195     *shift_return = g.UseRegister(m.right().node());
196   }
197   return true;
198 }
199
200
201 static inline bool TryMatchLSR(InstructionSelector* selector,
202                                InstructionCode* opcode_return, Node* node,
203                                InstructionOperand** value_return,
204                                InstructionOperand** shift_return) {
205   ArmOperandGenerator g(selector);
206   if (node->opcode() != IrOpcode::kWord32Shr) return false;
207   Int32BinopMatcher m(node);
208   *value_return = g.UseRegister(m.left().node());
209   if (m.right().IsInRange(1, 32)) {
210     *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_I);
211     *shift_return = g.UseImmediate(m.right().node());
212   } else {
213     *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_R);
214     *shift_return = g.UseRegister(m.right().node());
215   }
216   return true;
217 }
218
219
220 static inline bool TryMatchShift(InstructionSelector* selector,
221                                  InstructionCode* opcode_return, Node* node,
222                                  InstructionOperand** value_return,
223                                  InstructionOperand** shift_return) {
224   return (
225       TryMatchASR(selector, opcode_return, node, value_return, shift_return) ||
226       TryMatchLSL(selector, opcode_return, node, value_return, shift_return) ||
227       TryMatchLSR(selector, opcode_return, node, value_return, shift_return) ||
228       TryMatchROR(selector, opcode_return, node, value_return, shift_return));
229 }
230
231
232 static inline bool TryMatchImmediateOrShift(InstructionSelector* selector,
233                                             InstructionCode* opcode_return,
234                                             Node* node,
235                                             size_t* input_count_return,
236                                             InstructionOperand** inputs) {
237   ArmOperandGenerator g(selector);
238   if (g.CanBeImmediate(node, *opcode_return)) {
239     *opcode_return |= AddressingModeField::encode(kMode_Operand2_I);
240     inputs[0] = g.UseImmediate(node);
241     *input_count_return = 1;
242     return true;
243   }
244   if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) {
245     *input_count_return = 2;
246     return true;
247   }
248   return false;
249 }
250
251
252 static void VisitBinop(InstructionSelector* selector, Node* node,
253                        InstructionCode opcode, InstructionCode reverse_opcode,
254                        FlagsContinuation* cont) {
255   ArmOperandGenerator g(selector);
256   Int32BinopMatcher m(node);
257   InstructionOperand* inputs[5];
258   size_t input_count = 0;
259   InstructionOperand* outputs[2];
260   size_t output_count = 0;
261
262   if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
263                                &input_count, &inputs[1])) {
264     inputs[0] = g.UseRegister(m.left().node());
265     input_count++;
266   } else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
267                                       m.left().node(), &input_count,
268                                       &inputs[1])) {
269     inputs[0] = g.UseRegister(m.right().node());
270     opcode = reverse_opcode;
271     input_count++;
272   } else {
273     opcode |= AddressingModeField::encode(kMode_Operand2_R);
274     inputs[input_count++] = g.UseRegister(m.left().node());
275     inputs[input_count++] = g.UseRegister(m.right().node());
276   }
277
278   if (cont->IsBranch()) {
279     inputs[input_count++] = g.Label(cont->true_block());
280     inputs[input_count++] = g.Label(cont->false_block());
281   }
282
283   outputs[output_count++] = g.DefineAsRegister(node);
284   if (cont->IsSet()) {
285     outputs[output_count++] = g.DefineAsRegister(cont->result());
286   }
287
288   DCHECK_NE(0, input_count);
289   DCHECK_NE(0, output_count);
290   DCHECK_GE(ARRAY_SIZE(inputs), input_count);
291   DCHECK_GE(ARRAY_SIZE(outputs), output_count);
292   DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
293
294   Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
295                                       outputs, input_count, inputs);
296   if (cont->IsBranch()) instr->MarkAsControl();
297 }
298
299
300 static void VisitBinop(InstructionSelector* selector, Node* node,
301                        InstructionCode opcode, InstructionCode reverse_opcode) {
302   FlagsContinuation cont;
303   VisitBinop(selector, node, opcode, reverse_opcode, &cont);
304 }
305
306
307 void InstructionSelector::VisitLoad(Node* node) {
308   MachineType rep = OpParameter<MachineType>(node);
309   ArmOperandGenerator g(this);
310   Node* base = node->InputAt(0);
311   Node* index = node->InputAt(1);
312
313   InstructionOperand* result = rep == kMachineFloat64
314                                    ? g.DefineAsDoubleRegister(node)
315                                    : g.DefineAsRegister(node);
316
317   ArchOpcode opcode;
318   switch (rep) {
319     case kMachineFloat64:
320       opcode = kArmFloat64Load;
321       break;
322     case kMachineWord8:
323       opcode = kArmLoadWord8;
324       break;
325     case kMachineWord16:
326       opcode = kArmLoadWord16;
327       break;
328     case kMachineTagged:  // Fall through.
329     case kMachineWord32:
330       opcode = kArmLoadWord32;
331       break;
332     default:
333       UNREACHABLE();
334       return;
335   }
336
337   if (g.CanBeImmediate(index, opcode)) {
338     Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), result,
339          g.UseRegister(base), g.UseImmediate(index));
340   } else if (g.CanBeImmediate(base, opcode)) {
341     Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), result,
342          g.UseRegister(index), g.UseImmediate(base));
343   } else {
344     Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), result,
345          g.UseRegister(base), g.UseRegister(index));
346   }
347 }
348
349
350 void InstructionSelector::VisitStore(Node* node) {
351   ArmOperandGenerator g(this);
352   Node* base = node->InputAt(0);
353   Node* index = node->InputAt(1);
354   Node* value = node->InputAt(2);
355
356   StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
357   MachineType rep = store_rep.rep;
358   if (store_rep.write_barrier_kind == kFullWriteBarrier) {
359     DCHECK(rep == kMachineTagged);
360     // TODO(dcarney): refactor RecordWrite function to take temp registers
361     //                and pass them here instead of using fixed regs
362     // TODO(dcarney): handle immediate indices.
363     InstructionOperand* temps[] = {g.TempRegister(r5), g.TempRegister(r6)};
364     Emit(kArmStoreWriteBarrier, NULL, g.UseFixed(base, r4),
365          g.UseFixed(index, r5), g.UseFixed(value, r6), ARRAY_SIZE(temps),
366          temps);
367     return;
368   }
369   DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind);
370   InstructionOperand* val = rep == kMachineFloat64 ? g.UseDoubleRegister(value)
371                                                    : g.UseRegister(value);
372
373   ArchOpcode opcode;
374   switch (rep) {
375     case kMachineFloat64:
376       opcode = kArmFloat64Store;
377       break;
378     case kMachineWord8:
379       opcode = kArmStoreWord8;
380       break;
381     case kMachineWord16:
382       opcode = kArmStoreWord16;
383       break;
384     case kMachineTagged:  // Fall through.
385     case kMachineWord32:
386       opcode = kArmStoreWord32;
387       break;
388     default:
389       UNREACHABLE();
390       return;
391   }
392
393   if (g.CanBeImmediate(index, opcode)) {
394     Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), NULL,
395          g.UseRegister(base), g.UseImmediate(index), val);
396   } else if (g.CanBeImmediate(base, opcode)) {
397     Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), NULL,
398          g.UseRegister(index), g.UseImmediate(base), val);
399   } else {
400     Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), NULL,
401          g.UseRegister(base), g.UseRegister(index), val);
402   }
403 }
404
405
406 static inline void EmitBic(InstructionSelector* selector, Node* node,
407                            Node* left, Node* right) {
408   ArmOperandGenerator g(selector);
409   InstructionCode opcode = kArmBic;
410   InstructionOperand* value_operand;
411   InstructionOperand* shift_operand;
412   if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) {
413     selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left),
414                    value_operand, shift_operand);
415     return;
416   }
417   selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
418                  g.DefineAsRegister(node), g.UseRegister(left),
419                  g.UseRegister(right));
420 }
421
422
423 void InstructionSelector::VisitWord32And(Node* node) {
424   ArmOperandGenerator g(this);
425   Int32BinopMatcher m(node);
426   if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) {
427     Int32BinopMatcher mleft(m.left().node());
428     if (mleft.right().Is(-1)) {
429       EmitBic(this, node, m.right().node(), mleft.left().node());
430       return;
431     }
432   }
433   if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) {
434     Int32BinopMatcher mright(m.right().node());
435     if (mright.right().Is(-1)) {
436       EmitBic(this, node, m.left().node(), mright.left().node());
437       return;
438     }
439   }
440   if (IsSupported(ARMv7) && m.right().HasValue()) {
441     uint32_t value = m.right().Value();
442     uint32_t width = CompilerIntrinsics::CountSetBits(value);
443     uint32_t msb = CompilerIntrinsics::CountLeadingZeros(value);
444     if (width != 0 && msb + width == 32) {
445       DCHECK_EQ(0, CompilerIntrinsics::CountTrailingZeros(value));
446       if (m.left().IsWord32Shr()) {
447         Int32BinopMatcher mleft(m.left().node());
448         if (mleft.right().IsInRange(0, 31)) {
449           Emit(kArmUbfx, g.DefineAsRegister(node),
450                g.UseRegister(mleft.left().node()),
451                g.UseImmediate(mleft.right().node()), g.TempImmediate(width));
452           return;
453         }
454       }
455       Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
456            g.TempImmediate(0), g.TempImmediate(width));
457       return;
458     }
459     // Try to interpret this AND as BFC.
460     width = 32 - width;
461     msb = CompilerIntrinsics::CountLeadingZeros(~value);
462     uint32_t lsb = CompilerIntrinsics::CountTrailingZeros(~value);
463     if (msb + width + lsb == 32) {
464       Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
465            g.TempImmediate(lsb), g.TempImmediate(width));
466       return;
467     }
468   }
469   VisitBinop(this, node, kArmAnd, kArmAnd);
470 }
471
472
473 void InstructionSelector::VisitWord32Or(Node* node) {
474   ArmOperandGenerator g(this);
475   InstructionCode opcode = kArmMov;
476   InstructionOperand* value_operand;
477   InstructionOperand* shift_operand;
478   if (TryMatchROR(this, &opcode, node, &value_operand, &shift_operand)) {
479     Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand);
480     return;
481   }
482   VisitBinop(this, node, kArmOrr, kArmOrr);
483 }
484
485
486 void InstructionSelector::VisitWord32Xor(Node* node) {
487   ArmOperandGenerator g(this);
488   Int32BinopMatcher m(node);
489   if (m.right().Is(-1)) {
490     InstructionCode opcode = kArmMvn;
491     InstructionOperand* value_operand;
492     InstructionOperand* shift_operand;
493     if (TryMatchShift(this, &opcode, m.left().node(), &value_operand,
494                       &shift_operand)) {
495       Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand);
496       return;
497     }
498     Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
499          g.DefineAsRegister(node), g.UseRegister(m.left().node()));
500     return;
501   }
502   VisitBinop(this, node, kArmEor, kArmEor);
503 }
504
505
506 template <typename TryMatchShift>
507 static inline void VisitShift(InstructionSelector* selector, Node* node,
508                               TryMatchShift try_match_shift) {
509   ArmOperandGenerator g(selector);
510   InstructionCode opcode = kArmMov;
511   InstructionOperand* value_operand = NULL;
512   InstructionOperand* shift_operand = NULL;
513   CHECK(
514       try_match_shift(selector, &opcode, node, &value_operand, &shift_operand));
515   selector->Emit(opcode, g.DefineAsRegister(node), value_operand,
516                  shift_operand);
517 }
518
519
520 void InstructionSelector::VisitWord32Shl(Node* node) {
521   VisitShift(this, node, TryMatchLSL);
522 }
523
524
525 void InstructionSelector::VisitWord32Shr(Node* node) {
526   ArmOperandGenerator g(this);
527   Int32BinopMatcher m(node);
528   if (IsSupported(ARMv7) && m.left().IsWord32And() &&
529       m.right().IsInRange(0, 31)) {
530     int32_t lsb = m.right().Value();
531     Int32BinopMatcher mleft(m.left().node());
532     if (mleft.right().HasValue()) {
533       uint32_t value = (mleft.right().Value() >> lsb) << lsb;
534       uint32_t width = CompilerIntrinsics::CountSetBits(value);
535       uint32_t msb = CompilerIntrinsics::CountLeadingZeros(value);
536       if (msb + width + lsb == 32) {
537         DCHECK_EQ(lsb, CompilerIntrinsics::CountTrailingZeros(value));
538         Emit(kArmUbfx, g.DefineAsRegister(node),
539              g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
540              g.TempImmediate(width));
541         return;
542       }
543     }
544   }
545   VisitShift(this, node, TryMatchLSR);
546 }
547
548
549 void InstructionSelector::VisitWord32Sar(Node* node) {
550   VisitShift(this, node, TryMatchASR);
551 }
552
553
554 void InstructionSelector::VisitInt32Add(Node* node) {
555   ArmOperandGenerator g(this);
556   Int32BinopMatcher m(node);
557   if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) {
558     Int32BinopMatcher mleft(m.left().node());
559     Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mleft.left().node()),
560          g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node()));
561     return;
562   }
563   if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) {
564     Int32BinopMatcher mright(m.right().node());
565     Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
566          g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
567     return;
568   }
569   VisitBinop(this, node, kArmAdd, kArmAdd);
570 }
571
572
573 void InstructionSelector::VisitInt32Sub(Node* node) {
574   ArmOperandGenerator g(this);
575   Int32BinopMatcher m(node);
576   if (IsSupported(MLS) && m.right().IsInt32Mul() &&
577       CanCover(node, m.right().node())) {
578     Int32BinopMatcher mright(m.right().node());
579     Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
580          g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
581     return;
582   }
583   VisitBinop(this, node, kArmSub, kArmRsb);
584 }
585
586
587 void InstructionSelector::VisitInt32Mul(Node* node) {
588   ArmOperandGenerator g(this);
589   Int32BinopMatcher m(node);
590   if (m.right().HasValue() && m.right().Value() > 0) {
591     int32_t value = m.right().Value();
592     if (IsPowerOf2(value - 1)) {
593       Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
594            g.DefineAsRegister(node), g.UseRegister(m.left().node()),
595            g.UseRegister(m.left().node()),
596            g.TempImmediate(WhichPowerOf2(value - 1)));
597       return;
598     }
599     if (value < kMaxInt && IsPowerOf2(value + 1)) {
600       Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
601            g.DefineAsRegister(node), g.UseRegister(m.left().node()),
602            g.UseRegister(m.left().node()),
603            g.TempImmediate(WhichPowerOf2(value + 1)));
604       return;
605     }
606   }
607   Emit(kArmMul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
608        g.UseRegister(m.right().node()));
609 }
610
611
612 static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
613                     ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
614                     InstructionOperand* result_operand,
615                     InstructionOperand* left_operand,
616                     InstructionOperand* right_operand) {
617   ArmOperandGenerator g(selector);
618   if (selector->IsSupported(SUDIV)) {
619     selector->Emit(div_opcode, result_operand, left_operand, right_operand);
620     return;
621   }
622   InstructionOperand* left_double_operand = g.TempDoubleRegister();
623   InstructionOperand* right_double_operand = g.TempDoubleRegister();
624   InstructionOperand* result_double_operand = g.TempDoubleRegister();
625   selector->Emit(f64i32_opcode, left_double_operand, left_operand);
626   selector->Emit(f64i32_opcode, right_double_operand, right_operand);
627   selector->Emit(kArmVdivF64, result_double_operand, left_double_operand,
628                  right_double_operand);
629   selector->Emit(i32f64_opcode, result_operand, result_double_operand);
630 }
631
632
633 static void VisitDiv(InstructionSelector* selector, Node* node,
634                      ArchOpcode div_opcode, ArchOpcode f64i32_opcode,
635                      ArchOpcode i32f64_opcode) {
636   ArmOperandGenerator g(selector);
637   Int32BinopMatcher m(node);
638   EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode,
639           g.DefineAsRegister(node), g.UseRegister(m.left().node()),
640           g.UseRegister(m.right().node()));
641 }
642
643
644 void InstructionSelector::VisitInt32Div(Node* node) {
645   VisitDiv(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
646 }
647
648
649 void InstructionSelector::VisitInt32UDiv(Node* node) {
650   VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
651 }
652
653
654 static void VisitMod(InstructionSelector* selector, Node* node,
655                      ArchOpcode div_opcode, ArchOpcode f64i32_opcode,
656                      ArchOpcode i32f64_opcode) {
657   ArmOperandGenerator g(selector);
658   Int32BinopMatcher m(node);
659   InstructionOperand* div_operand = g.TempRegister();
660   InstructionOperand* result_operand = g.DefineAsRegister(node);
661   InstructionOperand* left_operand = g.UseRegister(m.left().node());
662   InstructionOperand* right_operand = g.UseRegister(m.right().node());
663   EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand,
664           left_operand, right_operand);
665   if (selector->IsSupported(MLS)) {
666     selector->Emit(kArmMls, result_operand, div_operand, right_operand,
667                    left_operand);
668     return;
669   }
670   InstructionOperand* mul_operand = g.TempRegister();
671   selector->Emit(kArmMul, mul_operand, div_operand, right_operand);
672   selector->Emit(kArmSub, result_operand, left_operand, mul_operand);
673 }
674
675
676 void InstructionSelector::VisitInt32Mod(Node* node) {
677   VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
678 }
679
680
681 void InstructionSelector::VisitInt32UMod(Node* node) {
682   VisitMod(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
683 }
684
685
686 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
687   ArmOperandGenerator g(this);
688   Emit(kArmVcvtF64S32, g.DefineAsDoubleRegister(node),
689        g.UseRegister(node->InputAt(0)));
690 }
691
692
693 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
694   ArmOperandGenerator g(this);
695   Emit(kArmVcvtF64U32, g.DefineAsDoubleRegister(node),
696        g.UseRegister(node->InputAt(0)));
697 }
698
699
700 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
701   ArmOperandGenerator g(this);
702   Emit(kArmVcvtS32F64, g.DefineAsRegister(node),
703        g.UseDoubleRegister(node->InputAt(0)));
704 }
705
706
707 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
708   ArmOperandGenerator g(this);
709   Emit(kArmVcvtU32F64, g.DefineAsRegister(node),
710        g.UseDoubleRegister(node->InputAt(0)));
711 }
712
713
714 void InstructionSelector::VisitFloat64Add(Node* node) {
715   ArmOperandGenerator g(this);
716   Int32BinopMatcher m(node);
717   if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
718     Int32BinopMatcher mleft(m.left().node());
719     Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
720          g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
721          g.UseRegister(mleft.right().node()));
722     return;
723   }
724   if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
725     Int32BinopMatcher mright(m.right().node());
726     Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
727          g.UseRegister(mright.left().node()),
728          g.UseRegister(mright.right().node()));
729     return;
730   }
731   VisitRRRFloat64(this, kArmVaddF64, node);
732 }
733
734
735 void InstructionSelector::VisitFloat64Sub(Node* node) {
736   ArmOperandGenerator g(this);
737   Int32BinopMatcher m(node);
738   if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
739     Int32BinopMatcher mright(m.right().node());
740     Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
741          g.UseRegister(mright.left().node()),
742          g.UseRegister(mright.right().node()));
743     return;
744   }
745   VisitRRRFloat64(this, kArmVsubF64, node);
746 }
747
748
749 void InstructionSelector::VisitFloat64Mul(Node* node) {
750   ArmOperandGenerator g(this);
751   Float64BinopMatcher m(node);
752   if (m.right().Is(-1.0)) {
753     Emit(kArmVnegF64, g.DefineAsRegister(node),
754          g.UseDoubleRegister(m.left().node()));
755   } else {
756     VisitRRRFloat64(this, kArmVmulF64, node);
757   }
758 }
759
760
761 void InstructionSelector::VisitFloat64Div(Node* node) {
762   VisitRRRFloat64(this, kArmVdivF64, node);
763 }
764
765
766 void InstructionSelector::VisitFloat64Mod(Node* node) {
767   ArmOperandGenerator g(this);
768   Emit(kArmVmodF64, g.DefineAsFixedDouble(node, d0),
769        g.UseFixedDouble(node->InputAt(0), d0),
770        g.UseFixedDouble(node->InputAt(1), d1))->MarkAsCall();
771 }
772
773
774 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
775                                     BasicBlock* deoptimization) {
776   ArmOperandGenerator g(this);
777   CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call);
778   CallBuffer buffer(zone(), descriptor);  // TODO(turbofan): temp zone here?
779
780   // Compute InstructionOperands for inputs and outputs.
781   // TODO(turbofan): on ARM64 it's probably better to use the code object in a
782   // register if there are multiple uses of it. Improve constant pool and the
783   // heuristics in the register allocator for where to emit constants.
784   InitializeCallBuffer(call, &buffer, true, false, continuation,
785                        deoptimization);
786
787   // TODO(dcarney): might be possible to use claim/poke instead
788   // Push any stack arguments.
789   for (int i = buffer.pushed_count - 1; i >= 0; --i) {
790     Node* input = buffer.pushed_nodes[i];
791     Emit(kArmPush, NULL, g.UseRegister(input));
792   }
793
794   // Select the appropriate opcode based on the call type.
795   InstructionCode opcode;
796   switch (descriptor->kind()) {
797     case CallDescriptor::kCallCodeObject: {
798       bool lazy_deopt = descriptor->CanLazilyDeoptimize();
799       opcode = kArmCallCodeObject | MiscField::encode(lazy_deopt ? 1 : 0);
800       break;
801     }
802     case CallDescriptor::kCallAddress:
803       opcode = kArmCallAddress;
804       break;
805     case CallDescriptor::kCallJSFunction:
806       opcode = kArmCallJSFunction;
807       break;
808     default:
809       UNREACHABLE();
810       return;
811   }
812
813   // Emit the call instruction.
814   Instruction* call_instr =
815       Emit(opcode, buffer.output_count, buffer.outputs,
816            buffer.fixed_and_control_count(), buffer.fixed_and_control_args);
817
818   call_instr->MarkAsCall();
819   if (deoptimization != NULL) {
820     DCHECK(continuation != NULL);
821     call_instr->MarkAsControl();
822   }
823
824   // Caller clean up of stack for C-style calls.
825   if (descriptor->kind() == CallDescriptor::kCallAddress &&
826       buffer.pushed_count > 0) {
827     DCHECK(deoptimization == NULL && continuation == NULL);
828     Emit(kArmDrop | MiscField::encode(buffer.pushed_count), NULL);
829   }
830 }
831
832
833 void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
834                                                     FlagsContinuation* cont) {
835   VisitBinop(this, node, kArmAdd, kArmAdd, cont);
836 }
837
838
839 void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
840                                                     FlagsContinuation* cont) {
841   VisitBinop(this, node, kArmSub, kArmRsb, cont);
842 }
843
844
845 // Shared routine for multiple compare operations.
846 static void VisitWordCompare(InstructionSelector* selector, Node* node,
847                              InstructionCode opcode, FlagsContinuation* cont,
848                              bool commutative) {
849   ArmOperandGenerator g(selector);
850   Int32BinopMatcher m(node);
851   InstructionOperand* inputs[5];
852   size_t input_count = 0;
853   InstructionOperand* outputs[1];
854   size_t output_count = 0;
855
856   if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
857                                &input_count, &inputs[1])) {
858     inputs[0] = g.UseRegister(m.left().node());
859     input_count++;
860   } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
861                                       &input_count, &inputs[1])) {
862     if (!commutative) cont->Commute();
863     inputs[0] = g.UseRegister(m.right().node());
864     input_count++;
865   } else {
866     opcode |= AddressingModeField::encode(kMode_Operand2_R);
867     inputs[input_count++] = g.UseRegister(m.left().node());
868     inputs[input_count++] = g.UseRegister(m.right().node());
869   }
870
871   if (cont->IsBranch()) {
872     inputs[input_count++] = g.Label(cont->true_block());
873     inputs[input_count++] = g.Label(cont->false_block());
874   } else {
875     DCHECK(cont->IsSet());
876     outputs[output_count++] = g.DefineAsRegister(cont->result());
877   }
878
879   DCHECK_NE(0, input_count);
880   DCHECK_GE(ARRAY_SIZE(inputs), input_count);
881   DCHECK_GE(ARRAY_SIZE(outputs), output_count);
882
883   Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
884                                       outputs, input_count, inputs);
885   if (cont->IsBranch()) instr->MarkAsControl();
886 }
887
888
889 void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
890   switch (node->opcode()) {
891     case IrOpcode::kInt32Add:
892       return VisitWordCompare(this, node, kArmCmn, cont, true);
893     case IrOpcode::kInt32Sub:
894       return VisitWordCompare(this, node, kArmCmp, cont, false);
895     case IrOpcode::kWord32And:
896       return VisitWordCompare(this, node, kArmTst, cont, true);
897     case IrOpcode::kWord32Or:
898       return VisitBinop(this, node, kArmOrr, kArmOrr, cont);
899     case IrOpcode::kWord32Xor:
900       return VisitWordCompare(this, node, kArmTeq, cont, true);
901     default:
902       break;
903   }
904
905   ArmOperandGenerator g(this);
906   InstructionCode opcode =
907       cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R);
908   if (cont->IsBranch()) {
909     Emit(opcode, NULL, g.UseRegister(node), g.UseRegister(node),
910          g.Label(cont->true_block()),
911          g.Label(cont->false_block()))->MarkAsControl();
912   } else {
913     Emit(opcode, g.DefineAsRegister(cont->result()), g.UseRegister(node),
914          g.UseRegister(node));
915   }
916 }
917
918
919 void InstructionSelector::VisitWord32Compare(Node* node,
920                                              FlagsContinuation* cont) {
921   VisitWordCompare(this, node, kArmCmp, cont, false);
922 }
923
924
925 void InstructionSelector::VisitFloat64Compare(Node* node,
926                                               FlagsContinuation* cont) {
927   ArmOperandGenerator g(this);
928   Float64BinopMatcher m(node);
929   if (cont->IsBranch()) {
930     Emit(cont->Encode(kArmVcmpF64), NULL, g.UseDoubleRegister(m.left().node()),
931          g.UseDoubleRegister(m.right().node()), g.Label(cont->true_block()),
932          g.Label(cont->false_block()))->MarkAsControl();
933   } else {
934     DCHECK(cont->IsSet());
935     Emit(cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()),
936          g.UseDoubleRegister(m.left().node()),
937          g.UseDoubleRegister(m.right().node()));
938   }
939 }
940
941 }  // namespace compiler
942 }  // namespace internal
943 }  // namespace v8