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:
Arm64OperandGenerator(InstructionSelector * selector)29   explicit Arm64OperandGenerator(InstructionSelector* selector)
30       : OperandGenerator(selector) {}
31 
UseOperand(Node * node,ImmediateMode mode)32   InstructionOperand* UseOperand(Node* node, ImmediateMode mode) {
33     if (CanBeImmediate(node, mode)) {
34       return UseImmediate(node);
35     }
36     return UseRegister(node);
37   }
38 
CanBeImmediate(Node * node,ImmediateMode mode)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:
IsLoadStoreImmediate(int64_t value,LSDataSize size)79   bool IsLoadStoreImmediate(int64_t value, LSDataSize size) {
80     return Assembler::IsImmLSScaled(value, size) ||
81            Assembler::IsImmLSUnscaled(value);
82   }
83 };
84 
85 
VisitRRR(InstructionSelector * selector,ArchOpcode opcode,Node * node)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 
VisitRRRFloat64(InstructionSelector * selector,ArchOpcode opcode,Node * node)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 
VisitRRO(InstructionSelector * selector,ArchOpcode opcode,Node * node,ImmediateMode operand_mode)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>
VisitBinop(InstructionSelector * selector,Node * node,InstructionCode opcode,ImmediateMode operand_mode,FlagsContinuation * cont)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>
VisitBinop(InstructionSelector * selector,Node * node,ArchOpcode opcode,ImmediateMode operand_mode)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 
VisitLoad(Node * node)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 
VisitStore(Node * node)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 
VisitWord32And(Node * node)270 void InstructionSelector::VisitWord32And(Node* node) {
271   VisitBinop<Int32BinopMatcher>(this, node, kArm64And32, kLogical32Imm);
272 }
273 
274 
VisitWord64And(Node * node)275 void InstructionSelector::VisitWord64And(Node* node) {
276   VisitBinop<Int64BinopMatcher>(this, node, kArm64And, kLogical64Imm);
277 }
278 
279 
VisitWord32Or(Node * node)280 void InstructionSelector::VisitWord32Or(Node* node) {
281   VisitBinop<Int32BinopMatcher>(this, node, kArm64Or32, kLogical32Imm);
282 }
283 
284 
VisitWord64Or(Node * node)285 void InstructionSelector::VisitWord64Or(Node* node) {
286   VisitBinop<Int64BinopMatcher>(this, node, kArm64Or, kLogical64Imm);
287 }
288 
289 
VisitWord32Xor(Node * node)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 
VisitWord64Xor(Node * node)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 
VisitWord32Shl(Node * node)312 void InstructionSelector::VisitWord32Shl(Node* node) {
313   VisitRRO(this, kArm64Shl32, node, kShift32Imm);
314 }
315 
316 
VisitWord64Shl(Node * node)317 void InstructionSelector::VisitWord64Shl(Node* node) {
318   VisitRRO(this, kArm64Shl, node, kShift64Imm);
319 }
320 
321 
VisitWord32Shr(Node * node)322 void InstructionSelector::VisitWord32Shr(Node* node) {
323   VisitRRO(this, kArm64Shr32, node, kShift32Imm);
324 }
325 
326 
VisitWord64Shr(Node * node)327 void InstructionSelector::VisitWord64Shr(Node* node) {
328   VisitRRO(this, kArm64Shr, node, kShift64Imm);
329 }
330 
331 
VisitWord32Sar(Node * node)332 void InstructionSelector::VisitWord32Sar(Node* node) {
333   VisitRRO(this, kArm64Sar32, node, kShift32Imm);
334 }
335 
336 
VisitWord64Sar(Node * node)337 void InstructionSelector::VisitWord64Sar(Node* node) {
338   VisitRRO(this, kArm64Sar, node, kShift64Imm);
339 }
340 
341 
VisitWord32Ror(Node * node)342 void InstructionSelector::VisitWord32Ror(Node* node) {
343   VisitRRO(this, kArm64Ror32, node, kShift32Imm);
344 }
345 
346 
VisitWord64Ror(Node * node)347 void InstructionSelector::VisitWord64Ror(Node* node) {
348   VisitRRO(this, kArm64Ror, node, kShift64Imm);
349 }
350 
351 
VisitInt32Add(Node * node)352 void InstructionSelector::VisitInt32Add(Node* node) {
353   VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32, kArithmeticImm);
354 }
355 
356 
VisitInt64Add(Node * node)357 void InstructionSelector::VisitInt64Add(Node* node) {
358   VisitBinop<Int64BinopMatcher>(this, node, kArm64Add, kArithmeticImm);
359 }
360 
361 
VisitInt32Sub(Node * node)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 
VisitInt64Sub(Node * node)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 
VisitInt32Mul(Node * node)385 void InstructionSelector::VisitInt32Mul(Node* node) {
386   VisitRRR(this, kArm64Mul32, node);
387 }
388 
389 
VisitInt64Mul(Node * node)390 void InstructionSelector::VisitInt64Mul(Node* node) {
391   VisitRRR(this, kArm64Mul, node);
392 }
393 
394 
VisitInt32Div(Node * node)395 void InstructionSelector::VisitInt32Div(Node* node) {
396   VisitRRR(this, kArm64Idiv32, node);
397 }
398 
399 
VisitInt64Div(Node * node)400 void InstructionSelector::VisitInt64Div(Node* node) {
401   VisitRRR(this, kArm64Idiv, node);
402 }
403 
404 
VisitInt32UDiv(Node * node)405 void InstructionSelector::VisitInt32UDiv(Node* node) {
406   VisitRRR(this, kArm64Udiv32, node);
407 }
408 
409 
VisitInt64UDiv(Node * node)410 void InstructionSelector::VisitInt64UDiv(Node* node) {
411   VisitRRR(this, kArm64Udiv, node);
412 }
413 
414 
VisitInt32Mod(Node * node)415 void InstructionSelector::VisitInt32Mod(Node* node) {
416   VisitRRR(this, kArm64Imod32, node);
417 }
418 
419 
VisitInt64Mod(Node * node)420 void InstructionSelector::VisitInt64Mod(Node* node) {
421   VisitRRR(this, kArm64Imod, node);
422 }
423 
424 
VisitInt32UMod(Node * node)425 void InstructionSelector::VisitInt32UMod(Node* node) {
426   VisitRRR(this, kArm64Umod32, node);
427 }
428 
429 
VisitInt64UMod(Node * node)430 void InstructionSelector::VisitInt64UMod(Node* node) {
431   VisitRRR(this, kArm64Umod, node);
432 }
433 
434 
VisitChangeInt32ToFloat64(Node * node)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 
VisitChangeUint32ToFloat64(Node * node)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 
VisitChangeFloat64ToInt32(Node * node)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 
VisitChangeFloat64ToUint32(Node * node)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 
VisitChangeInt32ToInt64(Node * node)463 void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
464   Arm64OperandGenerator g(this);
465   Emit(kArm64Sxtw, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
466 }
467 
468 
VisitChangeUint32ToUint64(Node * node)469 void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
470   Arm64OperandGenerator g(this);
471   Emit(kArm64Mov32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
472 }
473 
474 
VisitTruncateInt64ToInt32(Node * node)475 void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
476   Arm64OperandGenerator g(this);
477   Emit(kArm64Mov32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
478 }
479 
480 
VisitFloat64Add(Node * node)481 void InstructionSelector::VisitFloat64Add(Node* node) {
482   VisitRRRFloat64(this, kArm64Float64Add, node);
483 }
484 
485 
VisitFloat64Sub(Node * node)486 void InstructionSelector::VisitFloat64Sub(Node* node) {
487   VisitRRRFloat64(this, kArm64Float64Sub, node);
488 }
489 
490 
VisitFloat64Mul(Node * node)491 void InstructionSelector::VisitFloat64Mul(Node* node) {
492   VisitRRRFloat64(this, kArm64Float64Mul, node);
493 }
494 
495 
VisitFloat64Div(Node * node)496 void InstructionSelector::VisitFloat64Div(Node* node) {
497   VisitRRRFloat64(this, kArm64Float64Div, node);
498 }
499 
500 
VisitFloat64Mod(Node * node)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 
VisitFloat64Sqrt(Node * node)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 
VisitInt32AddWithOverflow(Node * node,FlagsContinuation * cont)516 void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
517                                                     FlagsContinuation* cont) {
518   VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32, kArithmeticImm, cont);
519 }
520 
521 
VisitInt32SubWithOverflow(Node * node,FlagsContinuation * cont)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.
VisitCompare(InstructionSelector * selector,InstructionCode opcode,InstructionOperand * left,InstructionOperand * right,FlagsContinuation * cont)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.
VisitWordCompare(InstructionSelector * selector,Node * node,InstructionCode opcode,FlagsContinuation * cont,bool commutative)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 
VisitWord32Test(Node * node,FlagsContinuation * cont)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 
VisitWord64Test(Node * node,FlagsContinuation * cont)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 
VisitWord32Compare(Node * node,FlagsContinuation * cont)598 void InstructionSelector::VisitWord32Compare(Node* node,
599                                              FlagsContinuation* cont) {
600   VisitWordCompare(this, node, kArm64Cmp32, cont, false);
601 }
602 
603 
VisitWord64Compare(Node * node,FlagsContinuation * cont)604 void InstructionSelector::VisitWord64Compare(Node* node,
605                                              FlagsContinuation* cont) {
606   VisitWordCompare(this, node, kArm64Cmp, cont, false);
607 }
608 
609 
VisitFloat64Compare(Node * node,FlagsContinuation * cont)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 
VisitCall(Node * call,BasicBlock * continuation,BasicBlock * deoptimization)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
698