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
8namespace v8 {
9namespace internal {
10namespace compiler {
11
12// Adds X64-specific methods for generating operands.
13class X64OperandGenerator FINAL : public OperandGenerator {
14 public:
15  explicit X64OperandGenerator(InstructionSelector* selector)
16      : OperandGenerator(selector) {}
17
18  InstructionOperand* TempRegister(Register reg) {
19    return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
20                                           Register::ToAllocationIndex(reg));
21  }
22
23  InstructionOperand* UseByteRegister(Node* node) {
24    // TODO(dcarney): relax constraint.
25    return UseFixed(node, rdx);
26  }
27
28  InstructionOperand* UseImmediate64(Node* node) { return UseImmediate(node); }
29
30  bool CanBeImmediate(Node* node) {
31    switch (node->opcode()) {
32      case IrOpcode::kInt32Constant:
33        return true;
34      default:
35        return false;
36    }
37  }
38
39  bool CanBeImmediate64(Node* node) {
40    switch (node->opcode()) {
41      case IrOpcode::kInt32Constant:
42        return true;
43      case IrOpcode::kNumberConstant:
44        return true;
45      case IrOpcode::kHeapConstant: {
46        // Constants in new space cannot be used as immediates in V8 because
47        // the GC does not scan code objects when collecting the new generation.
48        Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node);
49        return !isolate()->heap()->InNewSpace(*value.handle());
50      }
51      default:
52        return false;
53    }
54  }
55};
56
57
58void InstructionSelector::VisitLoad(Node* node) {
59  MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
60  MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
61  X64OperandGenerator g(this);
62  Node* base = node->InputAt(0);
63  Node* index = node->InputAt(1);
64
65  ArchOpcode opcode;
66  // TODO(titzer): signed/unsigned small loads
67  switch (rep) {
68    case kRepFloat32:
69      opcode = kX64Movss;
70      break;
71    case kRepFloat64:
72      opcode = kX64Movsd;
73      break;
74    case kRepBit:  // Fall through.
75    case kRepWord8:
76      opcode = typ == kTypeInt32 ? kX64Movsxbl : kX64Movzxbl;
77      break;
78    case kRepWord16:
79      opcode = typ == kTypeInt32 ? kX64Movsxwl : kX64Movzxwl;
80      break;
81    case kRepWord32:
82      opcode = kX64Movl;
83      break;
84    case kRepTagged:  // Fall through.
85    case kRepWord64:
86      opcode = kX64Movq;
87      break;
88    default:
89      UNREACHABLE();
90      return;
91  }
92  if (g.CanBeImmediate(base)) {
93    // load [#base + %index]
94    Emit(opcode | AddressingModeField::encode(kMode_MRI),
95         g.DefineAsRegister(node), g.UseRegister(index), g.UseImmediate(base));
96  } else if (g.CanBeImmediate(index)) {  // load [%base + #index]
97    Emit(opcode | AddressingModeField::encode(kMode_MRI),
98         g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
99  } else {  // load [%base + %index + K]
100    Emit(opcode | AddressingModeField::encode(kMode_MR1I),
101         g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
102  }
103  // TODO(turbofan): addressing modes [r+r*{2,4,8}+K]
104}
105
106
107void InstructionSelector::VisitStore(Node* node) {
108  X64OperandGenerator g(this);
109  Node* base = node->InputAt(0);
110  Node* index = node->InputAt(1);
111  Node* value = node->InputAt(2);
112
113  StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
114  MachineType rep = RepresentationOf(store_rep.machine_type());
115  if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
116    DCHECK(rep == kRepTagged);
117    // TODO(dcarney): refactor RecordWrite function to take temp registers
118    //                and pass them here instead of using fixed regs
119    // TODO(dcarney): handle immediate indices.
120    InstructionOperand* temps[] = {g.TempRegister(rcx), g.TempRegister(rdx)};
121    Emit(kX64StoreWriteBarrier, NULL, g.UseFixed(base, rbx),
122         g.UseFixed(index, rcx), g.UseFixed(value, rdx), arraysize(temps),
123         temps);
124    return;
125  }
126  DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
127  InstructionOperand* val;
128  if (g.CanBeImmediate(value)) {
129    val = g.UseImmediate(value);
130  } else if (rep == kRepWord8 || rep == kRepBit) {
131    val = g.UseByteRegister(value);
132  } else {
133    val = g.UseRegister(value);
134  }
135  ArchOpcode opcode;
136  switch (rep) {
137    case kRepFloat32:
138      opcode = kX64Movss;
139      break;
140    case kRepFloat64:
141      opcode = kX64Movsd;
142      break;
143    case kRepBit:  // Fall through.
144    case kRepWord8:
145      opcode = kX64Movb;
146      break;
147    case kRepWord16:
148      opcode = kX64Movw;
149      break;
150    case kRepWord32:
151      opcode = kX64Movl;
152      break;
153    case kRepTagged:  // Fall through.
154    case kRepWord64:
155      opcode = kX64Movq;
156      break;
157    default:
158      UNREACHABLE();
159      return;
160  }
161  if (g.CanBeImmediate(base)) {
162    // store [#base + %index], %|#value
163    Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
164         g.UseRegister(index), g.UseImmediate(base), val);
165  } else if (g.CanBeImmediate(index)) {  // store [%base + #index], %|#value
166    Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
167         g.UseRegister(base), g.UseImmediate(index), val);
168  } else {  // store [%base + %index], %|#value
169    Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL,
170         g.UseRegister(base), g.UseRegister(index), val);
171  }
172  // TODO(turbofan): addressing modes [r+r*{2,4,8}+K]
173}
174
175
176// Shared routine for multiple binary operations.
177static void VisitBinop(InstructionSelector* selector, Node* node,
178                       InstructionCode opcode, FlagsContinuation* cont) {
179  X64OperandGenerator g(selector);
180  Int32BinopMatcher m(node);
181  InstructionOperand* inputs[4];
182  size_t input_count = 0;
183  InstructionOperand* outputs[2];
184  size_t output_count = 0;
185
186  // TODO(turbofan): match complex addressing modes.
187  // TODO(turbofan): if commutative, pick the non-live-in operand as the left as
188  // this might be the last use and therefore its register can be reused.
189  if (g.CanBeImmediate(m.right().node())) {
190    inputs[input_count++] = g.Use(m.left().node());
191    inputs[input_count++] = g.UseImmediate(m.right().node());
192  } else {
193    inputs[input_count++] = g.UseRegister(m.left().node());
194    inputs[input_count++] = g.Use(m.right().node());
195  }
196
197  if (cont->IsBranch()) {
198    inputs[input_count++] = g.Label(cont->true_block());
199    inputs[input_count++] = g.Label(cont->false_block());
200  }
201
202  outputs[output_count++] = g.DefineSameAsFirst(node);
203  if (cont->IsSet()) {
204    outputs[output_count++] = g.DefineAsRegister(cont->result());
205  }
206
207  DCHECK_NE(0, input_count);
208  DCHECK_NE(0, output_count);
209  DCHECK_GE(arraysize(inputs), input_count);
210  DCHECK_GE(arraysize(outputs), output_count);
211
212  Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
213                                      outputs, input_count, inputs);
214  if (cont->IsBranch()) instr->MarkAsControl();
215}
216
217
218// Shared routine for multiple binary operations.
219static void VisitBinop(InstructionSelector* selector, Node* node,
220                       InstructionCode opcode) {
221  FlagsContinuation cont;
222  VisitBinop(selector, node, opcode, &cont);
223}
224
225
226void InstructionSelector::VisitWord32And(Node* node) {
227  VisitBinop(this, node, kX64And32);
228}
229
230
231void InstructionSelector::VisitWord64And(Node* node) {
232  VisitBinop(this, node, kX64And);
233}
234
235
236void InstructionSelector::VisitWord32Or(Node* node) {
237  VisitBinop(this, node, kX64Or32);
238}
239
240
241void InstructionSelector::VisitWord64Or(Node* node) {
242  VisitBinop(this, node, kX64Or);
243}
244
245
246void InstructionSelector::VisitWord32Xor(Node* node) {
247  X64OperandGenerator g(this);
248  Uint32BinopMatcher m(node);
249  if (m.right().Is(-1)) {
250    Emit(kX64Not32, g.DefineSameAsFirst(node), g.Use(m.left().node()));
251  } else {
252    VisitBinop(this, node, kX64Xor32);
253  }
254}
255
256
257void InstructionSelector::VisitWord64Xor(Node* node) {
258  X64OperandGenerator g(this);
259  Uint64BinopMatcher m(node);
260  if (m.right().Is(-1)) {
261    Emit(kX64Not, g.DefineSameAsFirst(node), g.Use(m.left().node()));
262  } else {
263    VisitBinop(this, node, kX64Xor);
264  }
265}
266
267
268// Shared routine for multiple 32-bit shift operations.
269// TODO(bmeurer): Merge this with VisitWord64Shift using template magic?
270static void VisitWord32Shift(InstructionSelector* selector, Node* node,
271                             ArchOpcode opcode) {
272  X64OperandGenerator g(selector);
273  Node* left = node->InputAt(0);
274  Node* right = node->InputAt(1);
275
276  // TODO(turbofan): assembler only supports some addressing modes for shifts.
277  if (g.CanBeImmediate(right)) {
278    selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
279                   g.UseImmediate(right));
280  } else {
281    Int32BinopMatcher m(node);
282    if (m.right().IsWord32And()) {
283      Int32BinopMatcher mright(right);
284      if (mright.right().Is(0x1F)) {
285        right = mright.left().node();
286      }
287    }
288    selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
289                   g.UseFixed(right, rcx));
290  }
291}
292
293
294// Shared routine for multiple 64-bit shift operations.
295// TODO(bmeurer): Merge this with VisitWord32Shift using template magic?
296static void VisitWord64Shift(InstructionSelector* selector, Node* node,
297                             ArchOpcode opcode) {
298  X64OperandGenerator g(selector);
299  Node* left = node->InputAt(0);
300  Node* right = node->InputAt(1);
301
302  // TODO(turbofan): assembler only supports some addressing modes for shifts.
303  if (g.CanBeImmediate(right)) {
304    selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
305                   g.UseImmediate(right));
306  } else {
307    Int64BinopMatcher m(node);
308    if (m.right().IsWord64And()) {
309      Int64BinopMatcher mright(right);
310      if (mright.right().Is(0x3F)) {
311        right = mright.left().node();
312      }
313    }
314    selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
315                   g.UseFixed(right, rcx));
316  }
317}
318
319
320void InstructionSelector::VisitWord32Shl(Node* node) {
321  VisitWord32Shift(this, node, kX64Shl32);
322}
323
324
325void InstructionSelector::VisitWord64Shl(Node* node) {
326  VisitWord64Shift(this, node, kX64Shl);
327}
328
329
330void InstructionSelector::VisitWord32Shr(Node* node) {
331  VisitWord32Shift(this, node, kX64Shr32);
332}
333
334
335void InstructionSelector::VisitWord64Shr(Node* node) {
336  VisitWord64Shift(this, node, kX64Shr);
337}
338
339
340void InstructionSelector::VisitWord32Sar(Node* node) {
341  VisitWord32Shift(this, node, kX64Sar32);
342}
343
344
345void InstructionSelector::VisitWord64Sar(Node* node) {
346  VisitWord64Shift(this, node, kX64Sar);
347}
348
349
350void InstructionSelector::VisitWord32Ror(Node* node) {
351  VisitWord32Shift(this, node, kX64Ror32);
352}
353
354
355void InstructionSelector::VisitWord64Ror(Node* node) {
356  VisitWord64Shift(this, node, kX64Ror);
357}
358
359
360void InstructionSelector::VisitInt32Add(Node* node) {
361  VisitBinop(this, node, kX64Add32);
362}
363
364
365void InstructionSelector::VisitInt64Add(Node* node) {
366  VisitBinop(this, node, kX64Add);
367}
368
369
370void InstructionSelector::VisitInt32Sub(Node* node) {
371  X64OperandGenerator g(this);
372  Int32BinopMatcher m(node);
373  if (m.left().Is(0)) {
374    Emit(kX64Neg32, g.DefineSameAsFirst(node), g.Use(m.right().node()));
375  } else {
376    VisitBinop(this, node, kX64Sub32);
377  }
378}
379
380
381void InstructionSelector::VisitInt64Sub(Node* node) {
382  X64OperandGenerator g(this);
383  Int64BinopMatcher m(node);
384  if (m.left().Is(0)) {
385    Emit(kX64Neg, g.DefineSameAsFirst(node), g.Use(m.right().node()));
386  } else {
387    VisitBinop(this, node, kX64Sub);
388  }
389}
390
391
392static void VisitMul(InstructionSelector* selector, Node* node,
393                     ArchOpcode opcode) {
394  X64OperandGenerator g(selector);
395  Node* left = node->InputAt(0);
396  Node* right = node->InputAt(1);
397  if (g.CanBeImmediate(right)) {
398    selector->Emit(opcode, g.DefineAsRegister(node), g.Use(left),
399                   g.UseImmediate(right));
400  } else if (g.CanBeImmediate(left)) {
401    selector->Emit(opcode, g.DefineAsRegister(node), g.Use(right),
402                   g.UseImmediate(left));
403  } else {
404    // TODO(turbofan): select better left operand.
405    selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
406                   g.Use(right));
407  }
408}
409
410
411void InstructionSelector::VisitInt32Mul(Node* node) {
412  VisitMul(this, node, kX64Imul32);
413}
414
415
416void InstructionSelector::VisitInt64Mul(Node* node) {
417  VisitMul(this, node, kX64Imul);
418}
419
420
421static void VisitDiv(InstructionSelector* selector, Node* node,
422                     ArchOpcode opcode) {
423  X64OperandGenerator g(selector);
424  InstructionOperand* temps[] = {g.TempRegister(rdx)};
425  selector->Emit(
426      opcode, g.DefineAsFixed(node, rax), g.UseFixed(node->InputAt(0), rax),
427      g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
428}
429
430
431void InstructionSelector::VisitInt32Div(Node* node) {
432  VisitDiv(this, node, kX64Idiv32);
433}
434
435
436void InstructionSelector::VisitInt64Div(Node* node) {
437  VisitDiv(this, node, kX64Idiv);
438}
439
440
441void InstructionSelector::VisitInt32UDiv(Node* node) {
442  VisitDiv(this, node, kX64Udiv32);
443}
444
445
446void InstructionSelector::VisitInt64UDiv(Node* node) {
447  VisitDiv(this, node, kX64Udiv);
448}
449
450
451static void VisitMod(InstructionSelector* selector, Node* node,
452                     ArchOpcode opcode) {
453  X64OperandGenerator g(selector);
454  InstructionOperand* temps[] = {g.TempRegister(rax), g.TempRegister(rdx)};
455  selector->Emit(
456      opcode, g.DefineAsFixed(node, rdx), g.UseFixed(node->InputAt(0), rax),
457      g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
458}
459
460
461void InstructionSelector::VisitInt32Mod(Node* node) {
462  VisitMod(this, node, kX64Idiv32);
463}
464
465
466void InstructionSelector::VisitInt64Mod(Node* node) {
467  VisitMod(this, node, kX64Idiv);
468}
469
470
471void InstructionSelector::VisitInt32UMod(Node* node) {
472  VisitMod(this, node, kX64Udiv32);
473}
474
475
476void InstructionSelector::VisitInt64UMod(Node* node) {
477  VisitMod(this, node, kX64Udiv);
478}
479
480
481void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
482  X64OperandGenerator g(this);
483  Emit(kSSEInt32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
484}
485
486
487void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
488  X64OperandGenerator g(this);
489  // TODO(turbofan): X64 SSE cvtqsi2sd should support operands.
490  Emit(kSSEUint32ToFloat64, g.DefineAsRegister(node),
491       g.UseRegister(node->InputAt(0)));
492}
493
494
495void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
496  X64OperandGenerator g(this);
497  Emit(kSSEFloat64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
498}
499
500
501void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
502  X64OperandGenerator g(this);
503  Emit(kSSEFloat64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
504}
505
506
507void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
508  X64OperandGenerator g(this);
509  Emit(kX64Movsxlq, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
510}
511
512
513void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
514  X64OperandGenerator g(this);
515  Emit(kX64Movl, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
516}
517
518
519void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
520  X64OperandGenerator g(this);
521  Emit(kX64Movl, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
522}
523
524
525void InstructionSelector::VisitFloat64Add(Node* node) {
526  X64OperandGenerator g(this);
527  Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
528       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
529}
530
531
532void InstructionSelector::VisitFloat64Sub(Node* node) {
533  X64OperandGenerator g(this);
534  Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
535       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
536}
537
538
539void InstructionSelector::VisitFloat64Mul(Node* node) {
540  X64OperandGenerator g(this);
541  Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
542       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
543}
544
545
546void InstructionSelector::VisitFloat64Div(Node* node) {
547  X64OperandGenerator g(this);
548  Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
549       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
550}
551
552
553void InstructionSelector::VisitFloat64Mod(Node* node) {
554  X64OperandGenerator g(this);
555  InstructionOperand* temps[] = {g.TempRegister(rax)};
556  Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node),
557       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1,
558       temps);
559}
560
561
562void InstructionSelector::VisitFloat64Sqrt(Node* node) {
563  X64OperandGenerator g(this);
564  Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
565}
566
567
568void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
569                                                    FlagsContinuation* cont) {
570  VisitBinop(this, node, kX64Add32, cont);
571}
572
573
574void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
575                                                    FlagsContinuation* cont) {
576  VisitBinop(this, node, kX64Sub32, cont);
577}
578
579
580// Shared routine for multiple compare operations.
581static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
582                         InstructionOperand* left, InstructionOperand* right,
583                         FlagsContinuation* cont) {
584  X64OperandGenerator g(selector);
585  opcode = cont->Encode(opcode);
586  if (cont->IsBranch()) {
587    selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
588                   g.Label(cont->false_block()))->MarkAsControl();
589  } else {
590    DCHECK(cont->IsSet());
591    selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
592  }
593}
594
595
596// Shared routine for multiple word compare operations.
597static void VisitWordCompare(InstructionSelector* selector, Node* node,
598                             InstructionCode opcode, FlagsContinuation* cont,
599                             bool commutative) {
600  X64OperandGenerator g(selector);
601  Node* left = node->InputAt(0);
602  Node* right = node->InputAt(1);
603
604  // Match immediates on left or right side of comparison.
605  if (g.CanBeImmediate(right)) {
606    VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont);
607  } else if (g.CanBeImmediate(left)) {
608    if (!commutative) cont->Commute();
609    VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont);
610  } else {
611    VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
612  }
613}
614
615
616void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
617  switch (node->opcode()) {
618    case IrOpcode::kInt32Sub:
619      return VisitWordCompare(this, node, kX64Cmp32, cont, false);
620    case IrOpcode::kWord32And:
621      return VisitWordCompare(this, node, kX64Test32, cont, true);
622    default:
623      break;
624  }
625
626  X64OperandGenerator g(this);
627  VisitCompare(this, kX64Test32, g.Use(node), g.TempImmediate(-1), cont);
628}
629
630
631void InstructionSelector::VisitWord64Test(Node* node, FlagsContinuation* cont) {
632  switch (node->opcode()) {
633    case IrOpcode::kInt64Sub:
634      return VisitWordCompare(this, node, kX64Cmp, cont, false);
635    case IrOpcode::kWord64And:
636      return VisitWordCompare(this, node, kX64Test, cont, true);
637    default:
638      break;
639  }
640
641  X64OperandGenerator g(this);
642  VisitCompare(this, kX64Test, g.Use(node), g.TempImmediate(-1), cont);
643}
644
645
646void InstructionSelector::VisitWord32Compare(Node* node,
647                                             FlagsContinuation* cont) {
648  VisitWordCompare(this, node, kX64Cmp32, cont, false);
649}
650
651
652void InstructionSelector::VisitWord64Compare(Node* node,
653                                             FlagsContinuation* cont) {
654  VisitWordCompare(this, node, kX64Cmp, cont, false);
655}
656
657
658void InstructionSelector::VisitFloat64Compare(Node* node,
659                                              FlagsContinuation* cont) {
660  X64OperandGenerator g(this);
661  Node* left = node->InputAt(0);
662  Node* right = node->InputAt(1);
663  VisitCompare(this, kSSEFloat64Cmp, g.UseRegister(left), g.Use(right), cont);
664}
665
666
667void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
668                                    BasicBlock* deoptimization) {
669  X64OperandGenerator g(this);
670  CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call);
671
672  FrameStateDescriptor* frame_state_descriptor = NULL;
673  if (descriptor->NeedsFrameState()) {
674    frame_state_descriptor = GetFrameStateDescriptor(
675        call->InputAt(static_cast<int>(descriptor->InputCount())));
676  }
677
678  CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
679
680  // Compute InstructionOperands for inputs and outputs.
681  InitializeCallBuffer(call, &buffer, true, true);
682
683  // TODO(dcarney): stack alignment for c calls.
684  // TODO(dcarney): shadow space on window for c calls.
685  // Push any stack arguments.
686  for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
687       input != buffer.pushed_nodes.rend(); input++) {
688    // TODO(titzer): handle pushing double parameters.
689    Emit(kX64Push, NULL,
690         g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input));
691  }
692
693  // Select the appropriate opcode based on the call type.
694  InstructionCode opcode;
695  switch (descriptor->kind()) {
696    case CallDescriptor::kCallCodeObject: {
697      opcode = kArchCallCodeObject;
698      break;
699    }
700    case CallDescriptor::kCallJSFunction:
701      opcode = kArchCallJSFunction;
702      break;
703    default:
704      UNREACHABLE();
705      return;
706  }
707  opcode |= MiscField::encode(descriptor->flags());
708
709  // Emit the call instruction.
710  Instruction* call_instr =
711      Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
712           buffer.instruction_args.size(), &buffer.instruction_args.front());
713
714  call_instr->MarkAsCall();
715  if (deoptimization != NULL) {
716    DCHECK(continuation != NULL);
717    call_instr->MarkAsControl();
718  }
719}
720
721}  // namespace compiler
722}  // namespace internal
723}  // namespace v8
724