Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / v8 / src / compiler / arm64 / instruction-selector-arm64.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
8 namespace v8 {
9 namespace internal {
10 namespace compiler {
11
12 enum ImmediateMode {
13   kArithmeticImm,  // 12 bit unsigned immediate shifted left 0 or 12 bits
14   kShift32Imm,     // 0 - 31
15   kShift64Imm,     // 0 - 63
16   kLogical32Imm,
17   kLogical64Imm,
18   kLoadStoreImm8,   // signed 8 bit or 12 bit unsigned scaled by access size
19   kLoadStoreImm16,
20   kLoadStoreImm32,
21   kLoadStoreImm64,
22   kNoImmediate
23 };
24
25
26 // Adds Arm64-specific methods for generating operands.
27 class Arm64OperandGenerator FINAL : public OperandGenerator {
28  public:
29   explicit Arm64OperandGenerator(InstructionSelector* selector)
30       : OperandGenerator(selector) {}
31
32   InstructionOperand* UseOperand(Node* node, ImmediateMode mode) {
33     if (CanBeImmediate(node, mode)) {
34       return UseImmediate(node);
35     }
36     return UseRegister(node);
37   }
38
39   bool CanBeImmediate(Node* node, ImmediateMode mode) {
40     int64_t value;
41     if (node->opcode() == IrOpcode::kInt32Constant)
42       value = OpParameter<int32_t>(node);
43     else if (node->opcode() == IrOpcode::kInt64Constant)
44       value = OpParameter<int64_t>(node);
45     else
46       return false;
47     unsigned ignored;
48     switch (mode) {
49       case kLogical32Imm:
50         // TODO(dcarney): some unencodable values can be handled by
51         // switching instructions.
52         return Assembler::IsImmLogical(static_cast<uint64_t>(value), 32,
53                                        &ignored, &ignored, &ignored);
54       case kLogical64Imm:
55         return Assembler::IsImmLogical(static_cast<uint64_t>(value), 64,
56                                        &ignored, &ignored, &ignored);
57       case kArithmeticImm:
58         // TODO(dcarney): -values can be handled by instruction swapping
59         return Assembler::IsImmAddSub(value);
60       case kShift32Imm:
61         return 0 <= value && value < 32;
62       case kShift64Imm:
63         return 0 <= value && value < 64;
64       case kLoadStoreImm8:
65         return IsLoadStoreImmediate(value, LSByte);
66       case kLoadStoreImm16:
67         return IsLoadStoreImmediate(value, LSHalfword);
68       case kLoadStoreImm32:
69         return IsLoadStoreImmediate(value, LSWord);
70       case kLoadStoreImm64:
71         return IsLoadStoreImmediate(value, LSDoubleWord);
72       case kNoImmediate:
73         return false;
74     }
75     return false;
76   }
77
78  private:
79   bool IsLoadStoreImmediate(int64_t value, LSDataSize size) {
80     return Assembler::IsImmLSScaled(value, size) ||
81            Assembler::IsImmLSUnscaled(value);
82   }
83 };
84
85
86 static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
87                      Node* node) {
88   Arm64OperandGenerator g(selector);
89   selector->Emit(opcode, g.DefineAsRegister(node),
90                  g.UseRegister(node->InputAt(0)),
91                  g.UseRegister(node->InputAt(1)));
92 }
93
94
95 static void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
96                             Node* node) {
97   Arm64OperandGenerator g(selector);
98   selector->Emit(opcode, g.DefineAsRegister(node),
99                  g.UseRegister(node->InputAt(0)),
100                  g.UseRegister(node->InputAt(1)));
101 }
102
103
104 static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode,
105                      Node* node, ImmediateMode operand_mode) {
106   Arm64OperandGenerator g(selector);
107   selector->Emit(opcode, g.DefineAsRegister(node),
108                  g.UseRegister(node->InputAt(0)),
109                  g.UseOperand(node->InputAt(1), operand_mode));
110 }
111
112
113 // Shared routine for multiple binary operations.
114 template <typename Matcher>
115 static void VisitBinop(InstructionSelector* selector, Node* node,
116                        InstructionCode opcode, ImmediateMode operand_mode,
117                        FlagsContinuation* cont) {
118   Arm64OperandGenerator g(selector);
119   Matcher m(node);
120   InstructionOperand* inputs[4];
121   size_t input_count = 0;
122   InstructionOperand* outputs[2];
123   size_t output_count = 0;
124
125   inputs[input_count++] = g.UseRegister(m.left().node());
126   inputs[input_count++] = g.UseOperand(m.right().node(), operand_mode);
127
128   if (cont->IsBranch()) {
129     inputs[input_count++] = g.Label(cont->true_block());
130     inputs[input_count++] = g.Label(cont->false_block());
131   }
132
133   outputs[output_count++] = g.DefineAsRegister(node);
134   if (cont->IsSet()) {
135     outputs[output_count++] = g.DefineAsRegister(cont->result());
136   }
137
138   DCHECK_NE(0, input_count);
139   DCHECK_NE(0, output_count);
140   DCHECK_GE(arraysize(inputs), input_count);
141   DCHECK_GE(arraysize(outputs), output_count);
142
143   Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
144                                       outputs, input_count, inputs);
145   if (cont->IsBranch()) instr->MarkAsControl();
146 }
147
148
149 // Shared routine for multiple binary operations.
150 template <typename Matcher>
151 static void VisitBinop(InstructionSelector* selector, Node* node,
152                        ArchOpcode opcode, ImmediateMode operand_mode) {
153   FlagsContinuation cont;
154   VisitBinop<Matcher>(selector, node, opcode, operand_mode, &cont);
155 }
156
157
158 void InstructionSelector::VisitLoad(Node* node) {
159   MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
160   MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
161   Arm64OperandGenerator g(this);
162   Node* base = node->InputAt(0);
163   Node* index = node->InputAt(1);
164   ArchOpcode opcode;
165   ImmediateMode immediate_mode = kNoImmediate;
166   switch (rep) {
167     case kRepFloat32:
168       opcode = kArm64LdrS;
169       immediate_mode = kLoadStoreImm32;
170       break;
171     case kRepFloat64:
172       opcode = kArm64LdrD;
173       immediate_mode = kLoadStoreImm64;
174       break;
175     case kRepBit:  // Fall through.
176     case kRepWord8:
177       opcode = typ == kTypeInt32 ? kArm64Ldrsb : kArm64Ldrb;
178       immediate_mode = kLoadStoreImm8;
179       break;
180     case kRepWord16:
181       opcode = typ == kTypeInt32 ? kArm64Ldrsh : kArm64Ldrh;
182       immediate_mode = kLoadStoreImm16;
183       break;
184     case kRepWord32:
185       opcode = kArm64LdrW;
186       immediate_mode = kLoadStoreImm32;
187       break;
188     case kRepTagged:  // Fall through.
189     case kRepWord64:
190       opcode = kArm64Ldr;
191       immediate_mode = kLoadStoreImm64;
192       break;
193     default:
194       UNREACHABLE();
195       return;
196   }
197   if (g.CanBeImmediate(index, immediate_mode)) {
198     Emit(opcode | AddressingModeField::encode(kMode_MRI),
199          g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
200   } else {
201     Emit(opcode | AddressingModeField::encode(kMode_MRR),
202          g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
203   }
204 }
205
206
207 void InstructionSelector::VisitStore(Node* node) {
208   Arm64OperandGenerator g(this);
209   Node* base = node->InputAt(0);
210   Node* index = node->InputAt(1);
211   Node* value = node->InputAt(2);
212
213   StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
214   MachineType rep = RepresentationOf(store_rep.machine_type());
215   if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
216     DCHECK(rep == kRepTagged);
217     // TODO(dcarney): refactor RecordWrite function to take temp registers
218     //                and pass them here instead of using fixed regs
219     // TODO(dcarney): handle immediate indices.
220     InstructionOperand* temps[] = {g.TempRegister(x11), g.TempRegister(x12)};
221     Emit(kArm64StoreWriteBarrier, NULL, g.UseFixed(base, x10),
222          g.UseFixed(index, x11), g.UseFixed(value, x12), arraysize(temps),
223          temps);
224     return;
225   }
226   DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
227   ArchOpcode opcode;
228   ImmediateMode immediate_mode = kNoImmediate;
229   switch (rep) {
230     case kRepFloat32:
231       opcode = kArm64StrS;
232       immediate_mode = kLoadStoreImm32;
233       break;
234     case kRepFloat64:
235       opcode = kArm64StrD;
236       immediate_mode = kLoadStoreImm64;
237       break;
238     case kRepBit:  // Fall through.
239     case kRepWord8:
240       opcode = kArm64Strb;
241       immediate_mode = kLoadStoreImm8;
242       break;
243     case kRepWord16:
244       opcode = kArm64Strh;
245       immediate_mode = kLoadStoreImm16;
246       break;
247     case kRepWord32:
248       opcode = kArm64StrW;
249       immediate_mode = kLoadStoreImm32;
250       break;
251     case kRepTagged:  // Fall through.
252     case kRepWord64:
253       opcode = kArm64Str;
254       immediate_mode = kLoadStoreImm64;
255       break;
256     default:
257       UNREACHABLE();
258       return;
259   }
260   if (g.CanBeImmediate(index, immediate_mode)) {
261     Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
262          g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
263   } else {
264     Emit(opcode | AddressingModeField::encode(kMode_MRR), NULL,
265          g.UseRegister(base), g.UseRegister(index), g.UseRegister(value));
266   }
267 }
268
269
270 void InstructionSelector::VisitWord32And(Node* node) {
271   VisitBinop<Int32BinopMatcher>(this, node, kArm64And32, kLogical32Imm);
272 }
273
274
275 void InstructionSelector::VisitWord64And(Node* node) {
276   VisitBinop<Int64BinopMatcher>(this, node, kArm64And, kLogical64Imm);
277 }
278
279
280 void InstructionSelector::VisitWord32Or(Node* node) {
281   VisitBinop<Int32BinopMatcher>(this, node, kArm64Or32, kLogical32Imm);
282 }
283
284
285 void InstructionSelector::VisitWord64Or(Node* node) {
286   VisitBinop<Int64BinopMatcher>(this, node, kArm64Or, kLogical64Imm);
287 }
288
289
290 void InstructionSelector::VisitWord32Xor(Node* node) {
291   Arm64OperandGenerator g(this);
292   Int32BinopMatcher m(node);
293   if (m.right().Is(-1)) {
294     Emit(kArm64Not32, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
295   } else {
296     VisitBinop<Int32BinopMatcher>(this, node, kArm64Xor32, kLogical32Imm);
297   }
298 }
299
300
301 void InstructionSelector::VisitWord64Xor(Node* node) {
302   Arm64OperandGenerator g(this);
303   Int64BinopMatcher m(node);
304   if (m.right().Is(-1)) {
305     Emit(kArm64Not, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
306   } else {
307     VisitBinop<Int64BinopMatcher>(this, node, kArm64Xor, kLogical32Imm);
308   }
309 }
310
311
312 void InstructionSelector::VisitWord32Shl(Node* node) {
313   VisitRRO(this, kArm64Shl32, node, kShift32Imm);
314 }
315
316
317 void InstructionSelector::VisitWord64Shl(Node* node) {
318   VisitRRO(this, kArm64Shl, node, kShift64Imm);
319 }
320
321
322 void InstructionSelector::VisitWord32Shr(Node* node) {
323   VisitRRO(this, kArm64Shr32, node, kShift32Imm);
324 }
325
326
327 void InstructionSelector::VisitWord64Shr(Node* node) {
328   VisitRRO(this, kArm64Shr, node, kShift64Imm);
329 }
330
331
332 void InstructionSelector::VisitWord32Sar(Node* node) {
333   VisitRRO(this, kArm64Sar32, node, kShift32Imm);
334 }
335
336
337 void InstructionSelector::VisitWord64Sar(Node* node) {
338   VisitRRO(this, kArm64Sar, node, kShift64Imm);
339 }
340
341
342 void InstructionSelector::VisitWord32Ror(Node* node) {
343   VisitRRO(this, kArm64Ror32, node, kShift32Imm);
344 }
345
346
347 void InstructionSelector::VisitWord64Ror(Node* node) {
348   VisitRRO(this, kArm64Ror, node, kShift64Imm);
349 }
350
351
352 void InstructionSelector::VisitInt32Add(Node* node) {
353   VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32, kArithmeticImm);
354 }
355
356
357 void InstructionSelector::VisitInt64Add(Node* node) {
358   VisitBinop<Int64BinopMatcher>(this, node, kArm64Add, kArithmeticImm);
359 }
360
361
362 void InstructionSelector::VisitInt32Sub(Node* node) {
363   Arm64OperandGenerator g(this);
364   Int32BinopMatcher m(node);
365   if (m.left().Is(0)) {
366     Emit(kArm64Neg32, g.DefineAsRegister(node),
367          g.UseRegister(m.right().node()));
368   } else {
369     VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32, kArithmeticImm);
370   }
371 }
372
373
374 void InstructionSelector::VisitInt64Sub(Node* node) {
375   Arm64OperandGenerator g(this);
376   Int64BinopMatcher m(node);
377   if (m.left().Is(0)) {
378     Emit(kArm64Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node()));
379   } else {
380     VisitBinop<Int64BinopMatcher>(this, node, kArm64Sub, kArithmeticImm);
381   }
382 }
383
384
385 void InstructionSelector::VisitInt32Mul(Node* node) {
386   VisitRRR(this, kArm64Mul32, node);
387 }
388
389
390 void InstructionSelector::VisitInt64Mul(Node* node) {
391   VisitRRR(this, kArm64Mul, node);
392 }
393
394
395 void InstructionSelector::VisitInt32Div(Node* node) {
396   VisitRRR(this, kArm64Idiv32, node);
397 }
398
399
400 void InstructionSelector::VisitInt64Div(Node* node) {
401   VisitRRR(this, kArm64Idiv, node);
402 }
403
404
405 void InstructionSelector::VisitInt32UDiv(Node* node) {
406   VisitRRR(this, kArm64Udiv32, node);
407 }
408
409
410 void InstructionSelector::VisitInt64UDiv(Node* node) {
411   VisitRRR(this, kArm64Udiv, node);
412 }
413
414
415 void InstructionSelector::VisitInt32Mod(Node* node) {
416   VisitRRR(this, kArm64Imod32, node);
417 }
418
419
420 void InstructionSelector::VisitInt64Mod(Node* node) {
421   VisitRRR(this, kArm64Imod, node);
422 }
423
424
425 void InstructionSelector::VisitInt32UMod(Node* node) {
426   VisitRRR(this, kArm64Umod32, node);
427 }
428
429
430 void InstructionSelector::VisitInt64UMod(Node* node) {
431   VisitRRR(this, kArm64Umod, node);
432 }
433
434
435 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
436   Arm64OperandGenerator g(this);
437   Emit(kArm64Int32ToFloat64, g.DefineAsRegister(node),
438        g.UseRegister(node->InputAt(0)));
439 }
440
441
442 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
443   Arm64OperandGenerator g(this);
444   Emit(kArm64Uint32ToFloat64, g.DefineAsRegister(node),
445        g.UseRegister(node->InputAt(0)));
446 }
447
448
449 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
450   Arm64OperandGenerator g(this);
451   Emit(kArm64Float64ToInt32, g.DefineAsRegister(node),
452        g.UseRegister(node->InputAt(0)));
453 }
454
455
456 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
457   Arm64OperandGenerator g(this);
458   Emit(kArm64Float64ToUint32, g.DefineAsRegister(node),
459        g.UseRegister(node->InputAt(0)));
460 }
461
462
463 void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
464   Arm64OperandGenerator g(this);
465   Emit(kArm64Sxtw, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
466 }
467
468
469 void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
470   Arm64OperandGenerator g(this);
471   Emit(kArm64Mov32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
472 }
473
474
475 void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
476   Arm64OperandGenerator g(this);
477   Emit(kArm64Mov32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
478 }
479
480
481 void InstructionSelector::VisitFloat64Add(Node* node) {
482   VisitRRRFloat64(this, kArm64Float64Add, node);
483 }
484
485
486 void InstructionSelector::VisitFloat64Sub(Node* node) {
487   VisitRRRFloat64(this, kArm64Float64Sub, node);
488 }
489
490
491 void InstructionSelector::VisitFloat64Mul(Node* node) {
492   VisitRRRFloat64(this, kArm64Float64Mul, node);
493 }
494
495
496 void InstructionSelector::VisitFloat64Div(Node* node) {
497   VisitRRRFloat64(this, kArm64Float64Div, node);
498 }
499
500
501 void InstructionSelector::VisitFloat64Mod(Node* node) {
502   Arm64OperandGenerator g(this);
503   Emit(kArm64Float64Mod, g.DefineAsFixed(node, d0),
504        g.UseFixed(node->InputAt(0), d0),
505        g.UseFixed(node->InputAt(1), d1))->MarkAsCall();
506 }
507
508
509 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
510   Arm64OperandGenerator g(this);
511   Emit(kArm64Float64Sqrt, g.DefineAsRegister(node),
512        g.UseRegister(node->InputAt(0)));
513 }
514
515
516 void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
517                                                     FlagsContinuation* cont) {
518   VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32, kArithmeticImm, cont);
519 }
520
521
522 void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
523                                                     FlagsContinuation* cont) {
524   VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32, kArithmeticImm, cont);
525 }
526
527
528 // Shared routine for multiple compare operations.
529 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
530                          InstructionOperand* left, InstructionOperand* right,
531                          FlagsContinuation* cont) {
532   Arm64OperandGenerator g(selector);
533   opcode = cont->Encode(opcode);
534   if (cont->IsBranch()) {
535     selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
536                    g.Label(cont->false_block()))->MarkAsControl();
537   } else {
538     DCHECK(cont->IsSet());
539     selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
540   }
541 }
542
543
544 // Shared routine for multiple word compare operations.
545 static void VisitWordCompare(InstructionSelector* selector, Node* node,
546                              InstructionCode opcode, FlagsContinuation* cont,
547                              bool commutative) {
548   Arm64OperandGenerator g(selector);
549   Node* left = node->InputAt(0);
550   Node* right = node->InputAt(1);
551
552   // Match immediates on left or right side of comparison.
553   if (g.CanBeImmediate(right, kArithmeticImm)) {
554     VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
555                  cont);
556   } else if (g.CanBeImmediate(left, kArithmeticImm)) {
557     if (!commutative) cont->Commute();
558     VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
559                  cont);
560   } else {
561     VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
562                  cont);
563   }
564 }
565
566
567 void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
568   switch (node->opcode()) {
569     case IrOpcode::kInt32Add:
570       return VisitWordCompare(this, node, kArm64Cmn32, cont, true);
571     case IrOpcode::kInt32Sub:
572       return VisitWordCompare(this, node, kArm64Cmp32, cont, false);
573     case IrOpcode::kWord32And:
574       return VisitWordCompare(this, node, kArm64Tst32, cont, true);
575     default:
576       break;
577   }
578
579   Arm64OperandGenerator g(this);
580   VisitCompare(this, kArm64Tst32, g.UseRegister(node), g.UseRegister(node),
581                cont);
582 }
583
584
585 void InstructionSelector::VisitWord64Test(Node* node, FlagsContinuation* cont) {
586   switch (node->opcode()) {
587     case IrOpcode::kWord64And:
588       return VisitWordCompare(this, node, kArm64Tst, cont, true);
589     default:
590       break;
591   }
592
593   Arm64OperandGenerator g(this);
594   VisitCompare(this, kArm64Tst, g.UseRegister(node), g.UseRegister(node), cont);
595 }
596
597
598 void InstructionSelector::VisitWord32Compare(Node* node,
599                                              FlagsContinuation* cont) {
600   VisitWordCompare(this, node, kArm64Cmp32, cont, false);
601 }
602
603
604 void InstructionSelector::VisitWord64Compare(Node* node,
605                                              FlagsContinuation* cont) {
606   VisitWordCompare(this, node, kArm64Cmp, cont, false);
607 }
608
609
610 void InstructionSelector::VisitFloat64Compare(Node* node,
611                                               FlagsContinuation* cont) {
612   Arm64OperandGenerator g(this);
613   Node* left = node->InputAt(0);
614   Node* right = node->InputAt(1);
615   VisitCompare(this, kArm64Float64Cmp, g.UseRegister(left),
616                g.UseRegister(right), cont);
617 }
618
619
620 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
621                                     BasicBlock* deoptimization) {
622   Arm64OperandGenerator g(this);
623   CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call);
624
625   FrameStateDescriptor* frame_state_descriptor = NULL;
626   if (descriptor->NeedsFrameState()) {
627     frame_state_descriptor =
628         GetFrameStateDescriptor(call->InputAt(descriptor->InputCount()));
629   }
630
631   CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
632
633   // Compute InstructionOperands for inputs and outputs.
634   // TODO(turbofan): on ARM64 it's probably better to use the code object in a
635   // register if there are multiple uses of it. Improve constant pool and the
636   // heuristics in the register allocator for where to emit constants.
637   InitializeCallBuffer(call, &buffer, true, false);
638
639   // Push the arguments to the stack.
640   bool pushed_count_uneven = buffer.pushed_nodes.size() & 1;
641   int aligned_push_count = buffer.pushed_nodes.size();
642   // TODO(dcarney): claim and poke probably take small immediates,
643   //                loop here or whatever.
644   // Bump the stack pointer(s).
645   if (aligned_push_count > 0) {
646     // TODO(dcarney): it would be better to bump the csp here only
647     //                and emit paired stores with increment for non c frames.
648     Emit(kArm64Claim | MiscField::encode(aligned_push_count), NULL);
649   }
650   // Move arguments to the stack.
651   {
652     int slot = buffer.pushed_nodes.size() - 1;
653     // Emit the uneven pushes.
654     if (pushed_count_uneven) {
655       Node* input = buffer.pushed_nodes[slot];
656       Emit(kArm64Poke | MiscField::encode(slot), NULL, g.UseRegister(input));
657       slot--;
658     }
659     // Now all pushes can be done in pairs.
660     for (; slot >= 0; slot -= 2) {
661       Emit(kArm64PokePair | MiscField::encode(slot), NULL,
662            g.UseRegister(buffer.pushed_nodes[slot]),
663            g.UseRegister(buffer.pushed_nodes[slot - 1]));
664     }
665   }
666
667   // Select the appropriate opcode based on the call type.
668   InstructionCode opcode;
669   switch (descriptor->kind()) {
670     case CallDescriptor::kCallCodeObject: {
671       opcode = kArchCallCodeObject;
672       break;
673     }
674     case CallDescriptor::kCallJSFunction:
675       opcode = kArchCallJSFunction;
676       break;
677     default:
678       UNREACHABLE();
679       return;
680   }
681   opcode |= MiscField::encode(descriptor->flags());
682
683   // Emit the call instruction.
684   Instruction* call_instr =
685       Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
686            buffer.instruction_args.size(), &buffer.instruction_args.front());
687
688   call_instr->MarkAsCall();
689   if (deoptimization != NULL) {
690     DCHECK(continuation != NULL);
691     call_instr->MarkAsControl();
692   }
693 }
694
695 }  // namespace compiler
696 }  // namespace internal
697 }  // namespace v8