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